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:
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.