Af hverju Go Design er slæmt fyrir snjalla forritara

Undanfarna mánuði hef ég notað Go fyrir útfærslur. Sönnun af hugtak (ca.: kóða til að prófa virkni hugmyndar) í frítíma sínum, að hluta til að læra forritunarmálið sjálft. Forritin sjálf eru mjög einföld og eru ekki tilgangur þessarar greinar, en reynslan af því að nota Go sjálf á skilið nokkur orð um hana. Go lofar að vera (ca.: grein skrifuð árið 2015) vinsælt tungumál fyrir alvarlegan stigstærðan kóða. Tungumálið var búið til af Google, þar sem það er virkt notað. Niðurstaðan, ég held satt að segja að hönnun Go tungumálsins sé slæm fyrir snjalla forritara.

Hannað fyrir veikburða forritara?

Go er mjög auðvelt að læra, svo auðvelt að kynningin tók mig eitt kvöld, eftir það gat ég þegar kóðað afkastamikill. Bókin sem ég notaði til að læra Go heitir Kynning á forritun í Go (þýðing), það er fáanlegt á netinu. Bókin, eins og Go frumkóðann sjálfur, er auðlesin, hefur góð kóðadæmi og inniheldur um 150 síður sem hægt er að lesa í einu. Þessi einfaldleiki er hressandi í fyrstu, sérstaklega í forritunarheimi sem er fullur af of flókinni tækni. En á endanum vaknar fyrr eða síðar hugsunin: "Er þetta virkilega svona?"

Google heldur því fram að einfaldleiki Go sé sölustaður þess og tungumálið er hannað fyrir hámarks framleiðni í stórum teymum, en ég efast um það. Það eru eiginleikar sem annað hvort vantar eða of ítarlegir. Og allt vegna skorts á trausti til þróunaraðila, með þeirri forsendu að þeir geti ekki gert neitt rétt. Þessi þrá eftir einfaldleika var meðvituð ákvörðun hönnuða tungumálsins og til að skilja til hlítar hvers vegna þess var þörf verðum við að skilja hvata þróunaraðilanna og hvað þeir voru að reyna að ná í Go.

Svo hvers vegna var þetta gert svona einfalt? Hér eru nokkrar tilvitnanir Rob Pike (ca.: einn af meðhöfundum Go tungumálsins):

Lykilatriðið hér er að forritarar okkar (ca.: Googlers) eru ekki vísindamenn. Þeir eru að jafnaði frekar ungir, koma til okkar eftir nám, kannski lærðu þeir Java, eða C/C++ eða Python. Þeir geta ekki skilið frábært tungumál en á sama tíma viljum við að þeir búi til góðan hugbúnað. Þess vegna ætti tungumál þeirra að vera auðvelt fyrir þá að skilja og læra.
 
Hann ætti að vera kunnugur, í grófum dráttum svipað og C. Forritarar sem starfa hjá Google hefja feril sinn snemma og þekkja að mestu málsmeðferðarmál, sérstaklega C fjölskylduna. Krafan um skjóta framleiðni í nýju forritunarmáli þýðir að tungumálið ætti ekki að vera of róttækt.

Hvað? Svo Rob Pike er í rauninni að segja að forritararnir hjá Google séu ekki svo góðir, þess vegna bjuggu þeir til tungumál fyrir fávita (ca.: dumbed down) svo að þeir séu færir um að gera eitthvað. Hvers konar hrokafullt útlit á eigin samstarfsmenn? Ég hef alltaf trúað því að forritarar Google séu handvaldir úr þeim björtustu og bestu á jörðinni. Þeir ráða örugglega við eitthvað erfiðara?

Artifacts of óhóflega einfaldleika

Að vera einfaldur er verðugt markmið í hvaða hönnun sem er og að reyna að gera eitthvað einfalt er erfitt. Hins vegar, þegar reynt er að leysa (eða jafnvel tjá) flókin vandamál, þarf stundum flókið tæki. Flækjustig og flækjustig eru ekki bestu eiginleikar forritunarmáls, en það er meðalvegur þar sem tungumálið getur búið til glæsilegar útdrættir sem auðvelt er að skilja og nota.

Ekki mjög svipmikill

Vegna skuldbindingar sinnar við einfaldleika, skortir Go smíðar sem eru álitnar eðlilegar á öðrum tungumálum. Þetta kann að virðast góð hugmynd í fyrstu, en í reynd leiðir það til margorðs kóða. Ástæðan fyrir þessu ætti að vera augljós - það þarf að vera auðvelt fyrir forritara að lesa kóða annarra, en í raun skaðar þessar einföldun aðeins læsileikann. Það eru engar skammstafanir í Go: annað hvort mikið eða ekkert.

Til dæmis, stjórnborðsforrit sem les stdin eða skrá úr skipanalínurökum myndi líta svona út:

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
)

func main() {

    flag.Parse()
    flags := flag.Args()

    var text string
    var scanner *bufio.Scanner
    var err error

    if len(flags) > 0 {

        file, err := os.Open(flags[0])

        if err != nil {
            log.Fatal(err)
        }

        scanner = bufio.NewScanner(file)

    } else {
        scanner = bufio.NewScanner(os.Stdin)
    }

    for scanner.Scan() {
        text += scanner.Text()
    }

    err = scanner.Err()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(text)
}

Þó að þessi kóði reyni líka að vera eins almennur og hægt er, þá kemur þvinguð orðræðni Go í veg fyrir, og þar af leiðandi leiðir það til mikils kóða að leysa einfalt vandamál.

Hér er til dæmis lausn á sama vandamáli í D:

import std.stdio, std.array, std.conv;

void main(string[] args)
{
    try
    {
        auto source = args.length > 1 ? File(args[1], "r") : stdin;
        auto text   = source.byLine.join.to!(string);

        writeln(text);
    }
    catch (Exception ex)
    {
        writeln(ex.msg);
    }
}

Og hver er læsilegri núna? Ég mun gefa D atkvæði mitt. Kóðinn hans er miklu læsilegri vegna þess að hann lýsir aðgerðunum betur. D notar mun flóknari hugtök (ca.: val aðgerðakalla и sniðmát) en í Go dæminu, en það er í raun ekkert flókið við að skilja þau.

Helvítis afritun

Vinsæl tillaga til að bæta Go er almenning. Þetta mun að minnsta kosti hjálpa til við að forðast óþarfa afritun kóða til að styðja allar gagnagerðir. Til dæmis, fall til að leggja saman lista yfir heiltölur er ekki hægt að útfæra á annan hátt en með því að afrita og líma grunnfallið fyrir hverja heiltölutegund; það er engin önnur leið:

package main

import "fmt"

func int64Sum(list []int64) (uint64) {
    var result int64 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int32Sum(list []int32) (uint64) {
    var result int32 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int16Sum(list []int16) (uint64) {
    var result int16 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int8Sum(list []int8) (uint64) {
    var result int8 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func main() {

    list8  := []int8 {1, 2, 3, 4, 5}
    list16 := []int16{1, 2, 3, 4, 5}
    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int8Sum(list8))
    fmt.Println(int16Sum(list16))
    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

Og þetta dæmi virkar ekki einu sinni fyrir undirritaðar tegundir. Þessi nálgun brýtur algjörlega í bága við meginregluna um að endurtaka sig ekki (Þurrkað), ein frægasta og augljósasta meginreglan, sem hunsar hver er uppspretta margra villna. Af hverju gerir Go þetta? Þetta er hræðilegur þáttur tungumálsins.

Sama dæmi á D:

import std.stdio;
import std.algorithm;

void main(string[] args)
{
    [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}

Einfalt, glæsilegt og beint að efninu. Aðgerðin sem notuð er hér er reduce fyrir sniðmátsgerð og forsögn. Já, þetta er aftur flóknara en Go útgáfan, en ekki svo erfitt fyrir snjalla forritara að skilja. Hvaða dæmi er auðveldara að viðhalda og auðveldara að lesa?

Einföld gerð kerfishjáveitu

Ég ímynda mér að Go forritarar sem lesa þetta verði froðufellandi og öskra: "Þú ert að gera það rangt!" Jæja, það er önnur leið til að búa til almenna virkni og tegundir, en hún brýtur algjörlega tegundakerfið!

Skoðaðu þetta dæmi um heimskulega tungumálaleiðréttingu til að vinna í kringum vandamálið:

package main

import "fmt"
import "reflect"

func Reduce(in interface{}, memo interface{}, fn func(interface{}, interface{}) interface{}) interface{} {
    val := reflect.ValueOf(in)

    for i := 0; i < val.Len(); i++ {
        memo = fn(val.Index(i).Interface(), memo)
    }

    return memo
}

func main() {

    list := []int{1, 2, 3, 4, 5}

    result := Reduce(list, 0, func(val interface{}, memo interface{}) interface{} {
        return memo.(int) + val.(int)
    })

    fmt.Println(result)
}

Þessi framkvæmd Reduce var fengið að láni úr greininni Idiomatic almennar lyf í Go (ca.: Ég fann ekki þýðinguna, ég mun vera ánægður ef þú hjálpar með þetta). Jæja, ef það er málsháttur, þá myndi ég hata að sjá dæmi sem ekki er orðrænt. Notkun interface{} - farsi, og á tungumálinu þarf hann aðeins til að komast framhjá vélritun. Þetta er tómt viðmót og allar gerðir innleiða það, sem gerir öllum kleift að hafa fullkomið frelsi. Þessi forritunarstíll er hræðilega ljótur og það er ekki allt. Loftfimleikar eins og þessir krefjast notkunar endurskoðunartíma. Jafnvel Rob Pike líkar ekki við einstaklinga sem misnota þetta eins og hann nefndi í einni af skýrslum sínum.

Þetta er öflugt tæki sem ætti að nota með varúð. Það ætti að forðast nema brýna nauðsyn beri til.

Ég myndi taka D sniðmát í staðinn fyrir þessa vitleysu. Hvernig getur nokkur maður sagt það interface{} læsilegri eða jafnvel tegund öruggur?

Vandræði stjórnunar á ósjálfstæði

Go er með innbyggt ósjálfstæðiskerfi byggt ofan á vinsælum hýsingaraðilum VCS. Verkfærin sem fylgja Go vita um þessa þjónustu og geta hlaðið niður, smíðað og sett upp kóða frá þeim í einu vetfangi. Þó að þetta sé frábært, þá er mikill galli við útgáfu! Já, það er satt að þú getur fengið frumkóðann frá þjónustu eins og github eða bitbucket með Go verkfærum, en þú getur ekki tilgreint útgáfuna. Og aftur einfaldleiki á kostnað notagildis. Ég get ekki skilið rökfræðina í slíkri ákvörðun.

Eftir að hafa spurt spurninga um lausn á þessu vandamáli stofnaði þróunarteymið Go spjallþráður, sem rakti hvernig þeir ætluðu að koma þessu máli að. Tilmæli þeirra voru að afrita einfaldlega alla geymsluna inn í verkefnið þitt einn daginn og skilja það eftir „eins og það er“. Hvað í fjandanum eru þeir að hugsa? Við erum með ótrúleg útgáfustýringarkerfi með frábærum merkingum og útgáfustuðningi sem Go höfundarnir hunsa og afrita bara frumkóðann.

Menningarfarangur frá Xi

Að mínu mati var Go þróað af fólki sem hafði notað C allt sitt líf og af þeim sem vildu ekki prófa eitthvað nýtt. Hægt er að lýsa tungumálinu sem C með aukahjólum(upprunalega.: æfingahjól). Það eru engar nýjar hugmyndir í henni, nema stuðningur við hliðstæður (sem er að vísu dásamlegt) og þetta er synd. Þú ert með frábæra hliðstæðu í varla nothæfu, lötu máli.

Annað brakandi vandamál er að Go er málsmeðferðarmál (eins og þögull hryllingur C). Þú endar með því að skrifa kóða í málsmeðferðarstíl sem finnst fornaldarlegur og úreltur. Ég veit að hlutbundin forritun er ekki silfurkúla, en það væri frábært að geta tekið smáatriðin saman í gerðir og útvegað hjúpun.

Einfaldleiki í eigin þágu

Go var hannað til að vera einfalt og það tekst því markmiði. Það var skrifað fyrir veikburða forritara og notaði gamalt tungumál sem sniðmát. Það kemur heill með einföldum verkfærum til að gera einfalda hluti. Það er auðvelt að lesa og auðvelt í notkun.

Það er ákaflega orðrétt, lítt áhrifamikið og slæmt fyrir snjalla forritara.

Takk mersinvald fyrir breytingar

Heimild: www.habr.com

Bæta við athugasemd