Zen pergi



Mengevaluasi pekerjaan saya, saya baru-baru ini banyak berpikir tentang cara menulis kode yang baik. Karena tidak ada yang tertarik dengan cara menulis kode yang buruk , muncul pertanyaan: bagaimana Anda tahu jika Anda menulis kode yang baik di Go ? Jika ada semacam skala antara yang baik dan yang buruk, lalu bagaimana cara memahami bagian skala mana yang menjadi milik yang baik? Apa sifat, atribut, fitur yang membedakan, pola, dan idiomnya?

Go secara idiomatis


Pertimbangan ini membawa saya ke Go idiomatik. Jika kita menyebut sesuatu "idiomatik", maka ini sesuatu sesuai dengan gaya tertentu pada suatu waktu. Jika sesuatu tidak idiomatis, maka itu tidak sesuai dengan gaya dominan. Itu tidak modis.

Lebih penting lagi, ketika kami mengatakan bahwa kode seseorang tidak idiomatis, ini tidak menjelaskan alasannya. Kenapa tidak idiomatis? Jawabannya diberikan oleh kamus.

Idiom (n.): Revolusi ucapan, digunakan secara keseluruhan, tidak tunduk pada dekomposisi lebih lanjut dan biasanya tidak mengizinkan permutasi di dalam dirinya sendiri.

Idiom adalah ciri khas dari makna yang sama. Buku tidak akan mengajarkan Anda Go idiomatis, tetapi hanya diketahui saat Anda menjadi bagian dari komunitas.

Saya prihatin dengan mantra Go idiomatis karena sering membatasi. Dia berkata: "kamu tidak bisa duduk bersama kami." Bukankah itu yang kita maksudkan ketika kita mengkritik karya orang lain sebagai "tidak idiomatik"? Mereka salah melakukannya. Ini tidak beres. Ini tidak sesuai dengan gaya waktu itu.

Saya percaya bahwa Go idiomatik tidak cocok untuk mengajarkan cara menulis kode yang baik, karena, pada dasarnya, ini berarti memberi tahu orang-orang bahwa mereka melakukan sesuatu yang salah. Lebih baik memberikan nasihat seperti itu yang tidak akan mendorong seseorang menjauh saat dia paling ingin menerima nasihat ini.

Ucapan


Mari kita mengalihkan perhatian dari masalah idiomatik. Apa artefak budaya lain yang melekat pada programmer Go? Beralih ke halaman Go Amsal yang indah . Apakah perkataan ini merupakan alat pembelajaran yang cocok? Apakah mereka memberi tahu pemula cara menulis kode Go yang baik?

Saya kira tidak. Saya tidak ingin meremehkan karya penulis. Perkataan yang ia susun hanyalah pengamatan, bukan definisi makna. Kamus datang untuk menyelamatkan lagi:

Amsal (n.): Pernyataan singkat yang memiliki arti literal atau kiasan.

Misi Go Amsal adalah menunjukkan esensi yang dalam dari arsitektur bahasa. Tetapi apakah akan berguna untuk saran seperti " Antarmuka kosong tidak mengatakan apa-apa " kepada pemula yang berasal dari bahasa tanpa pengetikan struktural?

Dalam komunitas yang berkembang, penting untuk mengenali bahwa jumlah siswa Go jauh lebih besar daripada jumlah mereka yang fasih dalam bahasa ini. Artinya, perkataan mungkin bukan cara terbaik untuk belajar dalam situasi seperti itu.

Nilai Desain


Dan Liu menemukan presentasi lama oleh Mark Lukowski mengenai budaya desain di tim pengembangan Windows Windows NT-Windows 2000. Saya menyebutkan ini karena Lukowski menggambarkan budaya sebagai cara umum mengevaluasi arsitektur dan membuat kompromi.


Gagasan utamanya adalah membuat keputusan berbasis nilai dalam arsitektur yang tidak dikenal . Tim NT memiliki nilai-nilai ini: portabilitas, keandalan, keamanan, dan ekstensibilitas. Sederhananya, nilai-nilai desain adalah cara untuk memecahkan masalah.

Go Values


Apa nilai eksplisit Go? Apa konsep atau filosofi kunci yang menentukan bagaimana programmer Go menafsirkan dunia? Bagaimana mereka diberitakan? Bagaimana cara mereka mengajar? Bagaimana mereka diikuti? Bagaimana mereka berubah seiring waktu?

Bagaimana Anda mengonversi seorang programmer Go mendapatkan nilai-nilai desain Go? Atau bagaimana Anda, seorang Go-pro yang berpengalaman, menyatakan nilai-nilai Anda kepada generasi mendatang? Dan agar Anda mengerti, proses transfer pengetahuan ini tidak opsional? Tanpa masuknya peserta baru dan ide-ide baru, komunitas kami menjadi rabun dan layu.

Nilai bahasa lain


Untuk mempersiapkan cara apa yang ingin saya katakan, kita bisa memperhatikan bahasa lain, dengan nilai desainnya.

Misalnya, dalam C ++ dan Rust diyakini bahwa seorang programmer tidak harus membayar untuk fitur yang tidak ia gunakan . Jika program tidak menggunakan fitur intensif sumber daya bahasa, maka program tidak dapat dipaksa untuk menanggung biaya pemeliharaan fitur ini. Nilai ini diproyeksikan dari bahasa ke pustaka standar dan digunakan sebagai kriteria untuk mengevaluasi arsitektur semua program yang ditulis dalam C ++.

Nilai utama di Java, Ruby dan Smalltalk - semuanya adalah objek. Prinsip ini mendasari desain program dalam hal transfer pesan, penyembunyian informasi, dan polimorfisme. Arsitektur yang sesuai dengan paradigma prosedural atau fungsional dianggap salah dalam bahasa-bahasa ini. Atau, seperti kata programmer Go, bukan idiomatis.

Mari kita kembali ke komunitas kita. Nilai desain apa yang diakui oleh programmer Go? Diskusi tentang topik ini sering terpecah-pecah, sehingga tidak mudah untuk merumuskan serangkaian makna. Sangat penting untuk mencapai kesepakatan, tetapi kesulitan untuk mencapainya tumbuh secara eksponensial dengan meningkatnya jumlah peserta dalam diskusi. Tetapi bagaimana jika seseorang melakukan pekerjaan yang sulit bagi kita?

Zen Python Go


Beberapa dekade yang lalu, Tim Peters duduk dan menulis PEP-20 - The Zen of Python . Dia mencoba mendokumentasikan nilai-nilai desain yang dipatuhi Guido Van Rossum sebagai Generic Lifetime Python Dictator.

Mari kita lihat The Zen of Python dan lihat apakah kita dapat mempelajari apa pun tentang nilai-nilai desain Go designer.

Paket yang baik dimulai dengan nama yang bagus


Mari kita mulai dengan yang tajam:

Ruang nama adalah ide bagus, mari kita buat mereka lebih besar!

The Zen of Python, catatan 19.

Cukup jelas: programmer Python harus menggunakan ruang nama. Banyak ruang.

Dalam terminologi Go, namespace adalah sebuah paket. Tidak ada keraguan bahwa bundling mendukung desain dan penggunaan kembali. Tetapi mungkin ada kebingungan tentang bagaimana melakukan ini, terutama jika Anda memiliki pengalaman pemrograman bertahun-tahun dalam bahasa lain.

Di Go, setiap paket harus dirancang untuk sesuatu. Dan namanya adalah cara terbaik untuk memahami tujuan ini. Merumuskan kembali pemikiran Peter, setiap paket di Go harus dirancang untuk satu hal.

Idenya bukan hal baru, saya sudah membicarakan hal ini . Tetapi mengapa pendekatan ini harus digunakan, dan bukan yang lain, di mana paket digunakan untuk kebutuhan klasifikasi rinci? Ini semua tentang perubahan.

— , .


Change adalah nama game tempat kami berpartisipasi. Kami, sebagai programmer, mengelola perubahan. Jika kita melakukannya dengan baik, kita menyebutnya arsitektur. Dan jika itu buruk, maka kami menyebutnya utang teknis atau kode warisan.

Jika Anda menulis sebuah program yang berfungsi sekali dengan satu set data input yang tetap, maka tidak seorang pun akan tertarik pada apakah ia memiliki kode yang baik, karena hanya hasil kerjanya yang penting untuk bisnis.

Tetapi ini tidak terjadi . Ada bug dalam program, persyaratan dan perubahan input data, dan sangat sedikit program ditulis dengan harapan eksekusi tunggal. Artinya, program Anda akan berubah seiring waktu. Mungkin tugas ini akan diberikan kepada Anda, tetapi kemungkinan besar orang lain akan melakukannya. Seseorang harus menyertai kode ini.

Bagaimana kita membuatnya lebih mudah untuk mengubah program? Tambahkan antarmuka di mana-mana? Apakah semuanya cocok untuk membuat bertopik? Menyebarkan dependensi dengan ketat? Mungkin, untuk beberapa jenis program, teknik ini cocok, tetapi tidak untuk banyak orang. Namun, untuk sebagian besar program, menciptakan arsitektur yang fleksibel lebih dari sekadar desain.

Dan jika bukannya memperluas komponen kami akan menggantinya? Jika komponen tidak melakukan apa yang ditentukan dalam instruksi, maka sekarang saatnya untuk mengubahnya.

Paket yang baik dimulai dengan memilih nama yang bagus. Anggap saja presentasi singkat yang menggambarkan fungsi suatu paket hanya dengan satu kata. Dan ketika nama tidak lagi memenuhi persyaratan, cari penggantinya.

Kesederhanaan penting


Sederhana lebih baik daripada kompleks.

Zen Python, entri 3.

PEP-20 mengklaim bahwa yang sederhana lebih baik daripada yang kompleks, dan saya sepenuhnya setuju. Beberapa tahun yang lalu saya menulis:


Sebagian besar bahasa pemrograman mencoba menjadi sederhana pada awalnya, tetapi kemudian memutuskan untuk menjadi kuat.

Menurut pengamatan saya, setidaknya pada saat itu, saya tidak dapat mengingat bahasa yang saya tahu tidak akan dianggap sederhana. Sebagai pembenaran dan godaan, penulis setiap bahasa baru menyatakan kesederhanaan. Tetapi saya menemukan bahwa kesederhanaan bukanlah nilai inti dari banyak bahasa pada usia yang sama dengan Go (Ruby, Swift, Elm, Go, NodeJS, Python, Rust). Mungkin ini akan sangat menyakitkan, tetapi mungkin alasannya adalah bahwa tidak satu pun dari bahasa ini sederhana. Atau penulis mereka tidak menganggapnya sederhana. Kesederhanaan tidak dimasukkan dalam daftar nilai inti.

Anda bisa menganggap saya kuno, tetapi kapan kesederhanaan ini tidak lagi populer? Mengapa industri perangkat lunak komersial terus-menerus dan dengan gembira melupakan kebenaran mendasar ini?

Ada dua cara untuk membuat arsitektur perangkat lunak: untuk membuatnya sangat sederhana sehingga kekurangannya jelas, dan untuk membuatnya sangat kompleks sehingga tidak memiliki kekurangan yang jelas. Metode pertama jauh lebih sulit.

Charles Hoar, Pakaian Tua Kaisar, Turing Award Lecture, 1980

Sederhana bukan berarti mudah, kita tahu itu. Seringkali dibutuhkan lebih banyak upaya untuk memastikan kemudahan penggunaan, bukan kemudahan penciptaan.

Kesederhanaan adalah kunci keandalan.

Edsger Dijkstra, EWD498, 18 Juni 1975

Mengapa berjuang untuk kesederhanaan? Mengapa penting agar program Go sederhana? Sederhana berarti mentah, artinya mudah dibaca dan mudah diikuti. Sederhana tidak berarti tanpa seni, itu berarti dapat diandalkan, dapat dipahami dan dimengerti.

Inti dari pemrograman adalah manajemen kompleksitas.

Brian Kernigan, Perangkat Lunak Alat (1976)

Apakah Python mengikuti mantra kesederhanaannya adalah pertanyaan yang bisa diperdebatkan. At Go, bagaimanapun, kesederhanaan adalah nilai inti. Saya pikir kita semua akan setuju bahwa dalam Go kode sederhana lebih baik daripada kode pintar.

Hindari status tingkat paket


Eksplisit lebih baik daripada implisit.

Zen Python, entri 2

Di sini, Peters, menurut pendapat saya, bukan mimpi daripada menganut fakta. Dalam Python, banyak yang tidak eksplisit: dekorator, metode dunder, dll. Tidak diragukan lagi, ini adalah alat yang kuat, dan mereka ada karena suatu alasan. Pada implementasi setiap fitur, terutama yang kompleks, seseorang bekerja. Tetapi penggunaan fitur-fitur tersebut secara aktif membuat sulit untuk mengevaluasi biaya operasi ketika membaca kode.

Untungnya, programmer Go kita secara opsional dapat membuat kode eksplisit. Mungkin, bagi Anda, manifestasi mungkin identik dengan birokrasi dan verbositas, tetapi ini adalah interpretasi yang dangkal. Ini akan menjadi kesalahan untuk fokus hanya pada sintaksis, untuk menjaga panjang garis dan penerapan prinsip KERING untuk ekspresi. Bagiku lebih penting untuk memberikan kesaksian dalam hal keterhubungan dan negara.

Konektivitas adalah ukuran dari ketergantungan satu sama lain. Jika satu terkait erat dengan yang lain, maka keduanya bergerak bersama. Suatu tindakan yang mempengaruhi satu secara langsung tercermin dalam yang lain. Bayangkan sebuah kereta di mana semua mobil terhubung - atau lebih tepatnya, terhubung - bersama. Di mana kereta uap pergi, ada mobil.

Konektivitas juga dapat digambarkan dengan istilah kohesi - kohesi. Ini adalah ukuran berapa banyak yang satu milik yang lain. Dalam tim yang disolder, semua peserta sangat cocok satu sama lain, seolah-olah mereka diciptakan secara khusus.

Mengapa koherensi penting? Seperti halnya kereta, ketika Anda perlu mengubah sepotong kode, Anda harus mengubah sisa kode yang terkait erat. Misalnya, seseorang telah merilis versi baru API mereka, dan sekarang kode Anda tidak dapat dikompilasi.

API adalah sumber pengikatan yang tidak dapat dihindari. Tapi itu bisa disajikan dalam bentuk yang lebih berbahaya. Semua orang tahu bahwa jika tanda tangan API telah berubah, maka data yang ditransfer ke dan dari API juga akan berubah. Ini semua tentang tanda tangan fungsi: Saya mengambil nilai dari satu jenis dan mengembalikan nilai dari jenis lainnya. Dan jika API mulai mentransfer data dengan cara yang berbeda? Bagaimana jika hasil dari setiap panggilan API tergantung pada panggilan sebelumnya, bahkan jika Anda tidak mengubah pengaturan Anda?

Ini disebut negara, dan manajemen negara adalah masalah dalam ilmu komputer.

package counter

var count int

func Increment(n int) int {
        count += n
        return count
}

Di sini kami memiliki paket sederhana counter. Untuk mengubah penghitung, Anda dapat menelepon Increment, Anda bahkan bisa mendapatkan kembali nilainya jika Anda menambah nilai nol.

Katakanlah Anda perlu menguji kode ini. Bagaimana cara mereset penghitung setelah setiap tes? Dan jika Anda ingin menjalankan tes secara paralel, bagaimana ini bisa dilakukan? Dan seandainya Anda ingin menggunakan beberapa penghitung dalam program ini, apakah Anda akan berhasil?

Tentu saja tidak. Jelas, solusinya adalah merangkum variabel variabledalam tipe.

package counter

type Counter struct {
        count int
}

func (c *Counter) Increment(n int) int {
        c.count += n
        return c.count
}

Sekarang bayangkan bahwa masalah yang dijelaskan tidak terbatas pada penghitung, tetapi juga mempengaruhi logika bisnis utama aplikasi Anda. Bisakah Anda mengujinya secara terpisah? Bisakah Anda menguji secara paralel? Bisakah Anda menggunakan banyak contoh sekaligus? Jika jawabannya tidak untuk semua pertanyaan, maka alasannya adalah keadaan di tingkat paket.

Hindari kondisi ini. Kurangi konektivitas dan jumlah aksi jarak jauh mimpi buruk dengan menyediakan jenis dependensi yang mereka butuhkan sebagai bidang, daripada menggunakan variabel paket.

Buatlah rencana untuk kegagalan, bukan kesuksesan


Jangan pernah melewatkan bug secara diam-diam.

Zen Python, entri 10

Ini dikatakan tentang bahasa yang mendorong penanganan pengecualian gaya samurai: kembali dengan kemenangan atau tidak kembali sama sekali. Dalam bahasa yang didasarkan pada pengecualian, fungsi hanya mengembalikan hasil yang valid. Jika fungsi tidak dapat melakukan ini, maka aliran kontrol berjalan dengan cara yang sama sekali berbeda.

Jelas, pengecualian yang tidak dicentang adalah model pemrograman yang tidak aman. Bagaimana Anda bisa menulis kode yang dapat diandalkan di hadapan kesalahan jika Anda tidak tahu ekspresi mana yang dapat menimbulkan pengecualian? Java mencoba mengurangi risiko dengan konsep pengecualian yang diperiksa. Dan sejauh yang saya tahu, dalam bahasa populer lainnya tidak ada analog dari solusi ini. Ada pengecualian dalam banyak bahasa, dan di mana-mana kecuali Jawa, mereka tidak dicentang.

Jelas, Go mengambil jalan yang berbeda. Programmer Go percaya bahwa program yang dapat diandalkan terdiri dari bagian yang menangani kegagalan sebelum memproses jalur yang berhasil. Mengingat bahwa bahasa tersebut dibuat untuk pengembangan server, pembuatan program multi-utas, serta program yang memproses data yang masuk melalui jaringan, programmer harus fokus pada bekerja dengan data yang tidak terduga dan rusak, batas waktu, dan kegagalan koneksi. Tentu saja jika mereka ingin membuat produk yang andal.

Saya percaya bahwa kesalahan harus ditangani secara eksplisit, ini harus menjadi nilai utama bahasa.

Peter Burgon, GoTime # 91

Saya bergabung dengan kata-kata Peter, mereka melayani sebagai dorongan untuk penulisan artikel ini. Saya percaya bahwa Go berutang kesuksesannya pada penanganan kesalahan yang eksplisit. Programmer terutama berpikir tentang kemungkinan crash. Pertama, kami memecahkan masalah seperti "bagaimana jika". Hasilnya adalah program di mana kegagalan ditangani pada tahap penulisan kode, dan tidak seperti yang terjadi selama operasi.

Verbositas dari kode ini

if err != nil {
    return err
}

Lebih penting daripada pentingnya menangani setiap kondisi gagal pada saat itu terjadi. Kunci untuk ini adalah nilai penanganan setiap kesalahan secara eksplisit.

Lebih baik kembali lebih awal daripada berinvestasi dalam-dalam


Saudara lebih baik daripada bersarang

The Zen of Python, entri 5

Nasihat bijak ini berasal dari bahasa di mana lekukan adalah bentuk utama aliran kontrol. Bagaimana kita menafsirkan tip ini dalam terminologi Go? gofmt mengelola seluruh jumlah ruang kosong di program Go, jadi kami tidak ada hubungannya di sini.

Saya menulis di atas tentang nama paket. Mungkin disarankan untuk menghindari hierarki paket yang kompleks. Dalam pengalaman saya, semakin seorang programmer mencoba untuk memisahkan dan mengklasifikasikan basis kode on Go, semakin tinggi risiko siklus impor paket.

Saya percaya bahwa penggunaan terbaik entri kelima dari The Zen of Python adalah untuk membuat aliran kontrol di dalam suatu fungsi. Dengan kata lain, hindari aliran kontrol yang membutuhkan lekukan multi-level.

Visibilitas langsung adalah garis lurus di mana pandangan tidak dikaburkan oleh apa pun.

May Ryer, Code: Sejajarkan jalur bahagia ke tepi kiri

May Ryer menggambarkan ide ini sebagai pemrograman yang berhadapan langsung:

  • Gunakan pernyataan kontrol untuk kembali lebih awal jika prasyarat tidak terpenuhi.
  • Menempatkan pernyataan pengembalian yang sukses di akhir fungsi, dan tidak di dalam blok bersyarat.
  • Kurangi tingkat bersarang secara keseluruhan dengan mengekstraksi fungsi dan metode.

Cobalah untuk memastikan bahwa fungsi-fungsi penting tidak pernah keluar dari pandangan ke tepi kanan layar. Prinsip ini memiliki efek samping: Anda akan menghindari perselisihan yang tidak berarti dengan tim tentang panjang garis.

Setiap kali Anda indentasi, Anda menambahkan satu prasyarat lagi ke kepala programmer, menempati salah satu dari 7 ± 2 slot memori jangka pendek mereka. Alih-alih memperdalam sarang, cobalah untuk menjaga jalur fungsi yang berhasil sedekat mungkin ke sisi kiri layar.

Jika Anda berpikir sesuatu berjalan lambat, maka buktikan dengan patokan


Hentikan godaan untuk menebak dalam menghadapi ambiguitas.

Zen dari Python 12

Pemrograman didasarkan pada matematika dan logika. Kedua konsep ini jarang menggunakan unsur keberuntungan. Tapi kami, sebagai programmer, membuat banyak asumsi setiap hari. Apa yang dilakukan variabel ini? Apa yang dilakukan opsi ini? Apa yang terjadi jika saya lulus nol di sini? Apa yang terjadi jika saya memanggil register dua kali? Dalam pemrograman modern, Anda harus banyak berasumsi, terutama ketika menggunakan perpustakaan orang lain.

API harus mudah digunakan dan sulit digunakan secara salah.

Josh Bloch

Salah satu cara terbaik yang saya ketahui untuk membantu programmer menghindari menebak ketika membuat API adalah fokus pada metode penggunaan standar . Penelepon harus dapat melakukan operasi normal semudah mungkin. Namun, sebelum saya banyak menulis dan berbicara tentang mendesain API, jadi inilah interpretasi saya atas catatan 12: jangan menebak tentang topik kinerja .

Terlepas dari sikap Anda terhadap saran Knut, salah satu alasan keberhasilan Go adalah efektivitas pelaksanaannya. Program yang efektif dapat ditulis dalam bahasa ini, dan berkat ini, orang - orang akan melakukannyapilih pergi. Ada banyak kesalahpahaman terkait kinerja. Oleh karena itu, ketika Anda mencari cara untuk meningkatkan kinerja kode, atau ikuti tips dogmatis seperti "rak melambat," "CGO mahal," atau "selalu menggunakan operasi atom bukan mutex," jangan lakukan ramalan.

Jangan menyulitkan kode Anda karena dogma usang. Dan jika Anda berpikir ada sesuatu yang bekerja lambat, pertama-tama pastikan itu dengan bantuan tolok ukur. Go memiliki alat pembandingan dan pembuatan profil gratis yang bagus. Gunakan mereka untuk menemukan hambatan dalam kinerja kode Anda.

Sebelum memulai gorutin, cari tahu kapan itu akan berhenti


Saya pikir saya telah mendaftarkan barang-barang berharga dari PEP-20 dan mungkin memperluas interpretasi mereka di luar selera yang baik. Ini bagus, karena meskipun ini adalah perangkat retoris yang berguna, kita masih berbicara tentang dua bahasa yang berbeda.

Tulis g, o, spasi, dan kemudian panggilan fungsi. Tiga tombol ditekan, tidak bisa lebih pendek. Tiga klik tombol, dan Anda meluncurkan proses.

Rob Pike, Simplicity is Complicated , dotGo 2015

Dua tips selanjutnya saya curahkan untuk goroutine. Gorutin adalah fitur khas dari bahasa tersebut, respons kami terhadap daya saing tingkat tinggi. Mereka sangat mudah digunakan: meletakkan kata godi depan operator dan Anda menjalankan fungsi secara tidak sinkron. Tidak ada utas eksekusi, tidak ada pelaksana kumpulan, tidak ada ID, tidak ada pelacakan status penyelesaian.

Gorutin itu murah. Karena kemampuan lingkungan runtime untuk multiplex goroutine dalam sejumlah kecil thread eksekusi (yang tidak perlu Anda kelola), Anda dapat dengan mudah membuat ratusan ribu atau jutaan goroutine. Ini memungkinkan Anda untuk membuat arsitektur yang tidak praktis ketika menggunakan model kompetitif lainnya, dalam bentuk utas eksekusi atau event callback.

Tapi betapapun murahnya goroutine, mereka tidak gratis. Tumpukan mereka membutuhkan setidaknya beberapa kilobyte. Dan ketika Anda memiliki jutaan goroutine, goresan tersebut menjadi nyata. Saya tidak bermaksud mengatakan bahwa Anda tidak perlu menggunakan jutaan goroutine, jika arsitektur mendorong Anda untuk ini. Tetapi jika Anda menggunakannya, maka sangat penting untuk memantaunya, karena dalam jumlah tersebut goroutine dapat mengkonsumsi banyak sumber daya.

Goroutine adalah sumber utama kepemilikan di Go. Agar bermanfaat, goroutine harus melakukan sesuatu. Artinya, hampir selalu berisi tautan ke sumber daya, yaitu, informasi kepemilikan: kunci, koneksi jaringan, buffer data yang mengirim ujung saluran. Sementara goroutine hidup, kunci ditahan, koneksi tetap terbuka, buffer disimpan, dan penerima saluran akan menunggu data baru.

Cara paling sederhana untuk membebaskan sumber daya adalah dengan menghubungkannya dengan siklus kehidupan goroutine. Ketika selesai, sumber daya dibebaskan. Dan karena sangat mudah untuk menjalankan goroutine, sebelum Anda menulis "pergi dan keluarkan" pastikan bahwa Anda memiliki jawaban untuk pertanyaan-pertanyaan ini:

  • Dalam kondisi apa goroutine berhenti? Go tidak dapat memberitahu goroutine untuk mengakhiri. Untuk alasan tertentu, tidak ada fungsi untuk berhenti atau menyela. Kita tidak bisa memerintahkan goroutine untuk berhenti, tetapi kita bisa dengan sopan bertanya. Ini hampir selalu terkait dengan pengoperasian saluran. Ketika ditutup, kisaran dilingkarkan untuk keluar dari saluran. Saat menutup saluran, Anda dapat memilihnya. Sinyal dari satu goroutine ke goroutine lainnya paling baik dinyatakan sebagai saluran tertutup.
  • ? , , : ?
  • , ? , - . , . . , .


Mungkin di salah satu program Go serius Anda, konkurensi digunakan. Ini sering mengarah pada masalah pola pekerja - satu goroutine per koneksi.

Contoh utama adalah net / http. Cukup sederhana untuk menghentikan server yang memiliki soket pendengaran, tetapi bagaimana dengan goroutine yang dihasilkan oleh soket ini? net / http menyediakan objek konteks di dalam objek permintaan yang dapat digunakan untuk memberi tahu pendengar bahwa permintaan perlu dibatalkan, dan karena itu mengganggu goroutine. Tetapi tidak jelas bagaimana mencari tahu kapan semua ini perlu dilakukan. Adalah satu hal untuk dihubungi context.Cancel, hal lain untuk mengetahui bahwa pembatalan selesai.

Saya sering menemukan kesalahan dengan net / http, tetapi bukan karena itu buruk. Sebaliknya, ini adalah API yang paling sukses, tertua, dan paling populer di basis kode Go. Oleh karena itu, arsitektur, evolusi, dan kekurangannya dianalisis dengan cermat. Pertimbangkan sanjungan ini, bukan kritik.

Jadi, saya ingin menjadikan net / http sebagai contoh praktik yang baik. Karena setiap koneksi diproses oleh goroutin yang dibuat di dalam tipe tersebut net/http.Server, program di luar paket net / http tidak dapat mengontrol goroutin yang dibuat oleh soket penerima.

Area arsitektur ini masih berkembang. Anda dapat mengingat run.Groupgo-kit, atau ErrGroup, dari tim pengembangan Go, yang menyediakan kerangka kerja untuk mengeksekusi, membatalkan, dan menunggu fungsi yang dijalankan secara tidak sinkron.

Untuk semua orang yang menulis kode yang dapat dieksekusi secara tidak serempak, prinsip utama pembuatan arsitektur adalah bahwa tanggung jawab untuk menjalankan goroutine harus dialihkan ke penelepon. Biarkan dia memilih bagaimana dia ingin berlari, melacak dan menunggu fungsi Anda selesai.

Tulis tes untuk memblokir perilaku API paket Anda


Anda mungkin berharap bahwa dalam artikel ini saya tidak akan menyebutkan pengujian. Maaf, lain waktu.

Tes Anda adalah perjanjian tentang apa yang program Anda lakukan dan apa yang tidak. Tes unit harus memblokir perilaku API mereka di tingkat paket. Tes menjelaskan dalam bentuk kode apa yang dijanjikan paket untuk dilakukan. Jika ada tes unit untuk setiap konversi input, maka Anda, dalam bentuk kode , dan bukan dokumentasi, telah menetapkan perjanjian tentang apa yang akan dilakukan kode.

Menyetujui perjanjian ini semudah menulis ujian. Pada tahap apa pun, Anda dapat menyatakan dengan tingkat keyakinan yang tinggi bahwa perilaku yang diandalkan orang sebelum perubahan yang Anda buat akan terus berfungsi setelah perubahan.

Tes memblokir perilaku API. Setiap perubahan yang menambah, mengubah, atau menghapus API publik harus mencakup perubahan dalam pengujian.

Moderasi adalah suatu kebajikan


Go adalah bahasa yang sederhana dengan hanya 25 kata kunci. Di satu sisi, ini menyoroti fitur yang dibangun ke dalam bahasa. Ini adalah fitur yang memungkinkan bahasa untuk mempromosikan dirinya: kompetisi sederhana, pengetikan struktural, dll.

Saya pikir kita semua bingung dengan mencoba menggunakan semua fitur Go sekaligus. Berapa banyak dari Anda yang sangat terinspirasi oleh penggunaan saluran sehingga Anda menggunakannya di mana saja? Saya menemukan bahwa program yang dihasilkan sulit untuk diuji, mereka rapuh dan terlalu kompleks. Dan kau?

Saya memiliki pengalaman yang sama dengan goroutin. Mencoba untuk membagi pekerjaan menjadi fragmen-fragmen kecil, saya menciptakan kegelapan goroutin, yang sulit dikendalikan, dan benar-benar kehilangan pandangan bahwa kebanyakan dari mereka selalu diblokir karena harapan para pendahulu mereka untuk menyelesaikan pekerjaan. Kode ini sepenuhnya konsisten, dan saya harus sangat meningkatkan kompleksitas untuk mendapatkan keuntungan kecil. Berapa banyak dari Anda yang mengalami ini?

Saya memiliki hal yang sama dengan penanaman. Pada awalnya saya bingung dengan warisan. Kemudian dia menghadapi masalah kelas dasar yang rapuh, menggabungkan beberapa tipe kompleks yang sudah memiliki beberapa tugas menjadi tipe besar yang bahkan lebih kompleks.

Ini mungkin saran yang paling tidak efektif, tetapi saya menganggap penting untuk menyebutkannya. Sarannya sama: tetap moderat, dan kemampuan Go tidak terkecuali. Kapan saja memungkinkan, jangan gunakan goroutine, saluran, struktur embedding, fungsi anonim, banyak paket dan antarmuka. Gunakan solusi yang lebih sederhana daripada yang cerdas.

Kemudahan masalah perawatan


Akhirnya, saya akan memberi Anda entri lain dari PEP-20:

Masalah keterbacaan.

The Zen of Python, catatan 7

Banyak yang telah dikatakan tentang pentingnya keterbacaan kode dalam semua bahasa pemrograman. Mereka yang mempromosikan Go menggunakan kata-kata seperti kesederhanaan, keterbacaan, kejelasan, produktivitas. Tetapi semua ini adalah sinonim dari satu konsep - kenyamanan pemeliharaan.

Tujuan sebenarnya adalah membuat kode yang mudah dipelihara. Kode yang hidup lebih lama dari penulis. Kode yang dapat ada tidak hanya sebagai investasi waktu, tetapi sebagai dasar untuk mendapatkan nilai masa depan. Ini tidak berarti bahwa keterbacaan tidak penting, hanya kenyamanan perawatan lebih penting .

Go bukan salah satu dari bahasa yang dioptimalkan untuk program single-line. Dan bukan salah satu dari bahasa itu yang dioptimalkan untuk program dengan jumlah baris minimum. Kami tidak mengoptimalkan untuk ukuran kode sumber pada disk, atau untuk kecepatan menulis program di editor. Kami ingin mengoptimalkan kode kami sehingga menjadi lebih mudah dipahami oleh pembaca. Karena merekalah yang harus menemaninya.

Jika Anda menulis sebuah program untuk diri sendiri, maka mungkin program itu akan diluncurkan hanya sekali, atau hanya Anda yang melihat kodenya. Dalam hal ini, lakukan apa saja. Tetapi jika lebih dari satu orang bekerja pada kode, atau jika itu akan digunakan untuk waktu yang lama dan persyaratan, kemampuan atau runtime dapat berubah, maka program harus nyaman untuk dipertahankan. Jika perangkat lunak tidak dapat dipertahankan, maka tidak dapat ditulis ulang. Dan ini mungkin terakhir kali perusahaan Anda berinvestasi di Go.

Apa yang Anda kerjakan dengan gampang akan menemani setelah keberangkatan Anda? Bagaimana Anda bisa memfasilitasi pemeliharaan kode Anda untuk mereka yang datang setelah Anda hari ini?

All Articles