Niyə Go Ağılsız Proqramçılar üçün Pisdir

Məqalə əvvəllər dərc olunmuş məqaləyə cavab olaraq yazılıb antipodean məqalə.

Niyə Go Ağılsız Proqramçılar üçün Pisdir

Son iki il ərzində mən inkişaf etmiş hesablaşma sistemi ilə ixtisaslaşmış RADIUS serverini tətbiq etmək üçün Go-dan istifadə edirəm. Bu yolda dilin özünün incəliklərini öyrənirəm. Proqramların özləri çox sadədir və bu məqalənin məqsədi deyil, lakin Go-dan istifadə təcrübəsi onun müdafiəsində bir neçə sözə layiqdir. Go ciddi, genişlənən kod üçün getdikcə əsas dilə çevrilir. Dil Google tərəfindən yaradılıb və burada fəal şəkildə istifadə olunur. Nəticə etibarı ilə mən Go dilinin dizaynının UNIntelligent proqramçılar üçün pis olduğunu düşünürəm.

Zəif proqramçılar üçün nəzərdə tutulub?

Zəiflər problemlərdən danışır. İdeyalar və xəyallar haqqında güclü danışıq...

Go öyrənmək çox asandır, o qədər asandır ki, kodu praktiki olaraq heç bir təlim olmadan oxuya bilərsiniz. Dilin bu xüsusiyyətindən bir çox qlobal şirkətlərdə kod əsas olmayan mütəxəssislərlə (menecerlər, müştərilər və s.) birlikdə oxunduqda istifadə olunur. Bu, Dizayn Əsaslı İnkişaf kimi metodologiyalar üçün çox əlverişlidir.
Hətta təcrübəsiz proqramçılar bir və ya iki həftədən sonra kifayət qədər layiqli kod istehsal etməyə başlayırlar. Oxuduğum kitab “Go Programming”dir (Mark Summerfield tərəfindən). Kitab çox gözəldir, dilin bir çox nüanslarına toxunur. Java, PHP kimi lazımsız mürəkkəb dillərdən sonra sehrin olmaması təravətləndirir. Ancaq gec və ya tez bir çox məhdud proqramçı köhnə metodlardan yeni bir sahədə istifadə etmək fikrinə sahibdir. Bu həqiqətən lazımdırmı?

Rob Pike (dilin əsas ideoloqu) Go dilini asan başa düşülən və istifadəsi effektiv olan sənaye dili kimi yaratmışdır. Dil böyük komandalarda maksimum məhsuldarlıq üçün nəzərdə tutulub və buna heç bir şübhə yoxdur. Bir çox təcrübəsiz proqramçılar, çatışmayan bir çox xüsusiyyətlərin olduğundan şikayətlənirlər. Bu sadəlik istəyi dil dizaynerlərinin şüurlu qərarı idi və bunun nə üçün lazım olduğunu tam başa düşmək üçün biz tərtibatçıların motivasiyasını və onların Go-da nəyə nail olmağa çalışdıqlarını başa düşməliyik.

Bəs niyə bu qədər sadələşdirildi? Rob Pikdən bir neçə sitat təqdim edirik:

Burada əsas məqam ondan ibarətdir ki, bizim proqramçılar tədqiqatçı deyillər. Onlar, bir qayda olaraq, kifayət qədər gəncdirlər, oxuyandan sonra bizə gəlirlər, bəlkə də Java, ya C/C++, ya da Python dilini öyrəniblər. Onlar gözəl bir dili başa düşə bilmirlər, lakin eyni zamanda biz onlardan yaxşı proqram təminatı yaratmalarını istəyirik. Ona görə də dil asan başa düşülən və öyrənilən olmalıdır.

O, tanış olmalıdır, təxminən C-yə bənzəyir. Google-da işləyən proqramçılar karyeralarına erkən başlayırlar və əsasən prosedur dilləri, xüsusən də C ailəsi ilə tanış olurlar. Yeni proqramlaşdırma dilində sürətli məhsuldarlıq tələbi o deməkdir ki, bu dil çox radikal olmamalıdır.

Müdrik sözlər, elə deyilmi?

Sadəlik əsərləri

Sadəlik gözəllik üçün zəruri şərtdir. Lev Tolstoy.

Sadə saxlamaq istənilən dizaynda ən vacib məqsədlərdən biridir. Bildiyiniz kimi, mükəmməl bir layihə əlavə ediləcək bir şey olmayan bir layihə deyil, çıxarılacaq bir şey olmayan bir layihədir. Bir çox insanlar mürəkkəb problemləri həll etmək (və ya hətta ifadə etmək) üçün mürəkkəb bir vasitənin lazım olduğuna inanırlar. Lakin, belə deyil. Məsələn, PERL dilini götürək. Dil ideoloqları hesab edirdilər ki, bir proqramçının bir problemi həll etmək üçün ən azı üç fərqli yolu olmalıdır. Go dilinin ideoloqları fərqli bir yol tutdular; məqsədə çatmaq üçün bir yol, lakin həqiqətən yaxşı bir yol kifayət olduğuna qərar verdilər. Bu yanaşmanın ciddi əsası var: yeganə yolu öyrənmək daha asandır və unutmaq daha çətindir.

Bir çox miqrantlar dildə nəfis abstraksiyaların olmamasından şikayətlənirlər. Bəli, bu doğrudur, lakin bu dilin əsas üstünlüklərindən biridir. Dildə minimum sehr var - ona görə də proqramı oxumaq üçün dərin bilik tələb olunmur. Kodun təfərrüatlılığına gəlincə, bu heç də problem deyil. Yaxşı yazılmış Golanq proqramı az və ya heç bir quruluş olmadan şaquli oxuyur. Bundan əlavə, bir proqramı oxumaq sürəti ən azı onu yazma sürətindən daha böyük bir sıradır. Əgər bütün kodun vahid formata malik olduğunu nəzərə alsanız (daxili gofmt əmrindən istifadə etməklə həyata keçirilir), onda bir neçə əlavə sətir oxumaq heç də problem deyil.

Çox ifadəli deyil

İncəsənət azadlığı məhdudlaşdırılanda dözmür. Dəqiqlik onun məsuliyyəti deyil.

Sadəlik arzusuna görə Go-da başqa dillərdə onlara öyrəşmiş insanlar tərəfindən təbii bir şey kimi qəbul edilən konstruksiyalar yoxdur. Əvvəlcə bu, bir qədər əlverişsiz ola bilər, amma sonra proqramın oxunması daha asan və birmənalı olduğunu görürsən.

Məsələn, stdin və ya komanda xətti arqumentlərindən faylı oxuyan konsol yardım proqramı belə görünür:

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
)

func main() {

    flag.Parse()

    scanner := newScanner(flag.Args())

    var text string
    for scanner.Scan() {
        text += scanner.Text()
    }

    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Println(text)
}

func newScanner(flags []string) *bufio.Scanner {
    if len(flags) == 0 {
        return bufio.NewScanner(os.Stdin)
    }

    file, err := os.Open(flags[0])

    if err != nil {
        log.Fatal(err)
    }

    return bufio.NewScanner(file)
}

D-də eyni problemin həlli bir qədər qısa görünsə də, oxumaq asan deyil

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

Kopyalama cəhənnəmi

İnsan cəhənnəmi öz içində daşıyır. Martin Lüter.

Başlayanlar generiklərin olmaması baxımından daim Go-dan şikayətlənirlər. Bu problemi həll etmək üçün onların əksəriyyəti birbaşa kodun kopyalanmasından istifadə edir. Məsələn, tam ədədlərin siyahısını toplamaq funksiyası, bu cür peşəkarlar hesab edirlər ki, funksionallıq hər bir məlumat növü üçün sadə surətdə yapışdırmaqdan başqa heç bir şəkildə həyata keçirilə bilməz.

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 main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

Dil bu cür konstruksiyaları həyata keçirmək üçün kifayət qədər vasitələrə malikdir. Məsələn, ümumi proqramlaşdırma yaxşı olardı.

package main

import "fmt"

func Eval32(list []int32, fn func(a, b int32)int32) int32 {
    var res int32
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int32Add(a, b int32) int32 {
    return a + b
}

func int32Sub(a, b int32) int32 {
    return a + b
}

func Eval64(list []int64, fn func(a, b int64)int64) int64 {
    var res int64
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int64Add(a, b int64) int64 {
    return a + b
}

func int64Sub(a, b int64) int64 {
    return a - b
}

func main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(Eval32(list32, int32Add))
    fmt.Println(Eval64(list64, int64Add))
    fmt.Println(Eval64(list64, int64Sub))
}

Və kodumuz əvvəlki vəziyyətdən bir qədər uzun olsa da, ümumiləşdirildi. Ona görə də bütün arifmetik əməliyyatları həyata keçirmək bizim üçün çətin olmayacaq.

Çoxları deyəcək ki, D-də proqram xeyli qısa görünür və onlar haqlı olacaqlar.

import std.stdio;
import std.algorithm;

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

Bununla belə, yalnız daha qısadır, lakin daha düzgün deyil, çünki D tətbiqi səhvlərin idarə edilməsi problemini tamamilə rədd edir.

Real həyatda məntiqin mürəkkəbliyi artdıqca boşluq sürətlə daralır. Standart dil operatorlarından istifadə etməklə yerinə yetirilməsi mümkün olmayan hərəkəti yerinə yetirmək lazım olduqda boşluq daha da sürətlə bağlanır.

Davamlılıq, genişlənmək və oxunaqlılıq baxımından, mənim fikrimcə, Go dili uduzsa da, qalib gəlir.

Ümumiləşdirilmiş proqramlaşdırma bəzi hallarda bizə danılmaz faydalar verir. Bu, çeşidləmə paketi ilə aydın şəkildə təsvir olunur. Beləliklə, hər hansı bir siyahını çeşidləmək üçün sadəcə sort.Interface interfeysini tətbiq etməliyik.

import "sort"

type Names []string

func (ns Names) Len() int {
    return len(ns)
}

func (ns Names) Less(i, j int) bool {
    return ns[i] < ns[j]
}

func (ns Names) Swap(i, j int) {
    ns[i], ns[j] = ns[j], ns[i]
}

func main() {
    names := Names{"London", "Berlin", "Rim"}
    sort.Sort(names)
}

Hər hansı bir açıq mənbə layihəsi götürsəniz və grep “interface{}” -R əmrini işlətsəniz, çaşdırıcı interfeyslərin nə qədər tez-tez istifadə edildiyini görəcəksiniz. Yaxın fikirli yoldaşlar dərhal deyəcəklər ki, bütün bunlar generiklərin olmaması ilə bağlıdır. Lakin bu, həmişə belə olmur. Nümunə olaraq DELPHI-ni götürək. Bu eyni generiklərin mövcudluğuna baxmayaraq, o, ixtiyari məlumat növləri ilə əməliyyatlar üçün xüsusi VARIANT tipini ehtiva edir. Go dili də eyni şeyi edir.

Topdan sərçələrə qədər

Və dəli gödəkçəsi dəlilik ölçüsünə uyğun olmalıdır. Stanislav Lec.

Bir çox ekstremal pərəstişkarlar iddia edə bilər ki, Go-da generiklər yaratmaq üçün başqa bir mexanizm var - əks. Və onlar haqlı olacaqlar... ancaq nadir hallarda.

Rob Pike bizə xəbərdarlıq edir:

Bu ehtiyatla istifadə edilməli olan güclü bir vasitədir. Çox zərurət olmadıqca bundan çəkinmək lazımdır.

Vikipediya bizə aşağıdakıları deyir:

Reflection proqramın icra zamanı öz strukturunu və davranışını izləyə və dəyişdirə bildiyi prosesə aiddir. Refleksiyanın əsasını təşkil edən proqramlaşdırma paradiqmasına əks etdirici proqramlaşdırma deyilir. Bu metaproqramlaşdırmanın bir növüdür.

Ancaq bildiyiniz kimi, hər şey üçün pul ödəməlisən. Bu halda belədir:

  • proqramların yazılmasında çətinlik
  • proqramın icra sürəti

Buna görə də, böyük çaplı silah kimi əks etdirmə ehtiyatla istifadə edilməlidir. Yansıtmadan düşüncəsiz istifadə oxunmayan proqramlara, daimi səhvlərə və aşağı sürətə səbəb olur. Snob bir proqramçının başqa, daha praqmatik və təvazökar həmkarları qarşısında öz kodunu göstərə bilməsi sadəcə olaraq budur.

Xi-dən mədəni baqaj? Xeyr, bir sıra dillərdən!

Var-dövlətlə yanaşı, borclar da varislərə qalır.

Çoxlarının dilin tamamilə C irsinə əsaslandığına inanmasına baxmayaraq, bu belə deyil. Bu dil ən yaxşı proqramlaşdırma dillərinin bir çox aspektlərini özündə birləşdirir.

sintaksis

Hər şeydən əvvəl, qrammatik strukturların sintaksisi C dilinin sintaksisinə əsaslanır. Bununla belə, DELPHI dilinin də əhəmiyyətli təsiri olmuşdur. Beləliklə, proqramın oxunuşunu xeyli azaldan lazımsız mötərizələrin tamamilə silindiyini görürük. Dil həmçinin DELPHI dilinə xas olan “:=” operatorunu ehtiva edir. Paketlər anlayışı ADA kimi dillərdən götürülmüşdür. İstifadə edilməmiş obyektlərin bəyannaməsi PROLOG dilindən götürülmüşdür.

Semantik

Paketlər DELPHI dilinin semantikasına əsaslanırdı. Hər bir paket məlumat və kodu əhatə edir və özəl və ictimai qurumları ehtiva edir. Bu, paket interfeysini minimuma endirməyə imkan verir.

Nümayəndə heyəti üsulu ilə icra əməliyyatı DELPHI dilindən götürülmüşdür.

Tərtib

Zarafat olması səbəbsiz deyil: Go C proqramı tərtib edilərkən hazırlanmışdır. Dilin güclü tərəflərindən biri onun ultra sürətli tərtibidir. İdeya DELPHI dilindən götürülmüşdür. Hər bir Go paketi DELPHI moduluna uyğundur. Bu paketlər yalnız həqiqətən zəruri olduqda yenidən tərtib edilir. Buna görə də, növbəti redaktədən sonra bütün proqramı tərtib etməyə ehtiyac yoxdur, əksinə, yalnız dəyişdirilmiş paketləri və bu dəyişdirilmiş paketlərdən asılı olan paketləri yenidən tərtib edin (və hətta bundan sonra, yalnız paket interfeysləri dəyişdikdə).

Yüksək səviyyəli konstruksiyalar

Dil, C kimi aşağı səviyyəli dillərlə heç bir şəkildə əlaqəli olmayan bir çox fərqli yüksək səviyyəli konstruksiyaları ehtiva edir.

  • Simlər
  • Hash cədvəlləri
  • Dilimlər
  • Ördək yazmaq RUBY kimi dillərdən götürülmüşdür (təəssüf ki, çoxları başa düşmür və ya tam potensialından istifadə etmir).

Yaddaşın idarə edilməsi

Yaddaşın idarə edilməsi ümumiyyətlə ayrıca məqaləyə layiqdir. Əgər C++ kimi dillərdə idarəetmə tamamilə tərtibatçının ixtiyarına verilirsə, DELPHI kimi sonrakı dillərdə istinad hesablama modeli istifadə edilmişdir. Bu yanaşma ilə siklik arayışlara icazə verilmirdi, çünki yetim klasterlər formalaşdığından, Go-da belə klasterlərin (C# kimi) daxili aşkarlanması var. Bundan əlavə, zibil toplayıcı hazırda məlum olan tətbiqlərdən daha səmərəlidir və artıq bir çox real vaxt tapşırıqları üçün istifadə edilə bilər. Dilin özü dəyişəni saxlamaq üçün dəyərin yığında ayrıla biləcəyi vəziyyətləri tanıyır. Bu, yaddaş menecerinin yükünü azaldır və proqramın sürətini artırır.

Paralellik və paralellik

Dilin paralelliyi və rəqabət qabiliyyəti tərifdən kənardır. Heç bir aşağı səviyyəli dil Go ilə uzaqdan belə rəqabət apara bilməz. Ədalətli olmaq üçün qeyd etmək lazımdır ki, model dilin müəllifləri tərəfindən icad edilməmişdir, sadəcə olaraq yaxşı köhnə ADA dilindən götürülmüşdür. Dil bütün CPU-lardan istifadə edərək milyonlarla paralel əlaqəni emal etməyə qadirdir, eyni zamanda çox yivli kod üçün xarakterik olan çıxılmaz vəziyyətlər və yarış şərtləri ilə daha az mürəkkəb problemlərə malikdir.

Əlavə üstünlüklər

Qazanclı olsa, hamı fədakar olar.

Dil bizə bir sıra şübhəsiz faydalar da verir:

  • Layihəni qurduqdan sonra bir icra edilə bilən fayl tətbiqlərin yerləşdirilməsini çox asanlaşdırır.
  • Statik tipləmə və tipli nəticə, hətta testlər yazmadan da kodunuzdakı səhvlərin sayını əhəmiyyətli dərəcədə azalda bilər. Mən bəzi proqramçılar tanıyıram ki, onlar ümumiyyətlə testlər yazmadan işləyirlər və onların kodunun keyfiyyəti əhəmiyyətli dərəcədə pisləşmir.
  • Çox sadə çarpaz kompilyasiya və standart kitabxananın əla daşınması, bu, çarpaz platforma tətbiqlərinin inkişafını xeyli asanlaşdırır.
  • RE2 müntəzəm ifadələri mövzu üçün təhlükəsizdir və proqnozlaşdırıla bilən icra müddətinə malikdir.
  • Əksər layihələri üçüncü tərəf çərçivələri olmadan etməyə imkan verən güclü standart kitabxana.
  • Dil problemi həll etməkdən daha çox diqqəti yönəltmək üçün kifayət qədər güclüdür, lakin problemi effektiv şəkildə həll etmək üçün kifayət qədər aşağı səviyyədədir.
  • Go eko sistemi artıq bütün hallar üçün hazırlanmış alətləri ehtiva edir: testlər, sənədlər, paketlərin idarə edilməsi, güclü linterlər, kod yaratmaq, yarış şəraiti detektoru və s.
  • Go versiyası 1.11 populyar VCS hostinqinin üzərində qurulmuş daxili semantik asılılığın idarə edilməsini təqdim etdi. Go ekosistemini təşkil edən bütün alətlər bu xidmətlərdən bir anda kod yükləmək, qurmaq və quraşdırmaq üçün istifadə edir. Və bu əladır. 1.11 versiyasının gəlməsi ilə paket versiyaları ilə bağlı problem də tamamilə həll olundu.
  • Dilin əsas ideyası sehri azaltmaq olduğundan, dil tərtibatçıları səhvləri açıq şəkildə idarə etməyə təşviq edir. Və bu düzgündür, çünki əks halda o, sadəcə olaraq səhvlərin idarə olunmasını tamamilə unudacaq. Başqa bir şey budur ki, əksər tərtibatçılar səhvlərin idarə edilməsinə qəsdən məhəl qoymurlar, onları emal etmək əvəzinə səhvi yuxarıya yönləndirməyə üstünlük verirlər.
  • Dil klassik OOP metodologiyasını tətbiq etmir, çünki onun saf formasında Go-da virtuallıq yoxdur. Ancaq interfeyslərdən istifadə edərkən bu problem deyil. OOP-un olmaması yeni başlayanlar üçün giriş maneəsini əhəmiyyətli dərəcədə azaldır.

İctimai fayda üçün sadəlik

Mürəkkəbləşdirmək asandır, sadələşdirmək çətindir.

Go sadə olmaq üçün hazırlanmışdır və bu məqsədə nail olur. Bu, komanda işinin faydalarını anlayan və Enterprise səviyyəli dillərin sonsuz dəyişkənliyindən yorulan ağıllı proqramçılar üçün yazılmışdır. Arsenalında nisbətən kiçik sintaktik strukturlar dəstinə malik olmaqla, zaman keçdikcə praktiki olaraq dəyişikliklərə məruz qalmır, buna görə tərtibatçılar dil innovasiyalarını sonsuz öyrənmək üçün deyil, inkişaf üçün çox vaxt ayırırlar.

Şirkətlər həmçinin bir sıra üstünlüklər əldə edirlər: aşağı giriş maneəsi onlara tez bir zamanda mütəxəssis tapmağa imkan verir, dilin dəyişməzliyi isə 10 ildən sonra da eyni kodu istifadə etməyə imkan verir.

Nəticə

Böyük beyin ölçüsü heç bir fili Nobel mükafatı laureatı etməmişdir.

Şəxsi eqosu komanda ruhundan üstün olan proqramçılar, eləcə də akademik çətinlikləri və sonsuz "özünü təkmilləşdirməyi" sevən nəzəriyyəçilər üçün dil həqiqətən pisdir, çünki bu, ümumi məqsədli sənətkarlıq dilidir və bu, əldə etməyə imkan vermir. işinizin nəticəsindən estetik həzz alın və həmkarlarınız qarşısında özünüzü peşəkar göstərin (bir şərtlə ki, zəkanı IQ ilə deyil, bu meyarlarla ölçsək). Həyatda hər şey kimi, bu da şəxsi prioritet məsələsidir. Bütün dəyərli yeniliklər kimi, dil də ümumbəşəri inkardan kütləvi qəbula qədər artıq uzun bir yol keçmişdir. Dil sadəliyi ilə dahiyanədir və bildiyiniz kimi, dahiyanə olan hər şey sadədir!

Mənbə: www.habr.com

Добавить комментарий