Mengapa Go adalah Buruk untuk Pengaturcara Tidak Pintar

Artikel itu ditulis sebagai respons kepada yang diterbitkan sebelum ini artikel antipodean.

Mengapa Go adalah Buruk untuk Pengaturcara Tidak Pintar

Sepanjang dua tahun lebih yang lalu saya telah menggunakan Go untuk melaksanakan pelayan RADIUS khusus dengan sistem pengebilan yang dibangunkan. Sepanjang perjalanan, saya sedang mempelajari selok-belok bahasa itu sendiri. Program-program itu sendiri adalah sangat mudah dan bukan tujuan artikel ini, tetapi pengalaman menggunakan Go itu sendiri memerlukan beberapa perkataan untuk mempertahankannya. Go semakin menjadi bahasa arus perdana untuk kod yang serius dan boleh skala. Bahasa ini dicipta oleh Google, di mana ia digunakan secara aktif. Intinya, saya secara jujur ​​berpendapat bahawa reka bentuk bahasa Go adalah buruk untuk pengaturcara UNintelligent.

Direka untuk pengaturcara yang lemah?

Yang lemah bercakap tentang masalah. Perbincangan kuat tentang idea dan impian...

Go sangat mudah dipelajari, begitu mudah sehingga anda boleh membaca kod tanpa latihan langsung. Ciri bahasa ini digunakan dalam banyak syarikat global apabila kod dibaca bersama dengan pakar bukan teras (pengurus, pelanggan, dsb.). Ini sangat mudah untuk metodologi seperti Pembangunan Didorong Reka Bentuk.
Malah pengaturcara baru mula menghasilkan kod yang agak baik selepas satu atau dua minggu. Buku yang saya pelajari ialah "Go Programming" (oleh Mark Summerfield). Buku ini sangat bagus, ia menyentuh banyak nuansa bahasa. Selepas bahasa rumit yang tidak perlu seperti Java, PHP, kekurangan sihir menyegarkan. Tetapi lambat laun, ramai pengaturcara terhad mempunyai idea untuk menggunakan kaedah lama dalam bidang baru. Adakah ini benar-benar perlu?

Rob Pike (ahli ideologi utama bahasa) mencipta bahasa Go sebagai bahasa industri yang mudah difahami dan berkesan untuk digunakan. Bahasa ini direka untuk produktiviti maksimum dalam pasukan besar dan tidak ada keraguan mengenainya. Ramai pengaturcara baru mengadu bahawa terdapat banyak ciri yang mereka hilang. Keinginan untuk kesederhanaan ini adalah keputusan sedar oleh pereka bahasa, dan untuk memahami sepenuhnya mengapa ia diperlukan, kita mesti memahami motivasi pembangun dan apa yang mereka cuba capai dalam Go.

Jadi mengapa ia dibuat begitu mudah? Berikut adalah beberapa petikan daripada Rob Pike:

Perkara utama di sini ialah pengaturcara kami bukan penyelidik. Mereka, sebagai peraturan, agak muda, datang kepada kami selepas belajar, mungkin mereka belajar Java, atau C/C++, atau Python. Mereka tidak dapat memahami bahasa yang hebat, tetapi pada masa yang sama kami mahu mereka mencipta perisian yang baik. Itulah sebabnya bahasa itu harus mudah difahami dan dipelajari.

Dia sepatutnya biasa, secara kasarnya sama dengan C. Pengaturcara yang bekerja di Google memulakan kerjaya mereka lebih awal dan kebanyakannya biasa dengan bahasa prosedur, khususnya keluarga C. Keperluan untuk produktiviti cepat dalam bahasa pengaturcaraan baharu bermakna bahasa itu tidak boleh terlalu radikal.

Kata-kata bijak, bukan?

Artifak Kesederhanaan

Kesederhanaan adalah syarat yang diperlukan untuk kecantikan. Lev Tolstoy.

Menjaganya dengan mudah adalah salah satu matlamat terpenting dalam mana-mana reka bentuk. Seperti yang anda ketahui, projek yang sempurna bukanlah projek yang tiada apa-apa untuk ditambah, tetapi projek yang tiada apa-apa untuk dialih keluar. Ramai orang percaya bahawa untuk menyelesaikan (atau menyatakan) masalah yang kompleks, alat yang kompleks diperlukan. Walau bagaimanapun, ia tidak. Mari kita ambil bahasa PERL sebagai contoh. Ahli ideologi bahasa percaya bahawa seorang pengaturcara harus mempunyai sekurang-kurangnya tiga cara berbeza untuk menyelesaikan satu masalah. Ahli ideologi bahasa Go mengambil jalan yang berbeza; mereka memutuskan bahawa satu cara, tetapi yang benar-benar bagus, sudah cukup untuk mencapai matlamat. Pendekatan ini mempunyai asas yang serius: satu-satunya cara adalah lebih mudah dipelajari dan lebih sukar untuk dilupakan.

Ramai pendatang mengadu bahawa bahasa itu tidak mengandungi abstraksi yang elegan. Ya, ini benar, tetapi ini adalah salah satu kelebihan utama bahasa. Bahasa ini mengandungi sekurang-kurangnya sihir - jadi tiada pengetahuan mendalam diperlukan untuk membaca program ini. Bagi verbositi kod, ini tidak menjadi masalah sama sekali. Program Golang yang ditulis dengan baik dibaca secara menegak, dengan sedikit atau tiada struktur. Di samping itu, kelajuan membaca program adalah sekurang-kurangnya urutan magnitud yang lebih besar daripada kelajuan menulisnya. Jika anda menganggap bahawa semua kod mempunyai pemformatan seragam (dilakukan menggunakan arahan gofmt terbina dalam), maka membaca beberapa baris tambahan tidak menjadi masalah sama sekali.

Tidak terlalu ekspresif

Seni tidak bertolak ansur apabila kebebasannya dikekang. Ketepatan bukan tanggungjawabnya.

Oleh kerana keinginan untuk kesederhanaan, Go tidak mempunyai binaan yang dalam bahasa lain dianggap sebagai sesuatu yang semula jadi oleh orang yang terbiasa dengannya. Pada mulanya ia mungkin agak menyusahkan, tetapi kemudian anda dapati bahawa program ini lebih mudah dan lebih jelas untuk dibaca.

Sebagai contoh, utiliti konsol yang membaca stdin atau fail daripada argumen baris arahan akan kelihatan seperti ini:

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

Penyelesaian kepada masalah yang sama dalam D, walaupun ia kelihatan agak pendek, tidak mudah dibaca

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

Jahanam meniru

Manusia membawa neraka dalam dirinya. Martin Luther.

Pemula sentiasa mengadu tentang Go dari segi kekurangan generik. Untuk menyelesaikan isu ini, kebanyakan mereka menggunakan penyalinan kod langsung. Sebagai contoh, fungsi untuk menjumlahkan senarai integer, bakal profesional seperti itu percaya bahawa kefungsian itu tidak boleh dilaksanakan dengan cara lain selain dengan menampal salinan mudah untuk setiap jenis data.

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

Bahasa mempunyai cara yang mencukupi untuk melaksanakan pembinaan tersebut. Sebagai contoh, pengaturcaraan generik adalah baik.

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

Dan, walaupun kod kami ternyata agak panjang daripada kes sebelumnya, ia telah menjadi umum. Oleh itu, tidak sukar bagi kita untuk melaksanakan semua operasi aritmetik.

Ramai yang akan mengatakan bahawa program dalam D kelihatan jauh lebih pendek, dan ia akan betul.

import std.stdio;
import std.algorithm;

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

Walau bagaimanapun, ia hanya lebih pendek, tetapi tidak lebih betul, kerana pelaksanaan D sepenuhnya mengabaikan masalah pengendalian ralat.

Dalam kehidupan sebenar, apabila kerumitan logik meningkat, jurang itu mengecil dengan cepat. Jurang ditutup dengan lebih pantas apabila anda perlu melakukan tindakan yang tidak boleh dilakukan menggunakan operator bahasa standard.

Dari segi kebolehselenggaraan, kebolehlanjutan dan kebolehbacaan, pada pendapat saya, bahasa Go menang, walaupun ia kalah dalam verbosity.

Pengaturcaraan umum dalam beberapa kes memberi kita faedah yang tidak dapat dinafikan. Ini jelas digambarkan oleh pakej isihan. Jadi, untuk mengisih mana-mana senarai, kita hanya perlu melaksanakan sort.Antara muka antara muka.

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

Jika anda mengambil sebarang projek sumber terbuka dan menjalankan perintah "antara muka{}" -R grep, anda akan melihat kekerapan antara muka yang mengelirukan digunakan. Rakan seperjuangan yang rapat akan segera mengatakan bahawa semua ini adalah kerana kekurangan generik. Walau bagaimanapun, ini tidak selalu berlaku. Mari kita ambil DELPHI sebagai contoh. Walaupun terdapat generik yang sama ini, ia mengandungi jenis VARIANT khas untuk operasi dengan jenis data arbitrari. Bahasa Go melakukan perkara yang sama.

Dari meriam kepada burung pipit

Dan straitjacket mesti sesuai dengan saiz kegilaan. Stanislav Lec.

Ramai peminat ekstrem mungkin mendakwa bahawa Go mempunyai mekanisme lain untuk mencipta generik - refleksi. Dan mereka akan betul... tetapi hanya dalam kes yang jarang berlaku.

Rob Pike memberi amaran kepada kami:

Ini adalah alat yang berkuasa yang harus digunakan dengan berhati-hati. Ia harus dielakkan melainkan sangat diperlukan.

Wikipedia memberitahu kita perkara berikut:

Refleksi merujuk kepada proses di mana program boleh memantau dan mengubah suai struktur dan tingkah lakunya sendiri semasa pelaksanaan. Paradigma pengaturcaraan yang mendasari refleksi dipanggil pengaturcaraan reflektif. Ini adalah sejenis pengaturcaraan meta.

Walau bagaimanapun, seperti yang anda tahu, anda perlu membayar untuk segala-galanya. Dalam kes ini ialah:

  • kesukaran menulis program
  • kelajuan pelaksanaan program

Oleh itu, refleksi mesti digunakan dengan berhati-hati, seperti senjata berkaliber besar. Penggunaan pantulan tanpa berfikir membawa kepada atur cara yang tidak boleh dibaca, ralat berterusan dan kelajuan rendah. Hanya satu perkara bagi seorang pengaturcara yang sombong untuk dapat mempamerkan kodnya di hadapan rakan sekerja lain yang lebih pragmatik dan sederhana.

Bagasi budaya dari Xi? Tidak, daripada beberapa bahasa!

Seiring dengan nasib, hutang juga ditinggalkan kepada waris.

Walaupun fakta bahawa ramai yang percaya bahawa bahasa itu sepenuhnya berdasarkan warisan C, ini tidak berlaku. Bahasa ini menggabungkan banyak aspek bahasa pengaturcaraan terbaik.

sintaks

Pertama sekali, sintaks struktur tatabahasa adalah berdasarkan sintaks bahasa C. Walau bagaimanapun, bahasa DELPHI juga mempunyai pengaruh yang ketara. Oleh itu, kami melihat bahawa kurungan berlebihan, yang sangat mengurangkan kebolehbacaan program, telah dialih keluar sepenuhnya. Bahasa ini juga mengandungi operator ":=" yang wujud dalam bahasa DELPHI. Konsep pakej dipinjam daripada bahasa seperti ADA. Pengisytiharan entiti yang tidak digunakan dipinjam daripada bahasa PROLOG.

Semantik

Pakej adalah berdasarkan semantik bahasa DELPHI. Setiap pakej merangkumi data dan kod serta mengandungi entiti persendirian dan awam. Ini membolehkan anda mengurangkan antara muka pakej kepada minimum.

Operasi pelaksanaan melalui kaedah delegasi dipinjam daripada bahasa DELPHI.

Penyusunan

Ia bukan tanpa sebab bahawa terdapat jenaka: Go telah dibangunkan semasa program C sedang disusun. Salah satu kekuatan bahasa itu ialah kompilasinya yang sangat pantas. Idea ini dipinjam daripada bahasa DELPHI. Setiap pakej Go sepadan dengan modul DELPHI. Pakej ini disusun semula hanya apabila benar-benar perlu. Oleh itu, selepas suntingan seterusnya, anda tidak perlu menyusun keseluruhan program, tetapi menyusun semula hanya pakej dan pakej yang diubah yang bergantung pada pakej yang diubah ini (dan itupun, hanya jika antara muka pakej telah berubah).

Konstruk peringkat tinggi

Bahasa ini mengandungi banyak binaan peringkat tinggi yang berbeza yang sama sekali tidak berkaitan dengan bahasa peringkat rendah seperti C.

  • rentetan
  • Hash jadual
  • hirisan
  • Penaipan itik dipinjam daripada bahasa seperti RUBY (yang, malangnya, ramai yang tidak memahami atau menggunakannya sepenuhnya).

Pengurusan ingatan

Pengurusan memori secara amnya memerlukan artikel yang berasingan. Jika dalam bahasa seperti C++, kawalan diserahkan sepenuhnya kepada pembangun, maka dalam bahasa kemudian seperti DELPHI, model pengiraan rujukan telah digunakan. Dengan pendekatan ini, rujukan kitaran tidak dibenarkan, kerana gugusan anak yatim telah dibentuk, maka Go mempunyai pengesanan terbina dalam bagi gugusan tersebut (seperti C#). Di samping itu, pemungut sampah adalah lebih cekap daripada kebanyakan pelaksanaan yang diketahui pada masa ini dan sudah boleh digunakan untuk banyak tugas masa nyata. Bahasa itu sendiri mengenali situasi apabila nilai untuk menyimpan pembolehubah boleh diperuntukkan pada timbunan. Ini mengurangkan beban pada pengurus memori dan meningkatkan kelajuan program.

Concurrency dan Concurrency

Keselarian dan daya saing bahasa tidak dapat dipuji. Tiada bahasa peringkat rendah yang boleh bersaing dengan Go dari jauh. Untuk bersikap adil, perlu diperhatikan bahawa model itu tidak dicipta oleh pengarang bahasa, tetapi hanya dipinjam daripada bahasa ADA lama yang baik. Bahasa ini mampu memproses berjuta-juta sambungan selari menggunakan semua CPU, sambil mempunyai susunan magnitud masalah yang kurang kompleks dengan kebuntuan dan keadaan perlumbaan yang tipikal untuk kod berbilang benang.

Faedah tambahan

Jika ia menguntungkan, semua orang akan menjadi tidak mementingkan diri sendiri.

Bahasa juga memberi kita beberapa faedah yang tidak diragui:

  • Satu fail boleh laku selepas membina projek sangat memudahkan penggunaan aplikasi.
  • Penaipan statik dan inferens jenis boleh mengurangkan bilangan ralat dalam kod anda dengan ketara, walaupun tanpa ujian bertulis. Saya tahu beberapa pengaturcara yang melakukan tanpa menulis ujian sama sekali dan kualiti kod mereka tidak terjejas dengan ketara.
  • Penyusunan silang yang sangat mudah dan mudah alih yang sangat baik bagi perpustakaan standard, yang sangat memudahkan pembangunan aplikasi merentas platform.
  • Ungkapan biasa RE2 selamat untuk benang dan mempunyai masa pelaksanaan yang boleh diramal.
  • Pustaka standard yang berkuasa yang membolehkan kebanyakan projek dilakukan tanpa rangka kerja pihak ketiga.
  • Bahasa ini cukup kuat untuk menumpukan perhatian kepada masalah dan bukannya cara menyelesaikannya, namun cukup tahap rendah sehingga masalah itu dapat diselesaikan dengan cekap.
  • Sistem eko ​​Go sudah mengandungi alatan yang dibangunkan di luar kotak untuk semua keadaan: ujian, dokumentasi, pengurusan pakej, linter berkuasa, penjanaan kod, pengesan keadaan perlumbaan, dsb.
  • Go versi 1.11 memperkenalkan pengurusan pergantungan semantik terbina dalam, dibina di atas pengehosan VCS yang popular. Semua alatan yang membentuk ekosistem Go menggunakan perkhidmatan ini untuk memuat turun, membina dan memasang kod daripadanya dalam satu masa. Dan itu bagus. Dengan ketibaan versi 1.11, masalah dengan versi pakej juga telah diselesaikan sepenuhnya.
  • Kerana idea teras bahasa adalah untuk mengurangkan sihir, bahasa itu memberi insentif kepada pembangun untuk melakukan pengendalian ralat secara eksplisit. Dan ini betul, kerana jika tidak, ia hanya akan melupakan pengendalian ralat sama sekali. Perkara lain ialah kebanyakan pembangun sengaja mengabaikan pengendalian ralat, lebih suka daripada memprosesnya untuk hanya memajukan ralat ke atas.
  • Bahasa ini tidak melaksanakan metodologi OOP klasik, kerana dalam bentuk tulennya tiada maya dalam Go. Walau bagaimanapun, ini tidak menjadi masalah apabila menggunakan antara muka. Ketiadaan OOP dengan ketara mengurangkan halangan kepada kemasukan untuk pemula.

Kesederhanaan untuk faedah masyarakat

Ia mudah untuk merumitkan, sukar untuk dipermudahkan.

Go direka untuk menjadi mudah dan ia berjaya mencapai matlamat itu. Ia ditulis untuk pengaturcara pintar yang memahami faedah kerja berpasukan dan bosan dengan kebolehubahan yang tidak berkesudahan bahasa peringkat Perusahaan. Mempunyai set struktur sintaksis yang agak kecil dalam senjatanya, ia boleh dikatakan tidak tertakluk kepada perubahan dari semasa ke semasa, jadi pembangun mempunyai banyak masa yang dibebaskan untuk pembangunan, dan bukan untuk mengkaji inovasi bahasa tanpa henti.

Syarikat juga menerima beberapa kelebihan: halangan kemasukan yang rendah membolehkan mereka mencari pakar dengan cepat, dan kebolehubahan bahasa membolehkan mereka menggunakan kod yang sama walaupun selepas 10 tahun.

Kesimpulan

Saiz otak yang besar tidak pernah menjadikan mana-mana gajah sebagai pemenang Hadiah Nobel.

Bagi pengaturcara yang ego peribadinya lebih diutamakan daripada semangat berpasukan, serta ahli teori yang menyukai cabaran akademik dan "pembaikan diri" yang tidak berkesudahan, bahasa itu benar-benar buruk, kerana ia adalah bahasa artisan tujuan umum yang tidak membenarkan anda untuk mendapatkan keseronokan estetik daripada hasil kerja anda dan tunjukkan diri anda profesional di hadapan rakan sekerja (dengan syarat kita mengukur kecerdasan dengan kriteria ini, dan bukan dengan IQ). Seperti segala-galanya dalam hidup, ia adalah soal keutamaan peribadi. Seperti semua inovasi yang berfaedah, bahasa itu sudah jauh dari penafian sejagat kepada penerimaan besar-besaran. Bahasa ini bijak dalam kesederhanaannya, dan, seperti yang anda tahu, segala-galanya yang bijak adalah mudah!

Sumber: www.habr.com

Tambah komen