Firwat Go Design ass schlecht fir Smart Programmer

An de leschte Méint hunn ech Go fir Implementatiounen benotzt. Beweis vum Konzept (ca.: Code fir d'Funktionalitéit vun enger Iddi ze testen) a senger Fräizäit, deelweis fir d'Programméiersprooch selwer ze studéieren. D'Programmer selwer si ganz einfach a sinn net den Zweck vun dësem Artikel, awer d'Erfahrung vu Go selwer verdéngt e puer Wierder doriwwer. Go versprécht ze sinn (ca.: Artikel geschriwwen am 2015) eng populär Sprooch fir seriöse skalierbare Code. D'Sprooch gouf vu Google erstallt, wou se aktiv benotzt gëtt. Bottom Line, ech mengen éierlech datt den Design vun der Go Sprooch schlecht ass fir intelligent Programméierer.

Entworf fir schwaach Programméierer?

Go ass ganz einfach ze léieren, sou einfach datt d'Aféierung mech en Owend gedauert huet, duerno konnt ech scho produktiv codéieren. D'Buch, dat ech benotzt gi fir ze léieren Go heescht Eng Aféierung fir Programméiere am Go (Iwwersetzung), ass et online verfügbar. D'Buch, wéi de Go Quellcode selwer, ass einfach ze liesen, huet gutt Code Beispiller, an enthält ongeféier 150 Säiten déi an engem Wee gelies kënne ginn. Dës Simplicitéit ass am Ufank erfrëschend, besonnesch an enger Programméierungswelt gefëllt mat iwwerkomplizéierter Technologie. Mä um Enn kënnt desto oder spéider de Gedanke: "Ass dat wierklech esou?"

Google behaapt dem Go seng Einfachheet ass säi Verkafspunkt an d'Sprooch ass fir maximal Produktivitéit a groussen Teams entworf, awer ech bezweifelen et. Et gi Features déi entweder fehlen oder zevill detailléiert sinn. An alles wéinst engem Mangel u Vertrauen an d'Entwéckler, mat der Virgab datt se näischt richteg maache kënnen. Dëse Wonsch fir Einfachheet war eng bewosst Entscheedung vun den Designer vun der Sprooch, a fir voll ze verstoen firwat et gebraucht gouf, musse mir d'Motivatioun vun den Entwéckler verstoen a wat se probéiert hunn am Go z'erreechen.

Also firwat gouf et sou einfach gemaach? Hei sinn e puer Zitater Rob Pike (ca.: ee vun de Co-Creatoren vun der Go Sprooch):

De Schlësselpunkt hei ass datt eis Programméierer (ca.: Googlers) si keng Fuerscher. Si sinn, an der Regel, zimlech jonk, kommen no engem Studium bei eis, vläicht hu se Java studéiert, oder C/C++, oder Python. Si kënne keng grouss Sprooch verstoen, awer gläichzäiteg wëlle mir datt se gutt Software kreéieren. Dofir soll hir Sprooch einfach sinn ze verstoen an ze léieren.
 
Hie sollt vertraut sinn, ongeféier ähnlech wéi C. Programméierer, déi bei Google schaffen, fänken hir Carrière fréi un a si meeschtens mat prozedurale Sprooche vertraut, besonnesch d'C Famill. D'Ufuerderung fir séier Produktivitéit an enger neier Programméierungssprooch bedeit datt d'Sprooch net ze radikal sollt sinn.

Waat? Also de Rob Pike seet am Fong datt d'Entwéckler bei Google net sou gutt sinn, dofir hunn se eng Sprooch fir Idioten erstallt (ca.: dumbed down) fir datt se fäeg sinn eppes ze maachen. Wéi eng arrogant Bléck op Är eege Kollegen? Ech hunn ëmmer gegleeft datt d'Entwéckler vu Google vun den hellsten a beschten op der Äerd handgewielt ginn. Si kënne sécher eppes méi schwéier handhaben?

Artefakte vun exzessive Einfachheet

Einfach ze sinn ass e wäertvollt Zil an all Design, a probéiert eppes einfach ze maachen ass schwéier. Wéi och ëmmer, wann Dir probéiert komplex Probleemer ze léisen (oder souguer auszedrécken), ass heiansdo e komplext Tool gebraucht. Komplexitéit an komplizéiert sinn net déi bescht Features vun enger Programméierungssprooch, awer et gëtt e Mëttelfeld an deem d'Sprooch elegant Abstraktioune ka kreéieren déi einfach ze verstoen an ze benotzen sinn.

Net ganz expressiv

Wéinst sengem Engagement fir Simplicitéit feelt Go Konstrukten déi als natierlech an anere Sproochen ugesi ginn. Dëst kann op d'éischt wéi eng gutt Iddi schéngen, awer an der Praxis resultéiert et zu verbose Code. De Grond dofir sollt evident sinn - et muss einfach sinn fir Entwéckler de Code vun anere Leit ze liesen, awer tatsächlech schueden dës Vereinfachungen nëmmen d'Liesbarkeet. Et gi keng Ofkierzungen am Go: entweder vill oder näischt.

Zum Beispill, e Konsol-Utility deen stdin liest oder eng Datei aus Kommandozeilargumenter géif esou ausgesinn:

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

Och wann dëse Code och probéiert sou allgemeng wéi méiglech ze sinn, gëtt dem Go seng forcéiert Verbositéit am Wee, an als Resultat gëtt d'Léisung vun engem einfache Problem zu enger grousser Quantitéit Code.

Hei ass zum Beispill eng Léisung fir dee selwechte Problem an 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);
    }
}

A wien ass elo méi liesbar? Ech ginn dem D meng Stëmm. Säi Code ass vill méi liesbar well hien d'Aktiounen méi kloer beschreift. D benotzt vill méi komplex Konzepter (ca.: alternativ Funktioun Opruff и Skeletter) wéi am Go Beispill, awer et ass wierklech näischt komplizéiert fir se ze verstoen.

Hell vun Kopie

E populäre Virschlag fir Go ze verbesseren ass Allgemengheet. Dëst wäert op d'mannst hëllefen, onnéideg Kopie vum Code ze vermeiden fir all Datentypen z'ënnerstëtzen. Zum Beispill, eng Funktioun fir eng Lëscht vun ganz Zuelen ze summéieren kann op keng aner Manéier ëmgesat ginn wéi andeems se seng Basisfunktioun fir all Ganzzueltyp kopéieren; et gëtt keng aner Manéier:

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

An dëst Beispill funktionnéiert net emol fir ënnerschriwwenen Typen. Dës Approche verletzt komplett de Prinzip fir Iech net ze widderhuelen (dréchnen), ee vun de bekanntste an offensichtleche Prinzipien, ignoréiert wat d'Quell vu ville Feeler ass. Firwat mécht Go dat? Dëst ass e schrecklechen Aspekt vun der Sprooch.

Selwecht Beispill op D:

import std.stdio;
import std.algorithm;

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

Einfach, elegant an direkt zum Punkt. D'Funktioun déi hei benotzt gëtt ass reduce fir Schablountyp a Prädikat. Jo, dëst ass erëm méi komplizéiert wéi d'Go Versioun, awer net sou schwéier fir Smart Programméierer ze verstoen. Wéi ee Beispill ass méi einfach ze erhalen a méi einfach ze liesen?

Einfach Typ System Bypass

Ech stellen mir vir, datt Go-Programméierer dëst liesen wäerten um Mond schaumen a jäizen: "Dir maacht et falsch!" Gutt, et gëtt en anere Wee fir eng generesch Funktioun an Typen ze maachen, awer et brécht den Typsystem komplett!

Kuckt Iech dëst Beispill vun enger domm Sproochfix fir de Problem ëmzegoen:

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

Dës Ëmsetzung Reduce gouf vum Artikel geléint Idiomatesch Generik am Go (ca.: Ech konnt d'Iwwersetzung net fannen, ech wäert frou sinn wann Dir mat dësem hëlleft). Gutt, wann et idiomatesch ass, géif ech haassen en net-idiomatescht Beispill ze gesinn. Benotzung interface{} - eng Farce, an der Sprooch ass et nëmmen néideg fir d'Typen z'iwwergoen. Dëst ass eng eidel Interface an all Zorte implementéieren se, wat fir jiddereen komplett Fräiheet erlaabt. Dëse Stil vun der programméiere ass schrecklech ellen, an dat ass net alles. Akrobatesch Feats wéi dës erfuerderen d'Benotzung vu Runtime Reflexioun. Och de Rob Pike huet net gär Leit, déi dat mëssbrauchen, wéi hien an engem vu senge Reportagen ernimmt huet.

Dëst ass e mächtegt Tool dat sollt mat Vorsicht benotzt ginn. Et soll vermeit ginn, ausser streng néideg.

Ech géif D Template huelen amplaz vun dësem Blödsinn. Wéi kann een dat soen interface{} méi liesbar oder souguer Typ sécher?

De Woes vun Ofhängegkeet Management

Go huet en agebaute Ofhängegkeetssystem uewen op populäre Hosting Ubidder gebaut VCS. D'Tools, déi mat Go kommen, wëssen iwwer dës Servicer a kënnen de Code vun hinnen an engem Schlag eroflueden, bauen an installéieren. Och wann dëst super ass, gëtt et e grousse Feeler mat der Versioun! Jo, et ass richteg datt Dir de Quellcode vu Servicer wéi Github oder Bitbucket mat Go Tools kritt, awer Dir kënnt d'Versioun net spezifizéieren. An erëm Simplicitéit op Käschte vun Nëtzlechkeet. Ech sinn net fäeg d'Logik vun esou enger Entscheedung ze verstoen.

Nodeems Dir Froen iwwer eng Léisung fir dëse Problem gestallt huet, huet d'Go Entwécklungsteam erstallt forum thread, déi beschriwwen hunn, wéi se dëst Thema ëmgoen. Hir Empfehlung war einfach de ganze Repository an Äre Projet enges Daags ze kopéieren an et "wéi ass" ze loossen. Wat d'Häll denken se? Mir hunn erstaunlech Versiounskontrollsystemer mat super Tagging a Versiounssupport déi d'Go Creatoren ignoréieren a just de Quellcode kopéieren.

Kulturgepäck vum Xi

Menger Meenung no, Go gouf vu Leit entwéckelt, déi hir ganzt Liewen C benotzt haten a vun deenen, déi net eppes Neies probéieren wollten. D'Sprooch kann als C beschriwwe ginn mat extra Rieder (orig.: Training Rieder). Et gi keng nei Iddien dran, ausser Ënnerstëtzung fir Parallelismus (wat iwwregens wonnerbar ass) an dat ass schued. Dir hutt exzellente Parallelismus an enger kaum benotzbarer, lame Sprooch.

En anere kräischende Problem ass datt Go eng prozedural Sprooch ass (wéi de stille Horror vu C). Dir schlussendlech Code an engem prozedurale Stil schreiwen, deen archaesch an verännert fillt. Ech weess datt objektorientéiert Programméierung keng Sëlwerkugel ass, awer et wier super fir d'Detailer an d'Typen ze abstrakt an d'Verkapselung ze bidden.

Einfachheet fir Ären eegene Virdeel

Go gouf entwéckelt fir einfach ze sinn an et geléngt bei deem Zil. Et gouf fir schwaach Programméierer geschriwwen, mat enger aler Sprooch als Schabloun. Et kënnt komplett mat einfachen Tools fir einfach Saachen ze maachen. Et ass einfach ze liesen an einfach ze benotzen.

Et ass extrem verbose, onimpressiv a schlecht fir intelligent Programméierer.

Spass mersinvald fir Ännerungen

Source: will.com

Setzt e Commentaire