2 poin oleh GN⁺ 2024-08-07 | 1 komentar | Bagikan ke WhatsApp
  • pv_controller.go milik 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 else untuk setiap if dan 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.VolumeName dan pv.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.go adalah file implementasi PersistentVolumeController dalam paket persistentvolume Kubernetes
  • Controller ini menyelaraskan status PersistentVolumeClaim dan PersistentVolume
    • cache controller yang memantau perubahan PersistentVolume
    • cache controller yang memantau perubahan PersistentVolumeClaim
    • sinkronisasi status PV/PVC berdasarkan event perubahan kedua objek
  • Komentar di bagian atas file berulang kali memperingatkan agar kode ini tidak disederhanakan
    • Nama gayanya adalah space shuttle style
    • Pendekatannya adalah menyediakan else yang berpasangan untuk setiap pernyataan if
    • 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

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 style harus 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
  • 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
  • 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

  • PersistentVolumeController memiliki 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 persistentVolumeOrderedIndex
    • claims 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
  • 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
    • claimQueue
    • volumeQueue
  • 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

  • syncClaim adalah 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
  • Pemrosesan aktual dipisahkan ke metode claim unbound dan claim bound demi keterbacaan

checkVolumeSatisfyClaim: pemeriksaan syarat PV

  • checkVolumeSatisfyClaim memeriksa 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 storageClassName berbeda
    • jika feature gate VolumeAttributesClass aktif, periksa kecocokan VolumeAttributesClassName
    • jika feature gate nonaktif tetapi claim atau volume memiliki VolumeAttributesClassName, hasilnya error
    • error jika volumeMode tidak kompatibel
    • error jika access mode tidak kompatibel
  • Jika semua syarat lolos, fungsi mengembalikan nil

Penanganan event untuk PVC delayed binding

  • emitEventForUnboundDelayBindingClaim membuat 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.VolumeName kosong, 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 FailedBinding bahwa tidak ada PV yang tersedia dan tidak ada StorageClass
  • Jika ada PV yang cocok, panggil bind untuk membinding PV dan PVC
    • jika berhasil, catat metrik pekerjaan provisioning + binding dan bersihkan cache timestamp
    • jika terjadi error saat penyimpanan, syncClaim berikutnya akan menyelesaikan binding

Menangani PVC yang meminta PV tertentu

  • Jika claim.Spec.VolumeName tidak kosong, berarti pengguna meminta PV tertentu
  • Jika PV yang diminta tidak ada di cache, status PVC diperbarui ke Pending dan akan dicoba lagi nanti
  • Jika PV yang diminta ada dan volume.Spec.ClaimRef kosong, berarti PV itu belum di-claim
    • periksa syarat dengan checkVolumeSatisfyClaim
    • jika syarat tidak terpenuhi, catat event VolumeMismatch dan pertahankan PVC di Pending
    • jika syarat terpenuhi, panggil bind
  • Jika PV yang diminta sudah di-claim oleh PVC ini, panggil bind untuk 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 FailedBinding dan biarkan tetap Pending
    • jika tampaknya controller yang membinding tetapi PV terikat ke claim lain, kembalikan error dengan status “should never happen”

syncBoundClaim: menangani PVC yang sudah dibinding

  • syncBoundClaim menangani PVC yang memiliki annotation AnnBindCompleted
  • Jika claim sudah dibinding tetapi claim.Spec.VolumeName kosong, status claim diubah menjadi ClaimLost
    • 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.ClaimRef kosong, volume dianggap menjadi unbound dan bind dipanggil lagi
  • Jika ClaimRef.UID milik PV sama dengan UID claim, itu dianggap status binding normal dan bind dipanggil
    • 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

  • syncVolume adalah 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.ClaimRef tidak ada, volume dianggap tidak digunakan dan phase disetel ke Available
  • Jika ClaimRef ada tetapi UID kosong, volume dianggap PV yang dicadangkan untuk PVC tertentu dan phase disetel ke Available
    • 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 Released dan reclaimVolume dijalankan
    • jika phase sebelumnya Failed, nilainya tidak ditimpa
    • jika reclaim policy adalah Retain, dicatat log bahwa PV mereferensikan claim yang tidak ada

Saat koneksi PV dan PVC tidak selaras

  • Jika claim ada tetapi claim.Spec.VolumeName kosong, berarti PVC belum memiliki nama PV
  • Jika volumeMode tidak cocok, event VolumeMismatch dicatat pada kedua sisi PV dan PVC, lalu syncClaim dilewati
  • Jika bukan mismatch, claim dimasukkan ke claimQueue agar syncClaim segera dipanggil
    • pendekatan ini mempercepat binding untuk volume yang diprovision
  • Jika Spec.VolumeName claim sama dengan nama volume saat ini, itu dianggap binding normal dan phase volume diperbarui ke Bound
  • Jika claim dibinding ke volume lain, penanganannya bergantung pada situasi
    • jika volume diprovision secara dinamis dan reclaim policy-nya Delete, tandai Released dan jalankan reclaimVolume
    • jika volume dibinding oleh controller, rapikan dengan unbindVolume
    • jika pointer dibuat oleh pengguna, biarkan sebagaimana adanya tetapi panggil unbindVolume untuk memperbarui phase dan mengosongkan ClaimRef.UID

Pembaruan status dan penerbitan event

  • updateClaimStatus menyimpan 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 VolumeAttributesClass aktif, CurrentVolumeAttributesClassName disetel 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
  • updateClaimStatusWithEvent dan updateVolumePhaseWithEvent hanya menerbitkan event ketika status/phase benar-benar berubah

Penetapan StorageClass default

  • assignDefaultStorageClass mencari 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.StorageClassName lalu diperbarui ke API server

Cakupan file dan batasan eksplisit

  • Berdasarkan metadata file yang ditampilkan di halaman GitHub, pv_controller.go berukuran 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

 
GN⁺ 2024-08-07
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 if yang sangat bersarang. Bagian itu jelas saya rasa akan saya jadikan cabang early return
      Rasanya 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 if memiliki komentar else pasangannya tampaknya tidak selalu benar. Banyak if yang tidak punya pasangan hanyalah pemeriksaan sederhana if (err != nil) { atau early return lain, tetapi bahkan setelah mengecualikan itu, tampaknya masih ada if tanpa pasangan
      Namun, berdasarkan pengalaman perangkat lunak enterprise, komentar tambahan juga tidak selalu banyak. Di codebase memang ada komentar // end if seperti wabah, tetapi komentar penjelasan yang sebenarnya jarang

  • Artikel 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

    • Saya penasaran apa tepatnya arti "tiga versi terakhir masing-masing 420 ribu baris dan memiliki satu kesalahan". Kalau masing-masing dari tiga versi itu punya tepat satu bug, bukankah itu cara aneh untuk mengatakan bahwa dua perbaikan sebelumnya tidak bekerja atau memasukkan bug baru?
    • Akan menarik membandingkan bagaimana metode NASA berbeda dari metode SpaceX. SpaceX juga sudah menjalankan misi berawak, jadi persyaratannya tampak cukup mirip
    • 5000 / 17 ≈ 295. Apakah adil jika diasumsikan bahwa program komersial dengan kompleksitas yang sama menghabiskan 295 kali lebih sedikit person-hour?
    • Masalah metodologi pengembangan Space Shuttle adalah biayanya luar biasa mahal dan lambat, tetapi tetap tidak 100% bebas bug
      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
    • Ini salah satu artikel favorit saya. Menakjubkan bahwa tulisan internet dari tahun 1996 masih bisa diakses
  • 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 lagi
    Kira-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

      Singkatnya, sistem dan sikap pemeriksaan perangkat lunak komputer berada pada kualitas tertinggi. Tidak terlihat proses menipu diri sendiri secara perlahan dengan menurunkan standar, yang menjadi ciri pada sistem keselamatan Solid Rocket Booster atau Space Shuttle Main Engine.

      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...

    DO-178B. Ini adalah standar kualitas untuk produk penerbangan yang kritis terhadap keselamatan... Pengujian harus membuat setiap operasi percabangan dalam kode biner hasil akhir dieksekusi setidaknya sekali, dan dilewati setidaknya sekali... Butuh satu tahun dengan 60 jam kerja per minggu... Itu menghasilkan perbedaan yang luar biasa. Selama 8–9 tahun setelahnya, praktis tidak ada bug

  • Bagian ini mengingatkan saya pada pemeriksaan kelengkapan dalam kode TypeScript. Saya selalu berusaha memakainya
    https://www.typescriptlang.org/docs/handbook/2/narrowing.htm...

    • satisfies never yang lebih baru sangat bagus untuk kegunaan ini. Juga praktis jika, karena selera, Anda memakai rantai if else

    • Anda mungkin juga menyukai ts-pattern

      https://github.com/gvergnaud/ts-pattern

  • Kalau hanya melihat kasus penambahan else eksplisit pada setiap if yang sama sekali tidak sepele, saya penasaran seberapa sederhananya kode ini jika para penulis Kubernetes merancangnya dengan berpusat pada structural pattern matching, alih-alih blok if/else
    Banyak 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 if bertingkat 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 penggunaan nil yang tidak perlu. Bahkan tanpa masuk ke masalah yang lebih dalam seperti coupling atau prinsip tanggung jawab tunggal, hal-hal ini sudah tampak di permukaan

    • Jika 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.

Komentar adalah bagian dari kode dan codebase. Jika Anda memperbaiki kode di sekitarnya tetapi tidak ikut memperbarui komentarnya, itu berarti Anda memasukkan bug dokumentasi ke dalam kode. Hanya karena compiler tidak memprosesnya, bukan berarti itu bukan bagian fungsional. Pada dasarnya, komentar adalah pengetahuan dan catatan riset yang tertanam di dalam kode, dan saat memelihara kode yang ditulis, komentar bisa lebih berharga daripada kode yang dieksekusi.

Best practice bukanlah hukum atau aturan ketat, melainkan panduan. Terapkan saat cocok dengan codebase, jangan mengikutinya secara membabi buta hingga menghasilkan codebase bermasalah. Terkadang aturan perlu dilenturkan dan dibuat sendiri; jika Anda tahu apa yang sedang Anda lakukan, itu sepenuhnya dapat diterima.
  • 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 else eksplisit ke setiap blok if membuat kompleksitas untuk mengingat konteks saat ini meledak. Menurut saya, aturan ini lebih masuk akal jika diubah menjadi "setiap blok kondisi if melakukan early return, atau memiliki blok else pasangannya". Pola if (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.

    • Filosofi Go pada dasarnya lebih dekat dengan menuliskan semuanya secara gamblang, seolah-olah memindahkan kode yang biasanya ditulis dalam C secara cukup langsung, dan tidak berusaha mengabstraksikan sesuatu.