Эмне үчүн Go акылсыз программисттер үчүн жаман

Макала мурда жарыяланган макалага жооп катары жазылган антиподеан макала.

Эмне үчүн Go акылсыз программисттер үчүн жаман

Акыркы эки жылдан ашык убакытта мен Go программасын өнүккөн биллинг системасы менен адистештирилген RADIUS серверин ишке ашыруу үчүн колдонуп жатам. Жолдо мен тилдин өзүнүн татаал жактарын үйрөнүп жатам. Программалардын өзү абдан жөнөкөй жана бул макаланын максаты эмес, бирок Go колдонуу тажрыйбасы аны коргоодо бир нече сөзгө татыктуу. Go олуттуу, масштабдуу код үчүн барган сайын негизги тилге айланууда. Тил Google тарабынан түзүлгөн, ал жерде активдүү колдонулат. Жыйынтыктап айтканда, мен чынын айтсам, Go тилинин дизайны UNintelligent программисттери үчүн жаман деп ойлойм.

Алсыз программисттер үчүн иштелип чыккан?

Алсыздар көйгөйлөрдү айтышат. Идеялар жана кыялдар жөнүндө күчтүү сөз...

Go үйрөнүү абдан оңой, ошондуктан сиз кодду дээрлик эч кандай машыгуусуз окуй аласыз. Тилдин бул өзгөчөлүгү көптөгөн дүйнөлүк компанияларда кодду негизги эмес адистер (менеджерлер, кардарлар ж.б.) менен бирге окуганда колдонулат. Бул Design Driven Development сыяктуу методологиялар үчүн абдан ыңгайлуу.
Ал тургай, жаңы программисттер бир же эки жумадан кийин абдан татыктуу кодду чыгара башташат. Мен окуган китеп "Go Programming" (Марк Саммерфилд тарабынан). Китеп абдан жакшы, ал тилдин көптөгөн нюанстарын козгойт. Java, PHP сыяктуу ашыкча татаал тилдерден кийин, сыйкырдын жоктугу сергитет. Бирок эртеби-кечпи, көптөгөн чектелген программисттер жаңы тармакта эски ыкмаларды колдонуу идеясына ээ. Бул чынында эле керекпи?

Роб Пайк (тилдин негизги идеологу) Go тилин түшүнүүгө оңой жана колдонууга эффективдүү индустриалдык тил катары жараткан. Бул тил чоң бригадаларда максималдуу өндүрүмдүүлүк үчүн иштелип чыккан жана буга эч кандай шек жок. Көптөгөн башталгыч программисттер, алар жетишпей жаткан көптөгөн өзгөчөлүктөр бар деп даттанышат. Жөнөкөйлүккө болгон бул каалоо тилдин дизайнерлеринин аң-сезимдүү чечими болгон жана ал эмне үчүн керек экенин толук түшүнүү үчүн биз иштеп чыгуучулардын мотивациясын жана алар Go программасында эмнеге жетишүүгө аракет кылып жатышканын түшүнүшүбүз керек.

Анда эмне үчүн ал ушунчалык жөнөкөй болгон? Бул жерде Роб Пайктан бир нече цитата келтирилген:

Бул жерде негизги нерсе биздин программисттер изилдөөчүлөр эмес. Алар, эреже катары, абдан жаш, окугандан кийин бизге келишет, балким алар Java, же C/C++ же Python тилдерин үйрөнүшкөн. Алар улуу тилди түшүнө алышпайт, бирок ошол эле учурда биз алардын жакшы программалык камсыздоону жаратышын каалайбыз. Ошондуктан тил түшүнүүгө жана үйрөнүүгө жеңил болушу керек.

Ал тааныш болушу керек, болжол менен айтканда, С. Google'да иштеген программисттер карьераларын эрте башташат жана көбүнчө процедуралык тилдерди, айрыкча C үй-бүлөсүн жакшы билишет. Жаңы программалоо тилиндеги тез өндүрүмдүүлүк талабы тил өтө радикал болбошу керек дегенди билдирет.

Акылдуу сөздөр, туурабы?

Жөнөкөйлүктүн артефакттары

Жөнөкөйлүк - сулуулук үчүн зарыл шарт. Лев Толстой.

Аны жөнөкөй сактоо ар кандай дизайндагы эң маанилүү максаттардын бири. Белгилүү болгондой, идеалдуу долбоор – бул кошумчалай турган эч нерсеси жок долбоор эмес, андан алып салууга эч нерсеси жок долбоор. Көптөгөн адамдар татаал маселелерди чечүү (ал тургай билдирүү) үчүн татаал курал керек деп эсептешет. Бирок, андай эмес. Мисалы, PERL тилин алалы. Тил идеологдору программистте бир маселени чечүү үчүн жок дегенде үч түрдүү ыкма болушу керек деп эсептешкен. Го тилинин идеологдору башка жолду басып өтүштү, алар максатка жетүү үчүн бир жол, бирок чындап эле жакшы жол жетиштүү деп чечишти. Бул ыкманын олуттуу негизи бар: жалгыз жолду үйрөнүү оңой жана унутуу кыйын.

Көптөгөн мигранттар тилде көрктүү абстракциялар жок деп нааразы. Ооба, бул туура, бирок бул тилдин негизги артыкчылыктарынын бири. Тил минималдуу сыйкырды камтыйт - ошондуктан программаны окуу үчүн терең билим талап кылынбайт. Ал эми кодекстин тактыгына келсек, бул такыр көйгөй эмес. Жакшы жазылган Голанг программасы түзүмү аз же такыр жок, вертикалдуу окуйт. Мындан тышкары, программаны окуу ылдамдыгы, жок эле дегенде, аны жазуу ылдамдыгынан чоңураак. Эгерде сиз бардык коддун бирдиктүү форматтоосу бар деп эсептесеңиз (курулган gofmt буйругун колдонуу менен жасалган), анда бир нече кошумча саптарды окуу такыр көйгөй эмес.

Өтө экспрессивдүү эмес

Эркиндиги чектелип турганда искусство чыдабайт. Тактык анын жоопкерчилиги эмес.

Жөнөкөйлүккө умтулгандыктан, Go башка тилдерде аларга көнүп калган адамдар тарабынан табигый нерсе катары кабыл алынган конструкциялар жок. Башында бул бир аз ыңгайсыз болушу мүмкүн, бирок кийин сиз программаны окуу бир топ жеңил жана түшүнүктүү экенин байкайсыз.

Мисалы, stdinди же буйрук сабынын аргументтеринен файлды окуган консолдук программа төмөнкүдөй болот:

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 бир эле маселени чечүү, ал бир аз кыскараак көрүнгөнү менен, окуу оңой эмес

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

Көчүрүү тозок

Тозокту адам өз ичинде алып жүрөт. Мартин Лютер.

Жаңы баштагандар генериктердин жоктугуна байланыштуу Go жөнүндө дайыма даттанышат. Бул маселени чечүү үчүн, алардын көбү түздөн-түз кодду көчүрүүнү колдонушат. Мисалы, бүтүн сандардын тизмесин жыйынтыктоо функциясы, мындай кесипкөйлөр бул функцияны ар бир маалымат түрү үчүн жөнөкөй көчүрүп чаптоодон башка жол менен ишке ашыруу мүмкүн эмес деп эсептешет.

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

Мындай конструкцияларды ишке ашыруу үчүн тилде жетиштүү каражат бар. Мисалы, жалпы программалоо жакшы болмок.

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

Жана биздин код мурункуга караганда бир аз узунураак болуп чыкса да, ал жалпыланган. Демек, бардык арифметикалык амалдарды ишке ашыруу бизге кыйын болбойт.

Көптөр D тилиндеги программа кыйла кыскараак көрүнөт деп айтышат жана алар туура болот.

import std.stdio;
import std.algorithm;

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

Бирок, ал кыскараак, бирок туура эмес, анткени D ишке ашыруу каталарды чечүү маселесин толугу менен четке кагат.

Чыныгы жашоодо логиканын татаалдыгы күчөгөн сайын ажырым тездик менен кыскарат. Стандарттык тил операторлорунун жардамы менен аткарылбай турган иш-аракетти аткаруу керек болгондо ажырым дагы тез жабылат.

Туруктуулугу, кеңейтилүүсү жана окулушу жагынан, менин оюмча, Go тили утат, бирок ал көп сөздү жоготкон.

Кээ бир учурларда жалпыланган программалоо бизге талашсыз пайдаларды берет. Бул сорттук пакетте айкын көрүнүп турат. Демек, каалаган тизмени иреттөө үчүн, биз жөн гана sort.Interface интерфейсин ишке ашыруубуз керек.

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

Эгерде сиз кандайдыр бир ачык булактуу долбоорду алып, grep “interface{}” -R буйругун иштетсеңиз, анда башаламан интерфейстер канчалык көп колдонулганын көрөсүз. Ушунун бардыгы генериктердин жетишсиздигинен деп жакын санаалаш жолдоштор дароо айтышат. Бирок, бул дайыма эле боло бербейт. Мисал катары DELPHIди алалы. Ушул эле генериктердин бар экендигине карабастан, ал ыктыярдуу маалымат түрлөрү менен операциялар үчүн атайын VARIANT түрүн камтыйт. Go тили да ушундай кылат.

Замбиректен таранчыларга чейин

Ал эми куртка жиндиликтин өлчөмүнө туура келиши керек. Станислав Лек.

Көптөгөн экстремалдык күйөрмандар Go генериктерин түзүү үчүн дагы бир механизми бар деп ырасташы мүмкүн - чагылдыруу. Жана алар туура болот... бирок сейрек учурларда гана.

Роб Пайк бизге эскертет:

Бул этияттык менен колдонулушу керек күчтүү курал болуп саналат. Катуу зарылчылык болбосо, андан качуу керек.

Wikipedia бизге төмөнкүлөрдү айтат:

Рефлексия программа аткаруу учурунда өзүнүн структурасын жана жүрүм-турумун көзөмөлдөй жана өзгөртө ала турган процессти билдирет. Рефлексияга негизделген программалоо парадигмасы чагылдыруучу программалоо деп аталат. Бул метапрограммалоонун бир түрү.

Бирок, өзүңөр билгендей, бардыгы үчүн төлөшүңөр керек. Бул учурда бул:

  • программаларды жазууда кыйынчылык
  • программаны аткаруу ылдамдыгы

Ошондуктан, ой жүгүртүү чоң калибрлүү курал сыяктуу этияттык менен колдонулушу керек. Рефлексияны ойлонбой колдонуу окулбаган программаларга, тынымсыз каталарга жана ылдамдыктын төмөн болушуна алып келет. Башка, прагматикалык жана жупуну кесиптештеринин алдында өз кодун көрсөтө алышы үчүн сноб программист үчүн гана нерсе.

Сиден маданий жүк? Жок, бир катар тилдерден!

Байлык менен катар мураскорлорго карыздар да калат.

Көптөр тил толугу менен С мурасына негизделген деп эсептешкенине карабастан, бул андай эмес. Бул тил мыкты программалоо тилдеринин көптөгөн аспектилерин камтыйт.

синтаксиси

Биринчиден, грамматикалык түзүлүштөрдүн синтаксиси Си тилинин синтаксисинин негизинде түзүлөт. Бирок, DELPHI тили да олуттуу таасир эткен. Ошентип, программанын окулушун бир топ төмөндөтүүчү ашыкча кашаалар толугу менен алынып салынганын көрөбүз. Бул тилде DELPHI тилине мүнөздүү “:=” оператору да бар. Пакет түшүнүгү ADA сыяктуу тилдерден алынган. Пайдаланылбаган объекттердин декларациясы PROLOG тилинен алынган.

Семантикалык

Пакеттер DELPHI тилинин семантикасына негизделген. Ар бир топтом маалыматтарды жана кодду камтыйт жана жеке жана коомдук жактарды камтыйт. Бул пакеттин интерфейсин минимумга чейин кыскартууга мүмкүндүк берет.

Делегация ыкмасы менен ишке ашыруу операциясы DELPHI тилинен алынган.

Compilation

Бул тамаша бекеринен эмес: Go C программасы түзүлүп жатканда иштелип чыккан. Тилдин күчтүү жактарынын бири – анын өтө тез түзүлүшү. Идея DELPHI тилинен алынган. Ар бир Go топтому DELPHI модулуна туура келет. Бул пакеттер чындап зарыл болгондо гана кайра түзүлөт. Ошондуктан, кийинки түзөтүүдөн кийин, сиз бүтүндөй программаны компиляциялоонун кереги жок, тескерисинче, өзгөртүлгөн пакеттерди жана ушул өзгөргөн пакеттерге көз каранды болгон пакеттерди гана кайра компиляциялооңуз керек (жана ошондо да, пакеттин интерфейстери өзгөргөн учурда гана).

Жогорку деңгээлдеги курулуштар

Бул тил C сыяктуу төмөнкү деңгээлдеги тилдерге эч кандай тиешеси жок көптөгөн ар кандай жогорку деңгээлдеги конструкцияларды камтыйт.

  • Саптар
  • Хеш таблицалары
  • Кесектер
  • Өрдөк менен терүү RUBY сыяктуу тилдерден алынган (тилекке каршы, көптөр түшүнбөйт же толук мүмкүнчүлүктөрүн колдонушпайт).

Эстутум башкаруу

Эстутум башкаруу жалпысынан өзүнчө макалага татыктуу. Эгерде C++ сыяктуу тилдерде башкаруу толугу менен иштеп чыгуучуга тапшырылса, DELPHI сыяктуу кийинки тилдерде шилтеме эсептөө модели колдонулган. Бул ыкма менен циклдик шилтемелерге жол берилген эмес, анткени жетим кластерлер түзүлгөн, анда Go мындай кластерлерди аныктоону орноткон (C# сыяктуу). Кошумчалай кетсек, таштанды жыйноочу көпчүлүк учурда белгилүү болгон ишке караганда натыйжалуураак жана аны реалдуу убакыт режиминде көптөгөн тапшырмалар үчүн колдонсо болот. Тил өзү өзгөрмө сактоо үчүн маани стекте бөлүштүрүлүшү мүмкүн болгон кырдаалдарды тааныйт. Бул эстутум менеджериндеги жүктү азайтат жана программанын ылдамдыгын жогорулатат.

Кошумчалык жана параллелдүүлүк

Тилдин параллелдүүлүгү жана атаандаштыгы мактоого арзырлык эмес. Эч бир төмөнкү деңгээлдеги тил Go менен алыстан атаандаша албайт. Калыстык үчүн айта кетчү нерсе, бул модель тилдин авторлору тарабынан ойлоп табылган эмес, бирок жөн гана жакшы эски ADA тилинен алынган. Бул тил миллиондогон параллелдүү туташууларды бардык процессорлорду колдонуу менен иштетүүгө жөндөмдүү, ошол эле учурда көп жиптүү код үчүн мүнөздүү туюктуктар жана жарыш шарттары менен азыраак татаал көйгөйлөргө ээ.

Кошумча пайдалар

Пайдалуу болсо, ар бир адам жан аябас болуп калат.

Тил бизге бир катар шексиз артыкчылыктарды берет:

  • Долбоорду кургандан кийин бир аткарылуучу файл тиркемелерди жайылтууну абдан жөнөкөйлөтөт.
  • Статикалык терүү жана түрү боюнча жыйынтык жазуу тесттерсиз да, кодуңуздагы каталардын санын бир топ азайтышы мүмкүн. Мен кээ бир программисттерди билем, алар тесттерди такыр жазбай аткарышат жана алардын кодунун сапаты анчалык деле жабыркабайт.
  • Өтө жөнөкөй кайчылаш компиляция жана стандарттык китепкананын эң сонун портативдүүлүгү, бул кайчылаш платформа тиркемелерин иштеп чыгууну абдан жөнөкөйлөтөт.
  • RE2 регулярдуу туюнтмалар жип үчүн коопсуз жана алдын ала аткарылуучу убакыттарга ээ.
  • Көпчүлүк долбоорлорду үчүнчү тараптын алкактары жок кылууга мүмкүндүк берген күчтүү стандарттык китепкана.
  • Тил көйгөйдү кантип чечүүгө эмес, ага көңүл бурууга жетишерлик күчтүү, бирок көйгөйдү натыйжалуу чечүүгө боло турган деңгээли төмөн.
  • Go эко тутуму мурунтан эле бардык жагдайлар үчүн иштелип чыккан куралдарды камтыйт: тесттер, документтер, пакеттерди башкаруу, күчтүү линтерлер, коддорду түзүү, жарыш шарттарын аныктоочу ж.б.
  • Go версиясы 1.11 таанымал VCS хостингинин үстүнө курулган семантикалык көз карандылыкты башкарууну киргизди. Go экосистемасын түзгөн бардык куралдар бул кызматтардан кодду жүктөп алуу, куруу жана орнотуу үчүн колдонушат. Жана бул сонун. 1.11 версиясынын келиши менен пакетти версиялоо маселеси да толугу менен чечилди.
  • Тилдин негизги идеясы сыйкырды азайтуу болгондуктан, тил иштеп чыгуучуларды каталарды ачык чечүүгө шыктандырат. Жана бул туура, анткени антпесе, ал жөн гана ката менен иштөөнү унутуп калат. Дагы бир нерсе, көпчүлүк иштеп чыгуучулар катаны иштетүүнү атайылап этибарга албай, аларды иштетүүнүн ордуна катаны жөн гана жогору карай жылдырууну артык көрүшөт.
  • Тил классикалык OOP методологиясын ишке ашырбайт, анткени анын таза түрүндө Go-до виртуалдык жок. Бирок, интерфейстерди колдонууда бул көйгөй эмес. OOP жоктугу жаңыдан баштагандар үчүн кирүүдөгү тоскоолдукту бир кыйла азайтат.

Коомдук пайда үчүн жөнөкөйлүк

Татаалдаштыруу оңой, жөнөкөйлөтүү кыйын.

Go жөнөкөй болуу үчүн иштелип чыккан жана бул максатка жетет. Бул командалык иштин артыкчылыктарын түшүнгөн жана Enterprise деңгээлиндеги тилдердин чексиз өзгөрмөлүүлүгүнөн чарчаган акылдуу программисттер үчүн жазылган. Өзүнүн арсеналында синтаксистик структуралардын салыштырмалуу аз топтому бар, ал иш жүзүндө убакыттын өтүшү менен өзгөрүүгө дуушар болбойт, ошондуктан иштеп чыгуучулар тилдик инновацияларды чексиз изилдөө үчүн эмес, өнүгүү үчүн көп убакыт бошотушат.

Компаниялар бир катар артыкчылыктарга да ээ болушат: кирүүдөгү аз тоскоол адисти тез табууга мүмкүндүк берет, ал эми тилдин өзгөрбөстүгү 10 жылдан кийин да ошол эле кодду колдонууга мүмкүндүк берет.

жыйынтыктоо

Мээнин чоңдугу эч качан бир дагы пилди Нобель сыйлыгынын лауреаты кылган эмес.

Жеке эгосу командалык рухтан жогору турган программисттер, ошондой эле академиялык кыйынчылыктарды жана чексиз "өзүн-өзү өркүндөтүүнү" сүйгөн теоретиктер үчүн тил чындап эле начар, анткени бул жалпы максаттагы кол өнөрчүлүк тил, бул сизге мүмкүнчүлүк бербейт. ишиңиздин жыйынтыгынан эстетикалык ырахат алып, кесиптештериңиздин алдында өзүңүздү профессионал катары көрсөтүңүз (эгерде биз интеллектти IQ менен эмес, ушул критерийлер менен өлчөсөк). Жашоодогу бардык нерсе сыяктуу эле, бул жеке артыкчылыктардын маселеси. Бардык баалуу инновациялар сыяктуу эле, тил жалпы четке кагуудан массалык түрдө кабыл алууга чейин бир топ жолду басып өттү. Тил өзүнүн жөнөкөйлүгү менен гениалдуу, өзүңөр билгендей, гениалдуу нерсенин баары жөнөкөй!

Source: www.habr.com

Комментарий кошуу