Perchè Go Design hè male per i programatori intelligenti

In l'ultimi mesi aghju utilizatu Go per implementazioni. Prova di cuncettu (ca.: codice per pruvà a funziunalità di una idea) in u so tempu liberu, in parte per studià a lingua di prugrammazione stessu. I prugrammi stessi sò assai sèmplice è ùn sò micca u scopu di stu articulu, ma l'esperienza di usu Go stessu meriteghja uni pochi di parolle. Vai prumetti di esse (ca.: articulu scrittu in 2015) una lingua populari per codice scalable seriu. A lingua hè stata creata da Google, induve hè attivamente utilizata. In fondu, pensu onestamente chì u disignu di a lingua Go hè male per i programatori intelligenti.

Cuncepitu per i programatori debuli?

Vai hè assai faciule d'amparà, cusì faciule chì l'intruduzioni m'hà pigliatu una sera, dopu chì puderia digià codificà in modu produtivu. U libru ch'e aghju avutu per amparà Go hè chjamatu Una introduzione à a prugrammazione in Go (traduzzione), hè dispunibule in linea. U libru, cum'è u codice fonte Go stessu, hè faciule di leghje, hà boni esempi di codice, è cuntene circa 150 pagine chì ponu esse leghje in una volta. Sta simplicità hè rinfrescante in prima, soprattuttu in un mondu di prugrammazione pienu di tecnulugia troppu cumplicata. Ma à a fine, prima o poi u pensamentu nasce: "Hè veramente cusì?"

Google dichjara chì a simplicità di Go hè u so puntu di vendita è a lingua hè pensata per a produtividade massima in grandi squadre, ma dubitu. Ci sò funzioni chì sò mancanti o troppu detallati. È tuttu per una mancanza di fiducia in i sviluppatori, cù l'assunzione chì ùn sò micca capaci di fà nunda bè. Stu desideriu di simplicità era una decisione cuscente da i diseggiani di a lingua, è per capiscenu cumplettamente perchè era necessariu, duvemu capisce a motivazione di i sviluppatori è ciò chì anu pruvatu à ottene in Go.

Allora perchè era fattu cusì simplice? Eccu un paru di citazioni Rob Pike (ca.: unu di i co-creatori di a lingua Go):

U puntu chjave quì hè chì i nostri programatori (ca.: Googlers) ùn sò micca circadori. Sò, in regula, abbastanza ghjovani, venenu à noi dopu avè studiatu, forsi anu studiatu Java, o C/C++, o Python. Ùn ponu micca capisce una grande lingua, ma à u stessu tempu vulemu chì creanu un bonu software. Hè per quessa chì a so lingua deve esse faciule per elli à capisce è amparà.
 
Deve esse familiarizatu, à pocu pressu simile à C. I programatori chì travaglianu in Google cumincianu a so carriera prima è sò soprattuttu familiarizati cù e lingue procedurali, in particulare a famiglia C. U requisitu per a produtividade rapida in una nova lingua di prugrammazione significa chì a lingua ùn deve esse troppu radicali.

Chì ? Allora Rob Pike dice in fondu chì i sviluppatori di Google ùn sò micca cusì boni, hè per quessa chì anu creatu una lingua per l'idioti (ca.: dumbed down) per ch'elli sò capaci di fà qualcosa. Chì tipu di sguardu arrogante à i vostri culleghi? Aghju sempre cridutu chì i sviluppatori di Google sò selezziunati da i più brillanti è megliu in a Terra. Di sicuru, ponu trattà qualcosa di più difficiule?

Artifatti di simplicità eccessiva

Esse simplice hè un scopu degnu in ogni disignu, è pruvà à fà qualcosa simplice hè difficiule. In ogni casu, quandu pruvate di risolve (o ancu spressione) prublemi cumplessi, qualchì volta hè necessariu un strumentu cumplessu. A cumplessità è l'intricatu ùn sò micca i migliori tratti di una lingua di prugrammazione, ma ci hè un mediu felice in quale una lingua pò creà astrazioni eleganti chì sò faciuli di capiscenu è di utilizà.

Ùn hè micca assai espressivu

Per via di u so impegnu à a simplicità, Go manca di custruzzioni chì sò percive cum'è naturali in altre lingue. Questu pò sembrà una bona idea in prima, ma in a pratica resulta in codice verbose. U mutivu di questu deve esse ovvi - deve esse faciule per i sviluppatori di leghje u codice di l'altri, ma in fattu queste simplificazioni solu dannu a leghjibilità. Ùn ci sò micca abbreviazioni in Go: o assai o nunda.

Per esempiu, una utilità di cunsola chì leghje stdin o un schedariu da l'argumenti di a linea di cumanda parerebbe cusì:

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

Ancu s'è stu codice prova ancu di esse u più generale pussibule, a verbosità furzata di Go si mette in u modu, è in u risultatu, risolviri un prublema simplice risultati in una grande quantità di codice.

Quì, per esempiu, hè una suluzione à u listessu prublema in 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);
    }
}

E quale hè più leggibile avà? Daraghju u mo votu à D. U so codice hè assai più leggibile perchè descrive l'azzioni più chjaramente. D usa cuncetti assai più cumplessi (ca.: chiama di funzione alternativa и modelli) chè in l'esempiu Go, ma ùn ci hè veramente nunda di complicatu per capiscenu.

L'infernu di copia

Un suggerimentu populari per migliurà Go hè a generalità. Stu vi almenu aiutà à evitari cupià innecessarii di codice à sustene tutti i tipi di dati. Per esempiu, una funzione per summing una lista di integer pò esse implementata in nisun altru modu ch'è da copia-incolla a so funzione basica per ogni tipu integer ùn ci hè micca altru modu:

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

È questu esempiu ùn funziona ancu per i tipi firmati. Stu approcciu viola cumplettamente u principiu di ùn ripetiri sè stessu (SECCHE), unu di i principii più famosi è evidenti, ignorendu quale hè a fonte di parechji errori. Perchè Go face questu? Questu hè un aspettu terribili di a lingua.

U stessu esempiu nantu à D:

import std.stdio;
import std.algorithm;

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

Semplice, elegante è drittu à u puntu. A funzione utilizata quì hè reduce per u tipu di mudellu è u predicatu. Iè, questu hè di novu più cumplicatu cà a versione Go, ma micca cusì difficiule per i programatori intelligenti per capiscenu. Qualessu esempiu hè più faciule da mantene è più faciule da leghje?

Bypass di sistema di tipu simplice

Immagino chì i programatori di Go chì leghjenu questu seranu spumante à a bocca è gridendu: "Avete sbagliatu!" Ebbè, ci hè un altru modu per fà una funzione generica è tipi, ma rompe cumplettamente u sistema di tipu!

Fighjate à questu esempiu di una correzione di lingua stupida per trattà u prublema:

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

Questa implementazione Reduce hè stata presa in prestu da l'articulu Generics idiomatici in Go (ca.: Ùn aghju pussutu truvà a traduzzione, saraghju cuntentu s'è vo aiutate cù questu). Ebbè, s'ellu hè idiomaticu, mi piacerebbe vede un esempiu non-idiomaticu. Usu interface{} - una farsa, è in a lingua hè necessariu solu per sguassate a scrittura. Questa hè una interfaccia viota è tutti i tipi l'implementanu, chì permettenu una libertà cumpleta per tutti. Stu stilu di prugrammazione hè bruttu cum'è l'infernu, è ùn hè micca tuttu. I fatti acrobatici cum'è questu necessitanu l'usu di a riflessione runtime. Ancu Rob Pike ùn piace micca l'individui chì abusanu di questu, cum'è hà dettu in unu di i so rapporti.

Questu hè un strumentu putente chì deve esse usatu cun prudenza. Hè da esse evitata, salvu micca strettamente necessariu.

Piglieraghju mudelli D invece di sta sciocchezza. Cumu qualcunu pò dì chì interface{} più leggibile o ancu tipu sicuru?

I guai di a gestione di a dipendenza

Go hà un sistema di dipendenza integratu custruitu annantu à i fornitori di hosting populari VCS. L'arnesi chì venenu cù Go sanu di sti servizii è ponu scaricà, custruisce è stallà codice da elli in un colpu. Mentre questu hè grande, ci hè un difettu maiò cù a versione! Iè, hè veru chì pudete uttene u codice fonte da servizii cum'è github o bitbucket cù l'utili Go, ma ùn pudete micca specificà a versione. È dinò a simplicità à a spesa di l'utilità. Ùn sò micca capaci di capisce a logica di una tale decisione.

Dopu à dumandà dumande nantu à una suluzione à stu prublema, u gruppu di sviluppu Go creatu filu di u forum, chì spiegà cumu si andavanu à attruvà stu prublema. A so ricunniscenza era di cupià solu u repositoriu tutale in u vostru prughjettu un ghjornu è lascià "cum'è". Chì diavolo pensanu ? Avemu un sistema di cuntrollu di versione maravigghiusu cù un grande tagging è supportu di versione chì i creatori di Go ignoranu è solu copià u codice fonte.

Bagagli culturali da Xi

In u mo parè, Go hè statu sviluppatu da e persone chì avianu usatu C tutta a so vita è da quelli chì ùn vulianu micca pruvà qualcosa di novu. A lingua pò esse discritta cum'è C cù roti extra (orig.: roti di furmazione). Ùn ci sò micca idee novi in ​​questu, salvu u sustegnu à u parallelismu (chì, per via, hè maravigliu) è questu hè una vergogna. Avete un parallelismu eccellente in una lingua à pocu pressu è zoppa.

Un altru prublemu stridulu hè chì Go hè una lingua procedurale (cum'è l'orrore silenziosu di C). Finite à scrive codice in un stile procedurale chì si senti arcaicu è anticu. Sò chì a prugrammazione orientata à l'ughjettu ùn hè micca una bala d'argentu, ma saria bella per pudè astrattu i dettagli in tipi è furnisce incapsulazione.

A simplicità per u vostru propiu benefiziu

Go hè statu cuncepitu per esse simplice è riesce à quellu scopu. Hè statu scrittu per i programatori debuli, utilizendu una lingua antica cum'è mudellu. Veni cumpletu cù arnesi simplici per fà e cose simplici. Hè faciule da leghje è faciule d'utilizà.

Hè estremamente verbose, pocu impressiunanti, è male per i programatori intelligenti.

Спасибо mersinvald per e modifiche

Source: www.habr.com

Add a comment