Kwa nini Ubunifu wa Go ni Mbaya kwa Watengenezaji wa Programu Mahiri

Katika miezi iliyopita nimekuwa nikitumia Go kwa utekelezaji. Uthibitisho wa Dhana (takriban.: msimbo wa kujaribu utendaji wa wazo) katika wakati wake wa bure, kwa sehemu kusoma lugha ya programu yenyewe. Mipango yenyewe ni rahisi sana na sio madhumuni ya makala hii, lakini uzoefu wa kutumia Go yenyewe unastahili maneno machache kuhusu hilo. Nenda ahadi kuwa (takriban.: makala iliyoandikwa mwaka wa 2015) lugha maarufu kwa msimbo mbaya sana. Lugha iliundwa na Google, ambapo inatumika kikamilifu. Jambo la msingi, nadhani kwa uaminifu kwamba muundo wa lugha ya Go ni mbaya kwa watengenezaji programu mahiri.

Je, imeundwa kwa ajili ya watayarishaji programu dhaifu?

Go ni rahisi sana kujifunza, ni rahisi sana hivi kwamba utangulizi ulinichukua jioni moja, baada ya hapo ningeweza kuandika kwa tija. Kitabu nilichokuwa nikijifunza Go kinaitwa Utangulizi wa Kupanga Programu katika Go (tafsiri), inapatikana mtandaoni. Kitabu, kama msimbo wa chanzo cha Go yenyewe, ni rahisi kusoma, kina mifano mizuri ya msimbo, na kina kurasa 150 hivi zinazoweza kusomwa kwa muda mmoja. Usahili huu unaburudisha mwanzoni, hasa katika ulimwengu wa programu uliojaa teknolojia iliyo ngumu zaidi. Lakini mwishowe, mapema au baadaye wazo linatokea: "Hii ni kweli?"

Google inadai unyenyekevu wa Go ni sehemu yake ya kuuza na lugha imeundwa kwa ajili ya tija ya juu katika timu kubwa, lakini nina shaka. Kuna vipengele ambavyo havipo au vina maelezo mengi kupita kiasi. Na yote kwa sababu ya ukosefu wa imani kwa watengenezaji, kwa kudhani kuwa hawawezi kufanya chochote sawa. Tamaa hii ya usahili ilikuwa uamuzi wa kufahamu wa wabunifu wa lugha, na ili kuelewa kikamilifu kwa nini ilihitajika, ni lazima tuelewe motisha ya wasanidi programu na kile walichokuwa wakijaribu kufikia katika Go.

Kwa hivyo kwa nini ilifanywa rahisi sana? Hapa kuna nukuu kadhaa Rob Pike (takriban.: mmoja wa waundaji wenza wa lugha ya Go):

Jambo kuu hapa ni kwamba watengenezaji programu wetu (takriban.: WanaGoogle) sio watafiti. Wao ni, kama sheria, wachanga kabisa, wanakuja kwetu baada ya kusoma, labda walisoma Java, au C / C ++, au Python. Hawawezi kuelewa lugha kubwa, lakini wakati huo huo tunataka watengeneze programu nzuri. Ndio maana lugha yao inapaswa kuwa rahisi kwao kuelewa na kujifunza.
 
Anapaswa kuwa mzoefu, anayezungumza takriban sawa na C. Watayarishaji programu wanaofanya kazi katika Google huanza taaluma zao mapema na mara nyingi wanafahamu lugha za kitaratibu, hasa familia ya C. Mahitaji ya tija ya haraka katika lugha mpya ya programu inamaanisha kuwa lugha haipaswi kuwa kali sana.

Nini? Kwa hivyo Rob Pike kimsingi anasema kwamba watengenezaji kwenye Google sio wazuri, ndiyo sababu waliunda lugha ya wajinga (takriban.: dumbed down) ili waweze kufanya jambo fulani. Ni aina gani ya kiburi kuangalia wenzako mwenyewe? Nimekuwa nikiamini kuwa wasanidi programu wa Google huchaguliwa kutoka kwa watengenezaji bora na bora zaidi Duniani. Hakika wanaweza kushughulikia jambo gumu zaidi?

Mabaki ya unyenyekevu kupita kiasi

Kuwa rahisi ni lengo linalostahili katika kubuni yoyote, na kujaribu kufanya kitu rahisi ni vigumu. Hata hivyo, wakati wa kujaribu kutatua (au hata kueleza) matatizo magumu, wakati mwingine chombo ngumu kinahitajika. Utata na ugumu sio sifa bora za lugha ya programu, lakini kuna msingi wa kati ambao lugha inaweza kuunda vifupisho vya kifahari ambavyo ni rahisi kuelewa na kutumia.

Sio kujieleza sana

Kwa sababu ya kujitolea kwake kwa urahisi, Go haina miundo ambayo inachukuliwa kuwa ya asili katika lugha zingine. Hili linaweza kuonekana kama wazo zuri mwanzoni, lakini kwa vitendo husababisha msimbo wa kitenzi. Sababu ya hii inapaswa kuwa dhahiri - inahitaji kuwa rahisi kwa watengenezaji kusoma msimbo wa watu wengine, lakini kwa kweli kurahisisha hizi kunadhuru tu usomaji. Hakuna vifupisho katika Go: ama mengi au hakuna.

Kwa mfano, matumizi ya koni ambayo inasoma stdin au faili kutoka kwa hoja za mstari wa amri ingeonekana kama hii:

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

Ingawa msimbo huu pia hujaribu kuwa wa jumla iwezekanavyo, kitenzi cha kulazimishwa cha Go hupata njia, na matokeo yake, kutatua tatizo rahisi husababisha idadi kubwa ya msimbo.

Hapa, kwa mfano, ni suluhisho la tatizo sawa katika 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);
    }
}

Na ni nani anayesomeka zaidi sasa? Nitatoa kura yangu kwa D. Nambari yake inasomeka zaidi kwa sababu anaelezea vitendo kwa uwazi zaidi. D hutumia dhana ngumu zaidi (takriban.: simu mbadala ya kazi ΠΈ mifumo) kuliko mfano wa Go, lakini kwa kweli hakuna chochote gumu kuhusu kuzielewa.

Kuzimu ya kuiga

Pendekezo maarufu la kuboresha Go ni la jumla. Hii itasaidia angalau kuzuia kunakili msimbo bila lazima ili kusaidia aina zote za data. Kwa mfano, kazi ya kujumlisha orodha ya nambari kamili inaweza kutekelezwa kwa njia yoyote isipokuwa kwa kunakili-kubandika utendakazi wake wa kimsingi kwa kila aina kamili; hakuna njia nyingine:

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

Na mfano huu haufanyi kazi hata kwa aina zilizosainiwa. Njia hii inakiuka kabisa kanuni ya kutojirudia (DRY), mojawapo ya kanuni maarufu na za wazi, kupuuza ambayo ni chanzo cha makosa mengi. Kwa nini Go hufanya hivi? Hiki ni kipengele cha kutisha cha lugha.

Mfano sawa kwenye D:

import std.stdio;
import std.algorithm;

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

Rahisi, kifahari na moja kwa moja kwa uhakika. Kitendaji kinachotumika hapa ni reduce kwa aina ya kiolezo na kihusishi. Ndiyo, hii ni ngumu tena kuliko toleo la Go, lakini si vigumu kwa watengenezaji programu mahiri kuelewa. Ni mfano gani ambao ni rahisi kudumisha na rahisi kusoma?

Njia rahisi ya kukwepa mfumo

Ninawazia watayarishaji wa programu za Go wakisoma hili watakuwa wakitokwa na povu mdomoni na kupiga kelele, "Unafanya vibaya!" Kweli, kuna njia nyingine ya kufanya kazi ya generic na aina, lakini inavunja kabisa mfumo wa aina!

Angalia mfano huu wa urekebishaji wa lugha ya kijinga ili kutatua shida:

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

Utekelezaji huu Reduce ilikopwa kutoka kwa makala Jenetiki za nahau katika Go (takriban.: Sikuweza kupata tafsiri, nitafurahi ikiwa utasaidia kwa hili). Kweli, ikiwa ni nahau, ningechukia kuona mfano usio wa nahau. Matumizi interface{} - kinyago, na kwa lugha inahitajika tu kupitisha uchapaji. Hii ni kiolesura tupu na aina zote huitekeleza, ikiruhusu uhuru kamili kwa kila mtu. Mtindo huu wa programu ni mbaya sana, na si hivyo tu. Michezo ya sarakasi kama hii inahitaji matumizi ya kuakisi wakati wa kukimbia. Hata Rob Pike hapendi watu wanaotumia vibaya hii, kama alivyosema katika moja ya ripoti zake.

Hii ni zana yenye nguvu ambayo inapaswa kutumika kwa tahadhari. Inapaswa kuepukwa isipokuwa lazima madhubuti.

Ningechukua violezo vya D badala ya upuuzi huu. Mtu anawezaje kusema hivyo interface{} inayosomeka zaidi au hata chapa salama?

Matatizo ya Usimamizi wa Utegemezi

Go ina mfumo wa utegemezi uliojengewa ndani uliojengwa juu ya watoa huduma maarufu wa upangishaji VCS. Zana zinazokuja na Go zinajua kuhusu huduma hizi na zinaweza kupakua, kujenga, na kusakinisha msimbo kutoka kwazo kwa haraka haraka. Ingawa hii ni nzuri, kuna dosari kubwa katika toleo! Ndiyo, ni kweli kwamba unaweza kupata msimbo wa chanzo kutoka kwa huduma kama vile github au bitbucket kwa kutumia zana za Go, lakini huwezi kubainisha toleo. Na tena unyenyekevu kwa gharama ya manufaa. Siwezi kuelewa mantiki ya uamuzi kama huo.

Baada ya kuuliza maswali kuhusu suluhu la tatizo hili, timu ya maendeleo ya Go iliunda thread ya jukwaa, ambayo ilieleza jinsi watakavyolitatua suala hili. Pendekezo lao lilikuwa kunakili tu hazina nzima kwenye mradi wako siku moja na kuiacha "kama ilivyo." Je, wanafikiria nini? Tuna mifumo ya ajabu ya udhibiti wa matoleo yenye uwekaji lebo bora na usaidizi wa matoleo ambayo watayarishi wa Go hupuuza na kunakili msimbo wa chanzo.

Mizigo ya kitamaduni kutoka kwa Xi

Kwa maoni yangu, Go ilitengenezwa na watu ambao walikuwa wametumia C maisha yao yote na wale ambao hawakutaka kujaribu kitu kipya. Lugha inaweza kuelezewa kama C na magurudumu ya ziada (asili.: magurudumu ya mafunzo) Hakuna mawazo mapya ndani yake, isipokuwa kwa msaada wa usawa (ambayo, kwa njia, ni ya ajabu) na hii ni aibu. Una usambamba bora katika lugha isiyoweza kutumika, ya kilema.

Shida nyingine ya kushangaza ni kwamba Go ni lugha ya kitaratibu (kama vile hofu ya kimya ya C). Unaishia kuandika msimbo kwa mtindo wa kitaratibu ambao unahisi kuwa wa kizamani na umepitwa na wakati. Najua upangaji unaolenga kitu sio risasi ya fedha, lakini itakuwa nzuri kuweza kutoa maelezo katika aina na kutoa ujumuishaji.

Urahisi kwa manufaa yako mwenyewe

Go iliundwa kuwa rahisi na inafanikiwa kwa lengo hilo. Iliandikwa kwa watengeneza programu dhaifu, kwa kutumia lugha ya zamani kama kiolezo. Inakuja kamili na zana rahisi kufanya mambo rahisi. Ni rahisi kusoma na rahisi kutumia.

Ni ya kitenzi sana, haivutii, na ni mbaya kwa watengeneza programu mahiri.

Shukrani mersinvald kwa ajili ya marekebisho

Chanzo: mapenzi.com

Kuongeza maoni