Kāpēc Go dizains ir kaitīgs viedajiem programmētājiem?

Pēdējo mēneÅ”u laikā es izmantoju Go ievieÅ”anai. Koncepta pierādÄ«jums (apm.: kods idejas funkcionalitātes pārbaudei) brÄ«vajā laikā, daļēji paÅ”as programmÄ“Å”anas valodas pētÄ«Å”anai. PaÅ”as programmas ir ļoti vienkārÅ”as un nav Ŕī raksta mērÄ·is, taču pati Go lietoÅ”anas pieredze ir pelnÄ«jusi dažus vārdus par to. Go solās bÅ«t (apm.: 2015. gadā rakstÄ«ts raksts) populāra valoda nopietnam mērogojamam kodam. Valodu izveidoja Google, kur tā tiek aktÄ«vi izmantota. Secinājums, es godÄ«gi domāju, ka Go valodas dizains ir slikts viedajiem programmētājiem.

Paredzēts vājiem programmētājiem?

Go ir ļoti viegli iemācÄ«ties, tik viegli, ka ievads aizņēma vienu vakaru, pēc kura jau varēju produktÄ«vi kodēt. Grāmatu, kuru es mēdzu iemācÄ«ties Go, sauc Ievads programmā Go (tulkojums), tas ir pieejams tieÅ”saistē. Grāmata, tāpat kā pats Go pirmkods, ir viegli lasāma, tajā ir labi kodu piemēri, un tajā ir aptuveni 150 lappuses, kuras var izlasÄ«t vienā piegājienā. Å Ä« vienkārŔība sākotnēji ir atsvaidzinoÅ”a, it Ä«paÅ”i programmÄ“Å”anas pasaulē, kas ir piepildÄ«ta ar pārāk sarežģītu tehnoloÄ£iju. Bet galu galā agrāk vai vēlāk rodas doma: "Vai tas tieŔām tā ir?"

Google apgalvo, ka Go vienkārŔība ir tā pārdoÅ”anas punkts, un valoda ir paredzēta maksimālai produktivitātei lielās komandās, taču es par to Å”aubos. Ir funkcijas, kuru trÅ«kst, vai tās ir pārāk detalizētas. Un tas viss tāpēc, ka trÅ«kst uzticÄ«bas izstrādātājiem, pieņemot, ka viņi neko nespēj izdarÄ«t pareizi. Å Ä« vēlme pēc vienkārŔības bija apzināts valodas dizaineru lēmums, un, lai pilnÄ«bā saprastu, kāpēc tas bija vajadzÄ«gs, mums ir jāsaprot izstrādātāju motivācija un tas, ko viņi mēģināja sasniegt Go.

Tātad, kāpēc tas tika izveidots tik vienkārÅ”i? Å eit ir pāris citāti Robs Paiks (apm.: viens no Go valodas lÄ«dzveidotājiem):

Galvenais Å”eit ir tas, ka mÅ«su programmētāji (apm.: Google darbinieki) nav pētnieki. Viņi, kā likums, ir diezgan jauni, nāk pie mums pēc studijām, iespējams, viņi ir apguvuÅ”i Java, C/C++ vai Python. Viņi nevar saprast lielisku valodu, bet tajā paŔā laikā mēs vēlamies, lai viņi izveidotu labu programmatÅ«ru. Tāpēc viņu valodai jābÅ«t viegli saprotamai un apgÅ«stamai.
 
Viņam vajadzētu bÅ«t pazÄ«stamam, rupji runājot, lÄ«dzÄ«gi kā C. Programmētāji, kas strādā Google, sāk savu karjeru agri un pārsvarā pārzina procesuālās valodas, jo Ä«paÅ”i C saimi. PrasÄ«ba pēc ātras produktivitātes jaunā programmÄ“Å”anas valodā nozÄ«mē, ka valodai nevajadzētu bÅ«t pārāk radikālai.

Kas? Tātad Robs Paiks bÅ«tÄ«bā saka, ka Google izstrādātāji nav tik labi, tāpēc viņi radÄ«ja valodu idiotiem (apm.: nomākts), lai viņi varētu kaut ko darÄ«t. Kāds augstprātÄ«gs skatiens uz paÅ”a kolēģiem? Es vienmēr esmu uzskatÄ«jis, ka Google izstrādātāji ir atlasÄ«ti no spilgtākajiem un labākajiem pasaulē. Vai viņi var tikt galā ar kaut ko grÅ«tāku?

PārmērÄ«gas vienkārŔības artefakti

BÅ«t vienkārÅ”am ir cienÄ«gs mērÄ·is jebkurā dizainā, un mēģināt izveidot kaut ko vienkārÅ”u ir grÅ«ti. Tomēr, mēģinot atrisināt (vai pat izteikt) sarežģītas problēmas, dažreiz ir nepiecieÅ”ams sarežģīts instruments. SarežģītÄ«ba un sarežģītÄ«ba nav labākās programmÄ“Å”anas valodas Ä«paŔības, taču pastāv vidusceļŔ, kurā valoda var radÄ«t elegantas abstrakcijas, kuras ir viegli saprast un lietot.

Ne pārāk izteiksmīgs

VienkārŔības dēļ Go trÅ«kst konstrukciju, kas citās valodās tiek uztvertas kā dabiskas. Sākumā tā var Ŕķist laba ideja, taču praksē tas rada daudznozÄ«mÄ«gu kodu. Iemeslam tam vajadzētu bÅ«t acÄ«mredzamam ā€“ izstrādātājiem ir jābÅ«t viegli lasāmam citu cilvēku kodam, taču patiesÄ«bā Å”ie vienkārÅ”ojumi tikai kaitē lasāmÄ«bai. Vārdā Go nav saÄ«sinājumu: vai nu daudz, vai neko.

Piemēram, konsoles utilÄ«ta, kas nolasa stdin vai failu no komandrindas argumentiem, izskatÄ«tos Ŕādi:

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

Lai gan arÄ« Å”is kods cenÅ”as bÅ«t pēc iespējas vispārÄ«gāks, Go piespiedu daudzvārdÄ«ba traucē, un rezultātā vienkārÅ”as problēmas risināŔanas rezultātā tiek iegÅ«ts liels koda daudzums.

Å eit, piemēram, ir vienas un tās paÅ”as problēmas risinājums 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);
    }
}

Un kurÅ” tagad ir lasāmāks? Es atdoÅ”u savu balsi D. Viņa kods ir daudz lasāmāks, jo viņŔ skaidrāk apraksta darbÄ«bas. D izmanto daudz sarežģītākus jēdzienus (apm.: alternatÄ«vās funkcijas izsaukums Šø veidnes) nekā Go piemērā, taču patiesÄ«bā nav nekā sarežģīta to izpratnē.

KopēŔanas elle

Populārs ieteikums Go uzlaboÅ”anai ir vispārÄ«gums. Tas vismaz palÄ«dzēs izvairÄ«ties no nevajadzÄ«gas koda kopÄ“Å”anas, lai atbalstÄ«tu visus datu tipus. Piemēram, veselu skaitļu saraksta summÄ“Å”anas funkciju var Ä«stenot tikai kopējot un ielÄ«mējot tās pamatfunkciju katram vesela skaitļa veidam; cita veida nav:

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

Un Å”is piemērs pat neder parakstÄ«tajiem tipiem. Å Ä« pieeja pilnÄ«bā pārkāpj principu neatkārtoties (DRY), viens no slavenākajiem un acÄ«mredzamākajiem principiem, kura ignorÄ“Å”ana ir daudzu kļūdu avots. Kāpēc Go to dara? Tas ir briesmÄ«gs valodas aspekts.

Tas pats piemērs uz D:

import std.stdio;
import std.algorithm;

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

VienkārÅ”i, eleganti un tieÅ”i uz lietu. Å eit izmantotā funkcija ir reduce veidnes tipam un predikātam. Jā, tas atkal ir sarežģītāks par Go versiju, taču tas nav tik grÅ«ti saprotams viedajiem programmētājiem. Kuru piemēru ir vieglāk uzturēt un vieglāk lasÄ«t?

VienkārÅ”a tipa sistēmas apvedceļŔ

Es domāju, ka Go programmētāji, lasot Å”o, putos no mutes un kliedz: "JÅ«s darāt to nepareizi!" Nu, ir vēl viens veids, kā izveidot vispārÄ«gu funkciju un tipus, bet tas pilnÄ«bā izjauc tipu sistēmu!

Apskatiet Å”o muļķīga valodas labojuma piemēru, lai novērstu problēmu:

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

Å Ä« Ä«stenoÅ”ana Reduce tika aizgÅ«ts no raksta Idiomātiski vispārÄ«gie medikamenti pakalpojumā Go (apm.: Es nevarēju atrast tulkojumu, priecāŔos, ja jÅ«s palÄ«dzēsiet. Nu, ja tas ir idiotisks, es negribētu redzēt ne-idiomātisku piemēru. LietoÅ”ana interface{} - farss, un valodā tas ir nepiecieÅ”ams tikai, lai apietu rakstÄ«Å”anu. Å Ä« ir tukÅ”a saskarne, un visi veidi to ievieÅ”, nodroÅ”inot pilnÄ«gu brÄ«vÄ«bu ikvienam. Å is programmÄ“Å”anas stils ir Å”ausmÄ«gi neglÄ«ts, un tas vēl nav viss. Šādiem akrobātiskajiem varoņdarbiem ir jāizmanto izpildlaika atspoguļojums. Pat Robam Paikam nepatÄ«k personas, kas to ļaunprātÄ«gi izmanto, kā viņŔ minēja vienā no saviem ziņojumiem.

Å is ir spēcÄ«gs rÄ«ks, kas jāizmanto piesardzÄ«gi. No tā jāizvairās, ja vien tas nav absolÅ«ti nepiecieÅ”ams.

Es Å”o muļķību vietā ņemtu D veidnes. Kā kāds var tā teikt interface{} lasāmāks vai pat droÅ”s rakstÄ«Å”anai?

Atkarības pārvaldības bēdas

Go ir iebÅ«vēta atkarÄ«bas sistēma, kas balstÄ«ta uz populāriem mitināŔanas pakalpojumu sniedzējiem VCS. RÄ«ki, kas tiek piegādāti kopā ar Go, zina par Å”iem pakalpojumiem un var vienā rāvienā lejupielādēt, izveidot un instalēt kodu no tiem. Lai gan tas ir lieliski, versiju veidoÅ”anā ir liels trÅ«kums! Jā, tā ir taisnÄ«ba, ka avota kodu var iegÅ«t no tādiem pakalpojumiem kā github vai bitbucket, izmantojot Go rÄ«kus, taču jÅ«s nevarat norādÄ«t versiju. Un atkal vienkārŔība uz lietderÄ«bas rēķina. Es nespēju saprast Ŕāda lēmuma loÄ£iku.

Pēc jautājumu uzdoÅ”anas par Ŕīs problēmas risinājumu Go izstrādes komanda izveidoja foruma pavediens, kurā bija izklāstÄ«ts, kā viņi gatavojas apiet Å”o problēmu. Viņu ieteikums bija kādu dienu vienkārÅ”i kopēt visu repozitoriju savā projektā un atstāt to ā€œkā irā€. Ko pie velna viņi domā? Mums ir pārsteidzoÅ”as versiju kontroles sistēmas ar lielisku marÄ·Ä“Å”anu un versiju atbalstu, ko Go veidotāji ignorē un vienkārÅ”i kopē pirmkodu.

Kultūras bagāža no Xi

Manuprāt, Go izstrādāja cilvēki, kuri visu mūžu bija lietojuÅ”i C, un tie, kuri nevēlējās izmēģināt kaut ko jaunu. Valodu var raksturot kā C ar papildu riteņiem (orig.: apmācÄ«bas riteņi). Tajā nav jaunu ideju, izņemot atbalstu paralēlismam (kas, starp citu, ir brÄ«niŔķīgi), un tas ir kauns. Jums ir izcils paralēlisms tikko lietojamā, klibā valodā.

Vēl viena čīkstoÅ”a problēma ir tā, ka Go ir procesuāla valoda (tāpat kā C klusās Å”ausmas). JÅ«s galu galā rakstāt kodu procesuālā stilā, kas Ŕķiet arhaisks un novecojis. Es zinu, ka objektorientētā programmÄ“Å”ana nav sudraba lode, taču bÅ«tu lieliski, ja spētu abstrahēt detaļas tipos un nodroÅ”ināt iekapsulÄ“Å”anu.

VienkārŔība jūsu paŔu labā

Go tika izstrādāts tā, lai tas bÅ«tu vienkārÅ”s, un tas izdodas sasniegt Å”o mērÄ·i. Tas tika rakstÄ«ts vājiem programmētājiem, kā veidni izmantojot vecu valodu. Tas ir komplektā ar vienkārÅ”iem rÄ«kiem vienkārÅ”u lietu veikÅ”anai. Tas ir viegli lasāms un ērti lietojams.

Tas ir ārkārtīgi runīgs, neizteiksmīgs un slikti gudriem programmētājiem.

Paldies mersinvald labojumiem

Avots: www.habr.com

Pievieno komentāru