Jangan Sederhanakan Kode Ini
(github.com/kubernetes)pv_controller.gomilik Kubernetes adalah controller yang menyinkronkan binding PV/PVC, dan sejak komentar di bagian atas file sudah ditegaskan untuk “jangan disederhanakan, pertahankan gaya space shuttle”- Gaya ini menempatkan
elseuntuk setiapifdan meninggalkan komentar bahkan untuk kondisi yang tampak jelas, agar cabang yang telah ditinjau dan niat desain terlihat langsung di dalam kode - Pusat desainnya adalah pointer dua arah yang terhubung melalui
pvc.Spec.VolumeNamedanpv.Spec.ClaimRef, sehingga kompetisi, penghapusan, modifikasi pengguna, dan binding bersamaan bisa dipulihkan dalam lingkungan tanpa transaksi - Controller ini menggabungkan pengawasan perubahan PV/PVC, cache internal, antrean worker tunggal, pencatatan event, provisioning dinamis, dan antarmuka migrasi CSI untuk mengelola transisi status binding
- Percabangan yang panjang dan komentar yang rinci adalah mekanisme untuk mempertahankan pengetahuan domain perilaku dan konteks pemulihan kegagalan, sehingga perubahan di masa depan juga harus mengikuti gaya yang sama
Peran dan prinsip penulisan pv_controller.go
pv_controller.goadalah file implementasi PersistentVolumeController dalam paketpersistentvolumeKubernetes- Controller ini menyelaraskan status
PersistentVolumeClaimdanPersistentVolume- cache controller yang memantau perubahan
PersistentVolume - cache controller yang memantau perubahan
PersistentVolumeClaim - sinkronisasi status PV/PVC berdasarkan event perubahan kedua objek
- cache controller yang memantau perubahan
- Komentar di bagian atas file berulang kali memperingatkan agar kode ini tidak disederhanakan
- Nama gayanya adalah
space shuttle style - Pendekatannya adalah menyediakan
elseyang berpasangan untuk setiap pernyataanif - Tujuannya adalah membuat semua cabang eksplisit, kecuali pemeriksaan error sederhana
- Bahkan perilaku yang tampak jelas pun ditulis dalam komentar agar maintainer dapat melacak kompleksitas binding
- Nama gayanya adalah
Alasan mempertahankan space shuttle style
- Controller ini merupakan hasil penggabungan pekerjaan yang awalnya dibagi ke dalam tiga controller
- Dalam proses menyederhanakan subsistem PV, diperlukan cara untuk menangani semua kondisi secara eksplisit di dalam kode
- Akibatnya, kode ini bisa tampak bertele-tele dan penuh komentar serta percabangan
- Keterperincian ini adalah mekanisme untuk menyimpan pengetahuan domain dan konteks dari perilaku binding di dalam kode
- Saat mengubah file ini,
space shuttle styleharus dipertahankan, dan bila perlu cabang serta komentar baru harus ditambahkan dengan pola yang sama
Desain inti: pointer dua arah antara PV dan PVC
- Pusat desainnya adalah pointer dua arah antara PV dan PVC
- Pointer di sisi PVC:
pvc.Spec.VolumeName - Pointer di sisi PV:
pv.Spec.ClaimRef
- Pointer di sisi PVC:
- Sifat dua arah ini sulit ditangani dalam sistem tanpa transaksi, tetapi diperlukan untuk menjamin perilaku normal bahkan dalam kondisi kegagalan
- Jika ada instance controller HA liar yang membuat kondisi balapan, beberapa binding yang tidak bisa dibedakan dapat muncul dan menimbulkan kemungkinan kehilangan data
- Controller ini pada dasarnya dirancang untuk beroperasi dalam mode high availability active-passive
- Transisi objek juga dirancang agar bisa bekerja dalam HA active-active
- Namun, jika dua controller aktif sering bertabrakan, performa bisa menurun
Metode binding dan kondisi pemulihan
- Controller ini mendukung objek pre-bound dua arah
- PVC yang menginginkan PV tertentu
- PV yang dicadangkan untuk PVC tertentu
- Binding berlangsung dalam dua tahap
- Pertama memodifikasi
PV.Spec.ClaimRef - Berikutnya memodifikasi
PVC.Spec.VolumeName
- Pertama memodifikasi
- Pada titik mana pun dalam proses ini, PV atau PVC dapat dimodifikasi atau dihapus oleh pengguna atau controller lain
- Dua atau lebih controller juga bisa mencoba membinding volume dan claim yang berbeda secara bersamaan
- Controller harus bisa memulihkan diri dari situasi benturan seperti ini
Komponen utama struct controller
PersistentVolumeControllermemiliki lister, fungsi sinkronisasi informer, klien Kubernetes, perekam event, pengelola plugin volume, dan komponen lain yang diperlukan untuk sinkronisasi PV/PVC- Versi terakhir PV/PVC yang diketahui disimpan di cache internal
volumes persistentVolumeOrderedIndexclaims cache.Store
- Cache ini mencerminkan baik versi terbaru yang disimpan ke API server maupun versi yang masuk melalui event etcd
- Satu binding dapat menghasilkan sekitar empat event
- pembaruan
volume.Spec - pembaruan
volume.Status - pembaruan
claim.Spec - pembaruan
claim.Status
- pembaruan
- Tanpa cache internal, informer dapat membawa status lama dan mencoba memperbaiki ulang binding yang sebenarnya sudah selesai
- Jika saat itu mencoba menulis ulang ke API server, bisa terjadi konflik versi dengan objek yang sudah tersimpan
Antrean kerja dan batasan konkurensi
- Controller ini memiliki workqueue terpisah untuk memproses claim dan volume
claimQueuevolumeQueue
- Setiap antrean harus memiliki tepat satu worker thread
- Secara khusus,
syncClaim()tidak reentrant - Jika dua
syncClaim()berjalan bersamaan, masalah berikut dapat terjadi- dua claim yang berbeda dibinding ke volume yang sama
- satu claim dibinding ke dua volume
- Controller bisa memulihkan situasi ini melalui error versi dari API server dan pemeriksaannya sendiri, tetapi pendekatan multi-worker dapat menurunkan kecepatan keseluruhan
syncClaim: titik masuk sinkronisasi PVC
syncClaimadalah metode utama yang dipanggil saat claim dibuat, diperbarui, atau disinkronkan secara periodik- Metode ini tidak membedakan jenis event
- Pertama, metode ini menetapkan migration annotation yang benar pada PVC dan, bila perlu, memperbaruinya ke API server
- Setelah itu ia bercabang berdasarkan ada tidaknya annotation
AnnBindCompleted- jika annotation tidak ada, panggil
syncUnboundClaim - jika annotation ada, panggil
syncBoundClaim
- jika annotation tidak ada, panggil
- Pemrosesan aktual dipisahkan ke metode claim unbound dan claim bound demi keterbacaan
checkVolumeSatisfyClaim: pemeriksaan syarat PV
checkVolumeSatisfyClaimmemeriksa apakah PV yang diminta memenuhi persyaratan PVC- Kondisi pemeriksaan didaftarkan secara eksplisit di dalam kode
- error jika PV memiliki
DeletionTimestamp - error jika kapasitas PV lebih kecil daripada kapasitas yang diminta PVC
- error jika
storageClassNameberbeda - jika feature gate
VolumeAttributesClassaktif, periksa kecocokanVolumeAttributesClassName - jika feature gate nonaktif tetapi claim atau volume memiliki
VolumeAttributesClassName, hasilnya error - error jika
volumeModetidak kompatibel - error jika access mode tidak kompatibel
- error jika PV memiliki
- Jika semua syarat lolos, fungsi mengembalikan
nil
Penanganan event untuk PVC delayed binding
emitEventForUnboundDelayBindingClaimmembuat event informasional untuk claim yang belum dibinding dalam mode delayed binding- Reason bawaannya adalah
WaitForFirstConsumer - Pesan bawaannya menyatakan bahwa binding menunggu hingga consumer pertama dibuat
- Jika ada Pod yang belum dijadwalkan dan mereferensikan PVC tersebut, reason berubah menjadi
WaitForPodScheduled- jika Pod-nya lebih dari satu, nama semua Pod dimasukkan ke dalam pesan
- dalam volume scheduling hanya satu Pod yang dipertimbangkan, tetapi karena tidak diketahui Pod mana yang akan dipakai, semuanya disertakan
syncUnboundClaim: menangani PVC yang belum dibinding
- Jika
claim.Spec.VolumeNamekosong, berarti pengguna tidak meminta PV tertentu - Dalam kasus ini, controller memeriksa mode delayed binding claim dan mencari PV yang paling cocok dengan
findBestMatchForClaim - Jika tidak ada PV yang cocok, pemrosesan berlangsung dalam urutan berikut
- jika StorageClass default bisa ditetapkan, perbarui PVC dan akhiri sinkronisasi
- jika delayed binding dan belum dalam status provisioning, buat event tunggu
- jika claim memiliki StorageClass, coba provisioning dinamis dengan
provisionClaim - selain itu, catat event
FailedBindingbahwa tidak ada PV yang tersedia dan tidak ada StorageClass
- Jika ada PV yang cocok, panggil
binduntuk membinding PV dan PVC- jika berhasil, catat metrik pekerjaan provisioning + binding dan bersihkan cache timestamp
- jika terjadi error saat penyimpanan,
syncClaimberikutnya akan menyelesaikan binding
Menangani PVC yang meminta PV tertentu
- Jika
claim.Spec.VolumeNametidak kosong, berarti pengguna meminta PV tertentu - Jika PV yang diminta tidak ada di cache, status PVC diperbarui ke
Pendingdan akan dicoba lagi nanti - Jika PV yang diminta ada dan
volume.Spec.ClaimRefkosong, berarti PV itu belum di-claim- periksa syarat dengan
checkVolumeSatisfyClaim - jika syarat tidak terpenuhi, catat event
VolumeMismatchdan pertahankan PVC diPending - jika syarat terpenuhi, panggil
bind
- periksa syarat dengan
- Jika PV yang diminta sudah di-claim oleh PVC ini, panggil
binduntuk menyelesaikan binding - Jika PV yang diminta terikat ke claim lain, penanganannya sebagai berikut
- jika claim tidak memiliki annotation bahwa ia dibinding oleh controller, catat event
FailedBindingdan biarkan tetapPending - jika tampaknya controller yang membinding tetapi PV terikat ke claim lain, kembalikan error dengan status “should never happen”
- jika claim tidak memiliki annotation bahwa ia dibinding oleh controller, catat event
syncBoundClaim: menangani PVC yang sudah dibinding
syncBoundClaimmenangani PVC yang memiliki annotationAnnBindCompleted- Jika claim sudah dibinding tetapi
claim.Spec.VolumeNamekosong, status claim diubah menjadiClaimLost- pesan event menyatakan bahwa bound claim kehilangan referensi ke PV dan data volume telah hilang
- Jika PV yang dirujuk claim tidak ada, status juga diubah menjadi
ClaimLost- pesan event menyatakan bahwa bound claim kehilangan PersistentVolume dan datanya telah hilang
- Jika PV ada tetapi
volume.Spec.ClaimRefkosong, volume dianggap menjadi unbound danbinddipanggil lagi - Jika
ClaimRef.UIDmilik PV sama dengan UID claim, itu dianggap status binding normal danbinddipanggil- dalam kebanyakan kasus ini adalah pemanggilan yang tidak melakukan apa-apa
- Jika PV menunjuk claimant lain, phase claim disetel ke status terminal
Lost
syncVolume: titik masuk sinkronisasi PV
syncVolumeadalah metode utama yang dipanggil saat volume dibuat, diperbarui, atau disinkronkan secara periodik- Ia tidak membedakan jenis event
- Pertama, metode ini menetapkan migration annotation dan finalizer yang benar pada PV lalu memperbaruinya ke API server bila perlu
- Jika
volume.Spec.ClaimReftidak ada, volume dianggap tidak digunakan dan phase disetel keAvailable - Jika
ClaimRefada tetapi UID kosong, volume dianggap PV yang dicadangkan untuk PVC tertentu dan phase disetel keAvailable- dalam keadaan ini PVC tersebut belum dibinding ke PV ini, dan sinkronisasi PVC yang akan menanganinya
Menangani PV yang claim-nya tidak ditemukan
- Jika PV dibinding ke claim, controller mencari PVC berdasarkan namespace/name pada
ClaimRef - Jika PVC tidak ditemukan di cache, pemeriksaan tambahan dilakukan dalam kondisi tertentu
- periksa lagi di informer cache
- periksa lagi di API server
- Pada PV yang dibuat oleh external PV provisioner atau external PV binder, dalam kondisi beban tinggi bisa jadi PVC belum tersinkron ke cache lokal
- Untuk menghindari reclaim PVC secara keliru, dilakukan pemeriksaan ganda
- Jika diputuskan bahwa claim memang tidak ada, phase volume diubah menjadi
ReleaseddanreclaimVolumedijalankan- jika phase sebelumnya
Failed, nilainya tidak ditimpa - jika reclaim policy adalah
Retain, dicatat log bahwa PV mereferensikan claim yang tidak ada
- jika phase sebelumnya
Saat koneksi PV dan PVC tidak selaras
- Jika claim ada tetapi
claim.Spec.VolumeNamekosong, berarti PVC belum memiliki nama PV - Jika
volumeModetidak cocok, eventVolumeMismatchdicatat pada kedua sisi PV dan PVC, lalusyncClaimdilewati - Jika bukan mismatch, claim dimasukkan ke
claimQueueagarsyncClaimsegera dipanggil- pendekatan ini mempercepat binding untuk volume yang diprovision
- Jika
Spec.VolumeNameclaim sama dengan nama volume saat ini, itu dianggap binding normal dan phase volume diperbarui keBound - Jika claim dibinding ke volume lain, penanganannya bergantung pada situasi
- jika volume diprovision secara dinamis dan reclaim policy-nya
Delete, tandaiReleaseddan jalankanreclaimVolume - jika volume dibinding oleh controller, rapikan dengan
unbindVolume - jika pointer dibuat oleh pengguna, biarkan sebagaimana adanya tetapi panggil
unbindVolumeuntuk memperbarui phase dan mengosongkanClaimRef.UID
- jika volume diprovision secara dinamis dan reclaim policy-nya
Pembaruan status dan penerbitan event
updateClaimStatusmenyimpan status PVC ke API server- perubahan phase
- saat tidak ada volume, inisialisasi
AccessModes,Capacity,CurrentVolumeAttributesClassName - saat ada volume, perbarui access mode, kapasitas, dan nama current volume attributes class
- Ada kondisi bahwa kapasitas hanya diperbarui ketika claim menjadi
Bound- karena perbedaan antara ukuran filesystem PVC dan ukuran block device PV bisa memang disengaja, kapasitas claim yang sudah bound tidak ditimpa
- Jika feature gate
VolumeAttributesClassaktif,CurrentVolumeAttributesClassNamedisetel saat transisi dari pending ke bound- setelah itu, penanganannya harus dilakukan oleh resizer atau admin override, karena jika controller terus menyetelnya bisa menimbulkan race condition
updateClaimStatusWithEventdanupdateVolumePhaseWithEventhanya menerbitkan event ketika status/phase benar-benar berubah
Penetapan StorageClass default
assignDefaultStorageClassmencari dan menetapkan StorageClass default ketika claim tidak memiliki storage class- Claim yang sudah memiliki storage class diabaikan
- Jika tidak ada class default, tidak ada pembaruan dan fungsi mengembalikan
false - Jika ada class default, nama class diisikan ke
claim.Spec.StorageClassNamelalu diperbarui ke API server
Cakupan file dan batasan eksplisit
- Berdasarkan metadata file yang ditampilkan di halaman GitHub,
pv_controller.goberukuran 2038 baris, 1864 LOC, 91 KB - Isi yang diberikan hanya mencakup dari bagian awal file hingga awal fungsi
bindVolumeToClaim, dan sisanya berlanjut melalui tautan raw view - Karena itu, ringkasan ini dibatasi pada struktur controller, komentar desain, cabang sinkronisasi utama, dan logika pembaruan status yang terlihat dalam isi kode yang disediakan
1 komentar
Pendapat Hacker News
Entah apakah aneh kalau kode di berkas ini terasa benar-benar seperti kode Go biasa. Karena Go, ia jadi bertele-tele, dan karena tidak bergantung pada abstraksi yang dalam, terlihat lebih panjang, tetapi kodenya sendiri tampak tipikal
Abstraksi adalah pedang bermata dua, jadi cara seperti ini juga baik-baik saja, dan kalau tidak ada pengantar di awal, sepertinya saya tidak akan berpikir dua kali soal gaya penulisannya. Mungkin ini perbedaan yang muncul karena saya punya lebih banyak pengalaman di perangkat lunak enterprise daripada perangkat lunak sistem. Bagi orang yang rutin berkontribusi ke Kubernetes, komentar-komentar ini mungkin terlihat tidak perlu, tetapi kalau ini kode yang akan dibaca jauh di masa depan oleh pembaca di lingkungan enterprise tanpa konteks, pada tingkat kompleksitas seperti ini saya mungkin justru akan menambahkan lebih banyak komentar
Dulu kode seperti ini terasa normal, tetapi dalam kira-kira 10 tahun terakhir banyak orang tampaknya lebih menghargai keringkasan daripada eksplisitas
Khususnya untuk kode sepenting ini, saya jauh lebih memilih eksplisitas. Dalam karier saya, sudah beberapa kali saya berhadapan dengan kode yang menggabungkan banyak kondisi dan menghilangkan komentar yang menjelaskan konteks serta makna bisnis, sehingga saya tidak bisa menilai apakah perilaku saat ini memang disengaja atau kebetulan. Cara seperti ini mudah berubah menjadi kode yang menghalangi perubahan, bukan kode yang tahan terhadap perubahan, dan setidaknya membuatnya sulit diperbaiki oleh orang selain penulisnya. Membuat pagar Chesterton yang tidak perlu bertentangan dengan keterpeliharaan
Komentar ini mungkin ditambahkan setelah ada upaya menyederhanakan kode yang gagal, sebagai peringatan bagi pemelihara di masa depan agar berpikir ulang sebelum mencoba hal yang sama
Commit yang menambahkan peringatan itu adalah "Add note about space-shuttle code style"[1], dan commit tepat sebelumnya adalah "Revert controller/volume: simplify sync logic in syncUnboundClaim"[2]
[1] https://github.com/kubernetes/kubernetes/commit/de4d193d45f6...
[2] https://github.com/kubernetes/kubernetes/commit/8a1baa4d64ca...
Saya juga awalnya berpikir mirip, lalu berubah pikiran setelah melihat pernyataan
ifyang sangat bersarang. Bagian itu jelas saya rasa akan saya jadikan cabang early returnRasanya seperti baru menyelesaikan langkah pertama dari "buat berfungsi, buat cepat, buat indah", lalu tidak melakukan bagian "buat indah". Saat mengurai interaksi status yang rumit, saya pernah menulis kode jelek dan penuh komentar seperti ini, tetapi biasanya saya merapikannya sedikit sebelum review. Mungkin lebih baik cukup memasang banner besar di paling atas berkas: "jangan mencoba menyederhanakan kode ini". Meski begitu, jelas ini tidak terlalu buruk
Mungkin saja aneh, tetapi Anda tidak sendirian. Bagi saya juga kode ini terlihat sepenuhnya normal. Untuk komponen yang saya anggap penting bagi keandalan sistem, saya pernah menulis kode dan komentar seperti ini
Saya tidak pernah setuju dengan tren "kode tanpa komentar", dan ketika kembali beberapa bulan atau beberapa tahun kemudian, komentar yang saya tulis terlalu sering sangat berharga bagi diri saya di masa depan. Sulit membayangkan menyusun kembali logika yang tertanam dalam komponen dengan tingkat kompleksitas seperti ini tanpa komentar yang kokoh
Khususnya, penjelasan bahwa setiap
ifmemiliki komentarelsepasangannya tampaknya tidak selalu benar. Banyakifyang tidak punya pasangan hanyalah pemeriksaan sederhanaif (err != nil) {atau early return lain, tetapi bahkan setelah mengecualikan itu, tampaknya masih adaiftanpa pasanganNamun, berdasarkan pengalaman perangkat lunak enterprise, komentar tambahan juga tidak selalu banyak. Di codebase memang ada komentar
// end ifseperti wabah, tetapi komentar penjelasan yang sebenarnya jarangArtikel tentang kualitas perangkat lunak Space Shuttle: https://archive.is/HX7n4
Jika dikutip, alasan perangkat lunak ini mengagumkan bukanlah seberapa banyak hal yang dilakukannya, melainkan seberapa baik ia bekerja. Katanya, ia tidak pernah crash, tidak perlu reboot, tidak memiliki bug, dan mendekati sempurna pada tingkat yang pernah dicapai manusia. Tiga versi terakhir masing-masing berisi 420 ribu baris, tetapi hanya memiliki satu kesalahan masing-masing, dan total kesalahan di 11 versi terakhir adalah 17. Disebutkan bahwa program komersial dengan kompleksitas yang sama mungkin memiliki sekitar 5.000 kesalahan
Karena terlalu mahal dan lambat, membuktikan kebenaran perangkat lunak dengan proof assistant modern kemungkinan jauh lebih murah, lebih cepat, dan sebenarnya lebih aman. Proyek seperti seL4 dan CompCert menunjukkan bagaimana seharusnya dilakukan
Saya memahami maksud
// KEEP THE SPACE SHUTTLE FLYING., tetapi agak lucu bahwa komentar itu merujuk pada sistem yang catatan keselamatannya tidak bagus dan sudah tidak dioperasikan lagiKira-kira 10 tahun lagi, apakah orang-orang masih akan mengenang Space Shuttle secara positif?
Masalah keselamatan Space Shuttle pada umumnya adalah masalah perangkat keras, bukan masalah perangkat lunak
Dalam "Appendix F - Personal Observations on Reliability of Shuttle" [0], lampiran Richard Feynman dalam laporan kecelakaan Challenger 1986, disebutkan sebagai berikut
Ia secara khusus menyoroti kualitas perangkat lunak avionik sebagai contoh bahwa proyek pemerintah besar dan kompleks seperti Shuttle pun dapat direkayasa dengan benar, dan tidak dengan sendirinya ditakdirkan berkualitas rendah atau berbahaya
0: https://www.nasa.gov/history/rogersrep/v2appf.htm
Telah membawa orang dan peralatan ke luar angkasa, lalu mengembalikannya ke rumah, dalam jauh lebih dari 100 misi sukses. Saya masih memandangnya baik, dan kemungkinan besar akan tetap begitu. Dari sisi kemajuan manusia dan dampak bersih, itu adalah keberhasilan
Yang mengakhiri Shuttle bukan catatan keselamatan yang buruk, melainkan biaya dan perkiraan penurunan keselamatan di masa depan
Memang dua kecelakaan Shuttle menewaskan lebih banyak astronaut daripada bencana NASA lainnya, tetapi jika mempertimbangkan tingkat kesulitan dari hal-hal yang benar-benar dilakukan, catatan keselamatannya sungguh luar biasa. Kodenya terlihat sangat bagus
Situasi Space Shuttle lebih kompleks daripada sekadar mengatakan keselamatannya buruk. Jika dilihat per misi, rekornya tergolong lebih baik daripada kendaraan peluncur lain. Shuttle memiliki 2 misi fatal dari 135, Soyuz era Soviet 2 dari 66, dan SpaceShipTwo punya catatan yang mengerikan: 1 misi fatal dari hanya 12 penerbangan
Namun Space Shuttle memiliki kapasitas awak yang jauh lebih besar daripada yang dibutuhkan untuk sebagian besar misi. Berbeda dengan Apollo atau Soyuz yang berawak 3 orang, Shuttle bisa membawa hingga 8 orang; dan jika mengingat sebagian besar misi Soviet/Roscosmos, ESA, dan CNSA sepenuhnya nirawak dan otonom, memang tidak ada awak yang bisa berada dalam risiko. Mungkin analogi ini lebih cocok untuk Kubernetes: sistem yang sangat direkayasa, kuat, serbaguna, tetapi menuntut banyak kehati-hatian, dan mungkin dipakai sedikit lebih banyak daripada yang sebenarnya diperlukan
Jika memakai ukuran paling umum, yaitu per penumpang-mil, Space Shuttle termasuk salah satu kendaraan paling aman yang pernah dibuat dan diterbangkan
Sebagai seseorang yang masa kecilnya tepat berada pada 1980-an, jujur saja saya bertanya: bagaimana mungkin orang tidak mengenangnya dengan baik? Apakah karena terlalu muda sehingga hanya melihat program ini beserta semua misi dan pencapaiannya secara retrospektif, dan hanya punya sudut pandang yang diwarnai suasana zaman sekarang yang berpusat pada kontraktor antariksa swasta?
Cerita Richard Hipp tentang menyesuaikan kode SQLite dengan standar penerbangan juga cukup menarik: https://corecursive.com/066-sqlite-with-richard-hipp/#testin...
Bagian ini mengingatkan saya pada pemeriksaan kelengkapan dalam kode TypeScript. Saya selalu berusaha memakainya
https://www.typescriptlang.org/docs/handbook/2/narrowing.htm...
satisfies neveryang lebih baru sangat bagus untuk kegunaan ini. Juga praktis jika, karena selera, Anda memakai rantaiif elseAnda mungkin juga menyukai
ts-patternhttps://github.com/gvergnaud/ts-pattern
Kalau hanya melihat kasus penambahan
elseeksplisit pada setiapifyang sama sekali tidak sepele, saya penasaran seberapa sederhananya kode ini jika para penulis Kubernetes merancangnya dengan berpusat pada structural pattern matching, alih-alih blokif/elseBanyak bahasa arus utama yang mendukung structural pattern matching memiliki alat untuk memeriksa pada waktu kompilasi apakah pencocokannya lengkap, dan itu saja bisa menjadi solusi idiomatis sekaligus meningkatkan kepadatan informasi kode
Diskusi 2018: https://news.ycombinator.com/item?id=18772873
Saya hanya melihat sekilas kodenya, tetapi jujur saja tidak terlihat seburuk itu. Ada bagian yang mungkin akan saya lakukan berbeda, tetapi saya sudah melihat banyak kode yang jauh lebih parah
Setidaknya kode ini mengikuti satu aturan; semuanya tampak ditulis setelah dipikirkan, dan ada kesan bahwa di balik kekacauan ini ada metodenya sendiri. Saya kapan saja akan memilih kode seperti ini dibanding gado-gado tipikal yang sudah sering saya lihat: campuran gaya, coding malas, dan struktur yang tidak logis
Saya penasaran mengapa, saat membuat praktik “keselamatan” baru, mereka mengabaikan praktik terbaik rekayasa perangkat lunak yang terdokumentasi
Modul 2.000 baris, metode 200 baris, dan
ifbertingkat 3–4 level dianggap berbahaya. Komentar yang hanya mengatakan apa yang dilakukan, bukan mengapa, juga tidak berguna dan mudah menyimpang dari kode sebenarnya. Terlihat pula penggunaannilyang tidak perlu. Bahkan tanpa masuk ke masalah yang lebih dalam seperti coupling atau prinsip tanggung jawab tunggal, hal-hal ini sudah tampak di permukaanJika Anda menganggap hal-hal ini berbahaya, saya sarankan membaca “John Carmack on Inlined Code”
http://number-none.com/blow/john_carmack_on_inlined_code.htm...
“Kode kontrol penerbangan roket Armadillo hanya beberapa ribu baris, jadi saya mengambil fungsi tic utama dan mulai meng-inline semua subrutin. Saya tidak bisa mengatakan bahwa saya menemukan bug tersembunyi yang bisa menyebabkan kecelakaan nyata, tetapi saya menemukan beberapa variabel yang disetel berkali-kali dan beberapa alur kontrol yang tampak agak mencurigakan, dan kode akhirnya menjadi lebih kecil dan lebih rapi.”
Jika Carmack menemukan nilai dalam pendekatan ini, rasanya kita tidak boleh buru-buru mengabaikannya. Komentar lanjutannya juga layak dibaca
“Dalam beberapa tahun setelah menulis ini, saya menjadi jauh lebih positif terhadap pemrograman fungsional murni dalam batas yang wajar, bahkan di C/C++... Jika mulai sulit ditangani, carilah cara untuk memisahkan blok menjadi fungsi murni”
Kadang memang ada kasus “tidak ada cara lain(TM)”
Batas jumlah baris yang arbitrer cenderung menghasilkan fragmentasi yang tidak perlu. Jika ditambah include, lisensi, kode perekat, dan komentar, jadilah spaghetti yang sulit didekati. Cobalah mempertahankan metode tetap 200 baris pada kode berkinerja tinggi; performanya bisa jatuh seperti penerbangan Icarus
Jika membaca komentar dalam kode, terlihat bahwa kode ini telah disederhanakan menjadi satu modul, dan banyak sekali pengetahuan praktis dimasukkan agar kode tersebut mudah diakses dan, yang lebih penting, berkelanjutan. Bagi orang yang tidak memahami bahasa atau logikanya, komentar yang memberi gambaran tentang apa yang dilakukan kode sangat berguna. Enam bulan kemudian, kode sendiri pun terasa asing, jadi komentar juga berguna bagi diri sendiri.
Saya sudah cukup lama menulis dengan cara "aman" seperti ini, tetapi hasilnya jauh lebih banyak bug dibanding penanganan error gaya railway melalui early return, dan memperbaikinya pun jauh lebih lama
Menambahkan
elseeksplisit ke setiap blokifmembuat kompleksitas untuk mengingat konteks saat ini meledak. Menurut saya, aturan ini lebih masuk akal jika diubah menjadi "setiap blok kondisiifmelakukan early return, atau memiliki blokelsepasangannya". Polaif (cond) { penanganan khusus }jelas jauh lebih berbahaya dan lebih sulit dinalar dibanding early return.Tidak ada satu paket best practice resmi yang tunggal
Panjang fungsi atau jumlah baris kode dalam file pada dasarnya tidak selalu merugikan atau menguntungkan. Tiap bahasa punya pandangan tentang bagaimana kode sebaiknya disusun, tetapi tidak satu pun dapat diklaim sebagai "praktik terbaik". Go bukan bahasa yang menyukai pemecahan kode menjadi banyak file kecil.
Metode 200 baris tidak secara inheren salah. Jika kode di dalamnya linear dan mempertahankan tingkat abstraksi yang sama, itu bisa menjadi pilihan terbaik
Alternatif berupa 40 metode masing-masing 5 baris bisa lebih buruk. Untuk memahami keseluruhannya, Anda harus melompat ke sana-kemari, dan urutan pemanggilan juga bisa kacau. Permutasi yang mungkin dipilih bahkan ada 40!.
Kode seperti ini tampak sebagai kandidat ideal untuk dipindahkan ke sistem deklaratif, berbasis aturan, dan table-driven
Cara seperti itu lebih mudah dipahami dan diverifikasi dibanding kode imperatif ad hoc yang penuh klausa
if. Kode berantakan semacam ini biasanya menjadi tanda adanya abstraksi yang hilang.