Zergatik Go Design txarra da programatzaile adimendunentzat

Azken hilabeteetan Go inplementazioetarako erabili dut. Kontzeptu froga (gutxi gorabehera.: ideia baten funtzionaltasuna probatzeko kodea) bere denbora librean, neurri batean programazio-lengoaia bera aztertzeko. Programak beraiek oso sinpleak dira eta ez dira artikulu honen helburua, baina Go erabiltzeak berak hitz batzuk merezi ditu horri buruz. Joan izango dela agintzen du (gutxi gorabehera.: 2015ean idatzitako artikulua) kode eskalagarri seriorako hizkuntza ezaguna. Googlek sortu zuen hizkuntza, non aktiboki erabiltzen den. Azken finean, zintzotasunez uste dut Go hizkuntzaren diseinua programatzaile adimendunentzat txarra dela.

Programatzaile ahulentzat diseinatuta?

Go oso erraza da ikasteko, hain erraza ezen aurkezpenak arratsalde batean hartu ninduen, eta horren ondoren jada modu produktiboan kodetu ahal izan nuen. Go ikasteko erabili nuen liburua du izena Programazioaren Sarrera Go-n (itzulpen), sarean eskuragarri dago. Liburua, Go iturburu kodea bera bezala, irakurterraza da, kode-adibide onak ditu eta 150 orrialde inguru ditu, eserleku batean irakur daitezkeenak. Soiltasun hori freskagarria da hasieran, batez ere teknologia konplikatuz betetako programazio munduan. Baina azkenean, goiz edo beranduago hausnarketa sortzen da: Β«Benetan hala al da?Β».

Google-k dio Go-ren sinpletasuna bere salmenta puntua dela eta hizkuntza talde handietan produktibitate handiena lortzeko diseinatuta dagoela, baina zalantzan jartzen dut. Badaude falta diren edo gehiegi zehaztutako ezaugarriak. Eta hori garatzaileenganako konfiantza faltagatik, ezer ondo egiteko gai ez direlakoan. Soiltasun-nahi hori hizkuntzaren diseinatzaileen erabaki kontzientea izan zen, eta zergatik behar zen ondo ulertzeko, garatzaileen motibazioa eta Go-n lortzen saiatzen ari zirena ulertu behar dugu.

Orduan, zergatik egin zen hain sinplea? Hona hemen aipamen pare bat Rob Pike (gutxi gorabehera.: Go hizkuntzaren sortzaileetako bat):

Hemen gakoa gure programatzaileek (gutxi gorabehera.: Googleriak) ez dira ikertzaileak. Oro har, nahiko gazteak dira, ikasi ondoren etortzen zaizkigu, agian Java, edo C/C++ edo Python ikasi zuten. Ezin dute hizkuntza handirik ulertu, baina, aldi berean, software ona sortzea nahi dugu. Horregatik, haien hizkuntza ulertzeko eta ikasteko erraza izan behar da.
 
Ezaguna izan behar du, gutxi gorabehera C-ren antzera. Googlen lan egiten duten programatzaileek goiz hasten dute karrera eta gehienbat prozedurazko lengoaiak ezagutzen dituzte, bereziki C familia. Programazio-lengoaia berri batean produktibitate azkarra eskakizunak esan nahi du hizkuntzak ez duela erradikala izan behar.

Zer? Beraz, Rob Pike funtsean esaten ari da Google-ko garatzaileak ez direla hain onak, horregatik sortu zuten idiota hizkuntza bat (gutxi gorabehera.: mututu) zerbait egiteko gai izan daitezen. Nolako begirada harroputz zure lankideei? Beti uste izan dut Google-ren garatzaileak eskuz aukeratzen direla Lurreko distiratsu eta onenen artean. Ziur zailagoa den zerbait kudeatu ahal izango dute?

Gehiegizko sinpletasuneko artefaktuak

Sinplea izatea helburu duina da edozein diseinutan, eta zerbait sinplea egiten saiatzea zaila da. Hala ere, arazo konplexuak ebazten (edo adierazten) saiatzean, batzuetan, tresna konplexu bat behar da. Konplexutasuna eta korapilatsua ez dira programazio-lengoaia baten ezaugarririk onenak, baina badago erdibide bat zeinetan hizkuntzak abstrakzio dotoreak sor ditzakeenak, ulertzeko eta erabiltzeko errazak.

Ez oso adierazgarria

Soiltasunaren aldeko apustua dela eta, beste hizkuntza batzuetan naturaltzat hartzen diren eraikuntzak falta zaizkio Go-k. Hasieran ideia ona dirudi, baina praktikan kode zehatza sortzen du. Horren arrazoia begi-bistakoa izan behar da - garatzaileek erraza izan behar dute besteen kodea irakurtzea, baina, egia esan, sinplifikazio hauek irakurgarritasuna kaltetzen dute. Go-n ez dago laburdurarik: asko ala ezer ez.

Adibidez, stdin edo komando-lerroko argumentuetatik fitxategi bat irakurtzen duen kontsola-erabilgarritasun batek itxura hau izango luke:

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)
}

Kode hau ere ahalik eta orokorrena izaten saiatzen den arren, Go-ren derrigorrezko hitzak oztopatzen du, eta, ondorioz, arazo sinple bat konpontzeak kode kopuru handia sortzen du.

Hona hemen, adibidez, arazo beraren irtenbidea 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);
    }
}

Eta nor da orain irakurgarriagoa? Nire botoa D-ri emango diot. Bere kodea askoz irakurgarriagoa da, ekintzak argiago deskribatzen dituelako. D askoz kontzeptu konplexuagoak erabiltzen ditu (gutxi gorabehera.: ordezko funtzio-deia ΠΈ txantiloiak) Go adibidean baino, baina ez dago ezer konplikaturik horiek ulertzeak.

Kopiaren infernua

Go hobetzeko iradokizun ezagun bat orokortasuna da. Horrek, gutxienez, alferrikako kodea kopiatzea saihesten lagunduko du datu mota guztiak onartzen dituen. Esate baterako, zenbaki osoen zerrenda batutzeko funtzio bat inplementatu daiteke osoko mota bakoitzerako bere oinarrizko funtzioa kopiatu-itsatsiz beste modu batean; ez dago beste modurik:

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))
}

Eta adibide honek ez du funtzionatzen sinatutako motetarako ere. Ikuspegi honek guztiz urratzen du zeure burua ez errepikatzearen printzipioa (DRY), printzipio ospetsu eta nabarienetako bat, akats askoren iturria zein den alde batera utzita. Zergatik egiten du Gok hau? Hau hizkuntzaren alderdi izugarria da.

Adibide bera D-n:

import std.stdio;
import std.algorithm;

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

Sinplea, dotorea eta zuzena. Hemen erabiltzen den funtzioa da reduce txantiloi mota eta predikaturako. Bai, hau berriro Go bertsioa baino konplikatuagoa da, baina ez da hain zaila programatzaile adimendunentzat ulertzea. Zein adibide da errazago mantentzen eta erraz irakurtzen?

Mota sinpleko sistemaren saihesbidea

Imajinatzen dut Go programatzaileak hau irakurtzen ari direla aparra ahoan eta garrasika egingo dutela: "Gaizki egiten ari zara!" Beno, badago funtzio eta mota generiko bat egiteko beste modu bat, baina mota sistema erabat apurtzen du!

Begiratu arazoari aurre egiteko hizkuntza konponketa ergel baten adibide honi:

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)
}

Ezarpen hau Reduce artikulutik maileguan hartu zen Generiko idiomatikoak Go-n (gutxi gorabehera.: Ezin izan dut itzulpena aurkitu, pozik egongo naiz honekin laguntzen baduzu). Tira, idiomatikoa bada, gorroto nuke adibide ez-idiomatiko bat ikustea. Erabilera interface{} - fartsa bat, eta hizkuntzan idazketa saihesteko baino ez da behar. Hau interfaze huts bat da eta mota guztiek inplementatzen dute, guztion askatasun osoa ahalbidetuz. Programazio estilo hau izugarri itsusia da, eta ez da hori guztia. Horrelako balentria akrobatikoek exekuzio-denboraren hausnarketa erabiltzea eskatzen dute. Rob Pike-ri ere ez zaizkio gustatzen hau abusatzen duten pertsonak, bere txostenetako batean aipatu zuen bezala.

Kontuz erabili beharreko tresna indartsua da hau. Beharrezkoa ez bada behintzat, saihestu egin behar da.

D txantiloiak hartuko nituzke zentzugabekeria honen ordez. Nola esan dezake inork hori interface{} irakurgarriagoa edo seguru idatzi?

Menpekotasunaren Kudeaketako kalteak

Go-k ostalaritza-hornitzaile ezagunen gainean eraikitako menpekotasun-sistema du VCS. Go-rekin batera datozen tresnek zerbitzu hauen berri ezagutzen dute eta haien kodea deskargatu, eraiki eta instalatu dezakete kolpe bakarrean. Hau bikaina den arren, bertsioa egitean akats handi bat dago! Bai, egia da iturburu kodea github edo bitbucket bezalako zerbitzuetatik lor dezakezula Go tresnak erabiliz, baina ezin duzu bertsioa zehaztu. Eta berriro sinpletasuna erabilgarritasunaren kontura. Ez naiz gai halako erabaki baten logika ulertzeko.

Arazo honen konponbideari buruzko galderak egin ondoren, Go garapen taldea sortu zen foroaren haria, zeinak gai hau nola konponduko zuten azaldu zuen. Haien gomendioa biltegi osoa egun batean zure proiektuan kopiatzea eta "dagoen bezala" uztea izan zen. Zer demontre ari dira pentsatzen? Bertsioak kontrolatzeko sistema harrigarriak ditugu etiketatze eta bertsio-laguntza bikainarekin, Go-ren sortzaileek baztertu eta iturburu-kodea kopiatu besterik ez dute egiten.

Xi-ren kultur ekipajea

Nire ustez, Go bizitza osoan C erabili zutenek eta zerbait berria probatu nahi ez zutenek garatu zuten. Hizkuntza C gisa deskriba daiteke gurpil gehigarriekin (orig.: entrenamendu gurpilak). Bertan ez dago ideia berririk, paralelismoaren aldeko laguntza izan ezik (hori, bide batez, zoragarria da) eta pena da hori. Paralelismo bikaina duzu ozta-ozta erabil daitekeen hizkuntza herren batean.

Beste arazo bat da Go prozedurazko hizkuntza bat dela (C-ren izu isila bezalakoa). Kodea idazten duzu arkaiko eta zaharkituta sentitzen den prozedura-estilo batean. Badakit objektuei zuzendutako programazioa ez dela zilarrezko bala, baina bikaina izango litzateke xehetasunak motetan abstraitzea eta kapsulatzea eskaintzea.

Sinpletasuna zure onurarako

Go sinplea izateko diseinatu zen eta helburu horretan lortzen du. Programatzaile ahulentzat idatzi zen, hizkuntza zahar bat txantiloi gisa erabiliz. Gauza errazak egiteko tresna errazekin dator. Irakurtzeko erraza eta erabiltzeko erraza da.

Oso zehatza, ikusgarria eta txarra da programatzaile adimendunentzat.

Eskerrik asko mersinvald edizioetarako

Iturria: www.habr.com

Gehitu iruzkin berria