Bu Kodu Sadeleştirmeyin
(github.com/kubernetes)- Kubernetes’teki
pv_controller.go, PV/PVC bağlamayı senkronize eden bir controller’dır; dosyanın en başından itibaren “sadeleştirmeyin, space shuttle style’ı koruyun” diye kesin biçimde uyarır - Bu stil, her
ifiçin karşılık gelen birelsekoyar ve bariz görünen koşulları bile yorum olarak bırakarak, incelenmiş dalları ve niyeti kod içinde görünür kılmayı amaçlar - Tasarımın merkezinde
pvc.Spec.VolumeNameilepv.Spec.ClaimRefüzerinden kurulan çift yönlü işaretçiler yer alır; transactionsız bir ortamda yarış, silme, kullanıcı değişiklikleri ve eşzamanlı bağlamaları kurtarılabilir şekilde ele alır - Controller; PV/PVC değişiklik izleme, iç cache, tek worker’lı queue, event kaydı, dinamik provisioning ve CSI migration arayüzlerini birleştirerek bağlama durum geçişlerini yönetir
- Uzun dallanmalar ve yorumlar, davranışın iş alanı bilgisini ve hata kurtarma bağlamını korumaya yarayan bir mekanizmadır; bu yüzden gelecekteki değişiklikler de aynı stili izlemelidir
pv_controller.gonun rolü ve yazım ilkeleri
pv_controller.go, Kubernetespersistentvolumepaketindeki PersistentVolumeController uygulama dosyasıdır- Bu controller,
PersistentVolumeClaimilePersistentVolumedurumlarını uyumlu hale getirirPersistentVolumedeğişikliklerini izleyen cache controller’ıPersistentVolumeClaimdeğişikliklerini izleyen cache controller’ı- İki nesnenin değişiklik event’lerine dayanarak PV/PVC durum senkronizasyonu
- Dosyanın başındaki yorumlar, bu kodu sadeleştirmeyin diye tekrar tekrar uyarır
- Stil adı
space shuttle style - Her
ififadesi için karşılık gelen birelsebulunduran bir yaklaşımdır - Basit hata kontrolleri dışında tüm dalları açıkça belirtmeyi amaçlar
- Bariz görünen davranışları bile yorum olarak yazarak bakım yapanların bağlama karmaşıklığını takip edebilmesini sağlar
- Stil adı
space shuttle styleın korunma nedeni
- Bu controller, aslında üç ayrı controller’a bölünmüş işleri tek bir yerde birleştirmenin sonucudur
- PV alt sistemini sadeleştirme sürecinde, tüm koşulları kodda açıkça ele alan bir yaklaşıma ihtiyaç duyulmuştur
- Bunun sonucu olarak kod uzun, yorumları ve dalları fazla görünebilir
- Bu uzunluk, bağlama davranışının iş alanı bilgisini ve bağlamını kodda bırakmaya yarayan bir mekanizmadır
- Bu dosyayı değiştirirken
space shuttle stylekorunmalı ve gerekirse aynı yaklaşımla yeni dallar ve yorumlar eklenmelidir
Temel tasarım: PV ile PVC’nin çift yönlü işaretçileri
- Tasarımın merkezinde PV ile PVC arasında çift yönlü işaretçiler bulunur
- PVC tarafındaki işaretçi:
pvc.Spec.VolumeName - PV tarafındaki işaretçi:
pv.Spec.ClaimRef
- PVC tarafındaki işaretçi:
- Bu çift yönlülük, transaction olmayan sistemlerde yönetmesi zordur; ancak arıza durumlarında da doğru çalışmayı garanti etmek için gereklidir
- Rogue HA controller instance bir yarış durumu oluşturursa, ayırt edilemeyen birden fazla bağlama ortaya çıkabilir ve veri kaybı olasılığı doğabilir
- Controller varsayılan olarak active-passive yüksek erişilebilirlik modunda çalışacak şekilde tasarlanmıştır
- Nesne geçişleri active-active HA’da da çalışabilecek şekilde tasarlanmıştır
- Ancak iki active controller sık sık çakışırsa performans düşebilir
Bağlama yöntemi ve kurtarma koşulları
- Controller, çift yönlü pre-bound nesneleri destekler
- Belirli bir PV isteyen PVC
- Belirli bir PVC için ayrılmış PV
- Bağlama iki aşamada ilerler
- Önce
PV.Spec.ClaimRefdeğiştirilir - Ardından
PVC.Spec.VolumeNamedeğiştirilir
- Önce
- Bu sürecin herhangi bir anında PV veya PVC, kullanıcı ya da başka bir controller tarafından değiştirilebilir veya silinebilir
- İki ya da daha fazla controller, farklı volume’ları ve claim’leri aynı anda bağlamaya çalışabilir
- Controller’ın bu çakışma durumlarını kurtarabilmesi gerekir
Controller yapısının ana bileşenleri
PersistentVolumeController, PV/PVC senkronizasyonu için gereken lister’ları, informer sync fonksiyonlarını, Kubernetes client’ını, event recorder’ını, volume plugin yöneticisini ve benzerlerini içerir- Bilinen son PV/PVC sürümleri iç cache’te tutulur
volumes persistentVolumeOrderedIndexclaims cache.Store
- Bu cache, API sunucusuna kaydedilen en yeni sürüm ile etcd event’leri üzerinden gelen sürümü birlikte yansıtır
- Tek bir bağlama yaklaşık dört event oluşturabilir
volume.Specgüncellemesivolume.Statusgüncellemesiclaim.Specgüncellemesiclaim.Statusgüncellemesi
- İç cache olmazsa, informer eski bir durumu tutarken zaten tamamlanmış bir bağlamayı yeniden düzeltmeye çalışabilir
- Bu sırada API sunucusuna yeniden yazma denenirse, zaten kaydedilmiş nesneyle sürüm çakışması yaşanabilir
Work queue ve eşzamanlılık kısıtları
- Controller, claim ve volume işlemek için ayrı workqueue’lara sahiptir
claimQueuevolumeQueue
- Her queue’nun tam olarak bir worker thread’i olmalıdır
- Özellikle
syncClaim()yeniden girişli değildir - İki
syncClaim()aynı anda çalışırsa şu sorunlar ortaya çıkabilir- İki farklı claim’i aynı volume’a bağlamak
- Bir claim’i iki volume’a bağlamak
- Controller, API sunucusunun sürüm hataları ve kendi kontrolleriyle bu durumları kurtarabilir; ancak multi-worker yaklaşımı toplam hızı düşürebilir
syncClaim: PVC senkronizasyonunun giriş noktası
syncClaim, claim oluşturulduğunda, güncellendiğinde veya periyodik olarak senkronize edildiğinde çağrılan ana metottur- Bu metot event türünü ayırt etmez
- Önce PVC üzerinde doğru migration annotation’ı ayarlar ve gerekirse API sunucusunda günceller
- Daha sonra
AnnBindCompletedannotation’ının varlığına göre dallanır- annotation yoksa
syncUnboundClaim - annotation varsa
syncBoundClaim
- annotation yoksa
- Asıl işlem, okunabilirlik için unbound claim ve bound claim metotlarına ayrılmıştır
checkVolumeSatisfyClaim: PV gereksinim kontrolü
checkVolumeSatisfyClaim, istenen PV’nin PVC gereksinimlerini karşılayıp karşılamadığını doğrular- Kontrol koşulları kodda açıkça listelenmiştir
- PV’de
DeletionTimestampvarsa hata - PV kapasitesi PVC’nin istediği kapasiteden küçükse hata
storageClassNamefarklıysa hataVolumeAttributesClassfeature gate’i açıksaVolumeAttributesClassNameeşleşmesi kontrol edilir- Feature gate kapalıyken claim veya volume üzerinde
VolumeAttributesClassNamevarsa hata volumeModeuyumlu değilse hata- Access mode uyumlu değilse hata
- PV’de
- Tüm koşullardan geçerse
nildöndürür
Gecikmeli bağlama PVC’si için event işleme
emitEventForUnboundDelayBindingClaim, gecikmeli bağlama modundaki bağlanmamış claim’e bilgi veren bir event oluşturur- Varsayılan reason
WaitForFirstConsumer’dır - Varsayılan mesaj, ilk consumer oluşturulana kadar bağlamanın bekleyeceğini söyler
- Bu PVC’ye referans veren henüz schedule edilmemiş bir Pod varsa reason
WaitForPodScheduledolarak değişir- Birden fazla Pod varsa mesaj tüm Pod adlarını içerir
- Volume scheduling’de yalnızca bir Pod dikkate alınır; ancak hangi Pod’un kullanılacağı bilinmediğinden hepsi dahil edilir
syncUnboundClaim: Henüz bağlanmamış PVC’nin işlenmesi
claim.Spec.VolumeNameboşsa, kullanıcı belirli bir PV istememiş durumdadır- Bu durumda controller claim’in gecikmeli bağlama modunu kontrol eder ve
findBestMatchForClaimile en uygun PV’yi bulur - Uygun PV yoksa aşağıdaki sırayla işlem yapar
- Varsayılan StorageClass atanabiliyorsa PVC’yi günceller ve senkronizasyonu bitirir
- Gecikmeli bağlama söz konusuysa ve henüz provisioning durumunda değilse bekleme event’i oluşturur
- Claim’de StorageClass varsa
provisionClaimile dinamik provisioning denemesi yapar - Aksi halde kullanılabilir PV de StorageClass da olmadığını belirten
FailedBindingevent’ini kaydeder
- Uygun PV varsa PV ile PVC’yi bağlamak için
bindçağrılır- Başarılı olursa provision + binding işinin metric’ini kaydeder ve timestamp cache’ini temizler
- Kaydetme sırasında hata olursa sonraki
syncClaimbağlamayı tamamlar
Belirli bir PV isteyen PVC’nin işlenmesi
claim.Spec.VolumeNameboş değilse, kullanıcı belirli bir PV istemiş durumdadır- İstenen PV cache’te yoksa PVC durumu
Pendingolarak güncellenir ve daha sonra yeniden denenir - İstenen PV varsa ve
volume.Spec.ClaimRefyoksa, PV henüz claim edilmemiş durumdadırcheckVolumeSatisfyClaimile gereksinimler kontrol edilir- Gereksinimleri karşılamıyorsa
VolumeMismatchevent’i kaydedilir ve PVCPendingkalır - Gereksinimleri karşılıyorsa
bindçağrılır
- İstenen PV zaten bu PVC’ye claim edilmişse bağlamayı tamamlamak için
bindçağrılır - İstenen PV başka bir claim’e bağlıysa şu şekilde işlenir
- Claim, controller tarafından bağlandığını gösteren annotation’a sahip değilse
FailedBindingevent’i kaydedilir vePendingbırakılır - Controller tarafından bağlanmış gibi görünüyor ama başka bir claim’e bağlıysa “should never happen” durumu olarak hata döndürülür
- Claim, controller tarafından bağlandığını gösteren annotation’a sahip değilse
syncBoundClaim: Zaten bağlanmış PVC’nin işlenmesi
syncBoundClaim,AnnBindCompletedannotation’ı olan PVC’leri işler- Zaten bağlı bir claim’de
claim.Spec.VolumeNameboşsa claim durumuClaimLostolarak değiştirilir- Event mesajı, bound claim’in PV referansını kaybettiğini ve volume’daki verinin kaybolduğunu belirtir
- Claim’in işaret ettiği PV yoksa yine
ClaimLostolarak değiştirilir- Event mesajı, bound claim’in PersistentVolume’u kaybettiğini ve verinin kaybolduğunu belirtir
- PV var ama
volume.Spec.ClaimRefyoksa volume’un unbound duruma geldiği kabul edilir ve yenidenbindçağrılır - PV’nin
ClaimRef.UIDdeğeri claim’in UID’siyle aynıysa normal bağlama durumu kabul edilir vebindçağrılır- Çoğu durumda hiçbir iş yapmayan bir çağrıdır
- PV başka bir claimant’ı gösteriyorsa claim phase’i terminal durum olan
Lostolarak ayarlanır
syncVolume: PV senkronizasyonunun giriş noktası
syncVolume, volume oluşturulduğunda, güncellendiğinde veya periyodik olarak senkronize edildiğinde çağrılan ana metottur- Event türlerini ayırt etmez
- Önce PV üzerinde doğru migration annotation’ı ve finalizer’ı ayarlar, gerekirse API sunucusunda günceller
volume.Spec.ClaimRefyoksa kullanılmayan volume olarak kabul eder ve phase’iAvailableyaparClaimRefvar ama UID boşsa belirli bir PVC için ayrılmış PV olarak kabul eder ve phase’iAvailableyapar- İlgili PVC henüz bu PV’ye bağlanmamıştır; bunu PVC sync işleyecektir
Claim’i bulamayan PV’nin işlenmesi
- PV bir claim’e bağlıysa controller,
ClaimRefiçindeki namespace/name ile PVC’yi arar - PVC cache’te bulunamazsa belirli koşullarda ek doğrulama yapar
- Informer cache’te yeniden kontrol
- API sunucusunda yeniden kontrol
- Harici PV provisioner veya harici PV binder tarafından oluşturulan PV’lerde, yüksek yük altında PVC henüz yerel cache’e senkronize edilmemiş olabilir
- PVC’yi yanlışlıkla reclaim etmemek için çift doğrulama yapılır
- Claim’in olmadığına karar verilirse volume phase’i
Releasedyapılır vereclaimVolumeçalıştırılır- Mevcut phase
Failedise üzerine yazılmaz - Reclaim policy
Retainise var olmayan bir claim’e referans veren PV olduğuna dair log bırakılır
- Mevcut phase
PV ile PVC bağlantısı uyuşmadığında
- Claim mevcut ama
claim.Spec.VolumeNameboşsa PVC henüz PV adını almamış durumdadır volumeModeuyuşmuyorsa hem PV hem PVC tarafındaVolumeMismatchevent’i kaydedilir vesyncClaimatlanır- Mismatch yoksa claim,
claimQueue’ya eklenereksyncClaim’in kısa süre içinde çağrılması sağlanır- Bu yöntem, provision edilmiş volume’un bağlanmasını hızlandırır
- Claim’in
Spec.VolumeNamedeğeri mevcut volume adıyla aynıysa normal bağlama kabul edilir ve volume phase’iBoundolarak güncellenir - Claim başka bir volume’a bağlanmışsa duruma göre işlenir
- Dinamik olarak provision edilmiş volume ise ve reclaim policy
DeleteiseReleasedolarak işaretlenir vereclaimVolumeçalıştırılır - Controller’ın bağladığı volume ise
unbindVolumeile temizlenir - Kullanıcının oluşturduğu bir işaretçiyse olduğu gibi bırakılır; ancak phase’i güncellemek ve
ClaimRef.UID’yi temizlemek içinunbindVolumeçağrılır
- Dinamik olarak provision edilmiş volume ise ve reclaim policy
Durum güncelleme ve event yayımlama
updateClaimStatus, PVC status’unu API sunucusuna kaydeder- Phase değişikliği
- Volume yokken
AccessModes,Capacity,CurrentVolumeAttributesClassNamesıfırlama - Volume varken access mode, capacity ve current volume attributes class adını güncelleme
- Claim’in
Boundolduğu anda capacity’yi güncelleyen özel bir koşul vardır- PVC filesystem size ile PV block device size arasındaki fark kasıtlı olabilir; bu yüzden zaten bound olan claim’in capacity’sinin üzerine yazılmaz
VolumeAttributesClassfeature gate’i açıksa, pending’den bound’a geçiş sırasındaCurrentVolumeAttributesClassNameayarlanır- Daha sonra bunu resizer veya admin override ele almalıdır; controller sürekli ayarlarsa race condition olasılığı oluşur
updateClaimStatusWithEventveupdateVolumePhaseWithEvent, yalnızca gerçek status/phase değiştiğinde event yayımlar
Varsayılan StorageClass atama
assignDefaultStorageClass, claim’de storage class yokken varsayılan StorageClass’ı bulup atar- Zaten storage class’ı olan claim’leri yok sayar
- Varsayılan class yoksa güncelleme yapmadan
falsedöndürür - Varsayılan class varsa
claim.Spec.StorageClassNamealanına class adını yazar ve API sunucusunda günceller
Dosya kapsamı ve açık sınırlar
- GitHub sayfasında görünen dosya metadata’sına göre
pv_controller.go2038 satır, 1864 LOC, 91 KB boyutundadır - Sağlanan metin, dosyanın başından
bindVolumeToClaimfonksiyonunun başlangıcına kadar olan kısmı içerir; kalanı raw view bağlantısıyla devam eder - Bu nedenle bu özet, sağlanan kod metninde görünen controller yapısı, tasarım yorumları, ana senkronizasyon dalları ve status güncelleme mantığıyla sınırlıdır
1 yorum
Hacker News yorumları
Bu dosyadaki kodun gerçekten sıradan Go kodu gibi hissettirmesinin tuhaf olup olmadığını bilmiyorum. Go olduğu için uzun uzun yazılmış ve derin soyutlamalara dayanmadığı için daha uzun görünüyor, ama kodun kendisi oldukça tipik duruyor.
Soyutlama iki ucu keskin bir kılıç; bu yaklaşım da gayet makul. Başındaki açıklama olmasaydı yazım tarzını ikinci kez düşünmezdim sanırım. Belki de sistem yazılımından çok kurumsal yazılım deneyimim olduğu için böyle hissediyorum. Kubernetes’e düzenli katkı yapan birine bu yorumlar gereksiz görünebilir, ama kurumsal ortamda uzak gelecekte bağlam olmadan okunacak bir kod olsaydı, bu karmaşıklık seviyesinde muhtemelen daha da fazla yorum eklerdim.
Eskiden böyle kodlar normal gelirdi; ama son 10 yıl kadar içinde birçok kişi açıklığı kısalıktan daha az değerli görmeye başladı gibi.
Özellikle böyle kritik kodlarda açıklığı çok daha fazla tercih ederim. Kariyerimde, birden fazla koşulu birleştirip iş bağlamını ve anlamını açıklayan yorumları atlayan kodlar yüzünden mevcut davranışın kasıtlı mı yoksa tesadüf mü olduğunu anlayamadığım birçok durum yaşadım. Bu yaklaşım değişime dayanıklı kod değil, değişimi engelleyen kod üretmeye yatkın; en azından yazarı olmayan birinin değiştirmesini zorlaştırıyor. Gereksiz Chesterton’ın çiti yaratmak sürdürülebilirliğe aykırı.
Bu yorum muhtemelen kodu basitleştirmeye çalışıp başarısız olduktan sonra, gelecekteki bakımcıları aynı şeyi denemeden önce bir kez daha düşünmeleri için uyarmak amacıyla eklenmiş.
Uyarıyı ekleyen commit "Add note about space-shuttle code style"[1]; hemen önceki commit ise "Revert controller/volume: simplify sync logic in syncUnboundClaim"[2] idi.
[1] https://github.com/kubernetes/kubernetes/commit/de4d193d45f6...
[2] https://github.com/kubernetes/kubernetes/commit/8a1baa4d64ca...
Ben de benzer düşünüyordum, ama derin iç içe geçmiş
ifbloklarını görünce fikrim değişti. O kısımda kesinlikle erken dönüş dalları oluştururdum."Çalışır hale getir, hızlı hale getir, güzel hale getir" sözünde sanki sadece ilk adımı bitirip "güzel hale getirme" yapılmamış gibi. Zor durum etkileşimlerini çözerken ben de böyle çirkin ve bol yorumlu kod yazdım, ama genelde incelemeden önce biraz toparlarım. Belki de dosyanın en üstüne "Bu kodu basitleştirmeye çalışmayın" diye büyük bir afiş koymak daha iyi olurdu. Yine de kesinlikle çok kötü değil.
Tuhaf olabilir, ama yalnız değilsin. Bana da bu kod tamamen normal görünüyor. Sistem güvenilirliği açısından kritik olduğunu düşündüğüm bileşenlerde buna benzer kod ve yorumlar kullandığım oldu.
"Yorumsuz kod" modasına hiç katılmadım; aylar ya da yıllar sonra geri döndüğümde kendi yazdığım yorumlar gelecekteki bana fazlasıyla sık biçimde değerli oldu. Bu karmaşıklık düzeyindeki bir bileşenin içine gömülü mantığı sağlam yorumlar olmadan yeniden kurmayı hayal etmek zor.
Özellikle her
ifiçin karşılık gelen birelseyorumu olduğu açıklaması her durumda doğru gibi görünmüyor. Karşılığı olmayaniflerin önemli bir kısmı basitif (err != nil) {kontrolleri ya da başka erken dönüşler, ama bunları çıkarsak bile karşılığı olmayanifler var gibi.Öte yandan kurumsal yazılım deneyimime göre ek yorumlar o kadar da çok değildi. Kod tabanında
// end ifyorumları salgın gibi vardı, ama gerçekten açıklayıcı yorumlar nadirdi.Space Shuttle yazılım kalitesiyle ilgili yazı: https://archive.is/HX7n4
Alıntılayacak olursak, bu yazılımı olağanüstü yapan şey ne kadar çok iş yaptığı değil, ne kadar iyi çalıştığı. Asla çökmediği, yeniden başlatma gerektirmediği, hatasız olduğu ve insanların ulaşabildiği ölçekte mükemmele yakın olduğu söyleniyor. Son üç sürümün her biri 420 bin satırdı ve her birinde yalnızca birer hata vardı; son 11 sürümün tamamındaki hata sayısı 17 idi. Aynı karmaşıklıktaki ticari bir programda yaklaşık 5.000 hata olacağı söyleniyor.
O kadar pahalı ve yavaş ki, modern bir kanıt yardımcısıyla (proof assistant) yazılımın doğruluğunu kanıtlamak çok daha ucuz, hızlı ve fiilen daha güvenli olurdu. seL4, CompCert gibi projeler bunun nasıl yapılacağını gösteriyor.
// KEEP THE SPACE SHUTTLE FLYING.niyetini anlıyorum, ama güvenlik sicili pek iyi olmadığı için artık işletilmeyen bir sistemi yorumda referans almak biraz komik.Yaklaşık 10 yıl sonra insanlar Space Shuttle’ı hâlâ iyi mi hatırlayacak?
Space Shuttle’ın güvenlik sorunları çoğunlukla donanım sorunlarıydı, yazılım sorunları değil.
Richard Feynman’ın 1986 Challenger kazası raporundaki eki olan "Appendix F - Personal Observations on Reliability of Shuttle" [0] şöyle der:
Feynman, avionik yazılım kalitesini özellikle; Shuttle gibi büyük ve karmaşık devlet projelerinin de doğru şekilde mühendislikle geliştirilebileceğine ve doğası gereği düşük kaliteli ya da tehlikeli olmak zorunda olmadığına örnek olarak vurgulamıştı.
0: https://www.nasa.gov/history/rogersrep/v2appf.htm
İnsanları ve ekipmanı 100’den çok daha fazla başarılı görevde uzaya çıkarıp tekrar eve getirdi. Hâlâ olumlu bakıyorum ve gelecekte de muhtemelen öyle bakacağım. İnsanlığın ilerlemesi ve net etkisi açısından bir başarıydı
Shuttle’ı sona erdiren şey kötü bir güvenlik sicili değil, maliyet ve gelecekte güvenliğin düşeceğine dair beklentiydi
İki Shuttle kazasında diğer NASA felaketlerinden daha fazla astronot ölmüş olsa da, fiilen yapılan işlerin zorluğu düşünüldüğünde güvenlik sicili gerçekten şaşırtıcıydı. Kod çok iyi görünüyor
Space Shuttle durumu, basitçe güvenliği kötüydü demekten daha karmaşık. Görev bazında bakıldığında sicili diğer fırlatma araçlarından daha iyi sayılır. Shuttle’da 135 görevden 2’si ölümcüldü; Sovyet dönemi Soyuz’da 66 görevden 2’si, SpaceShipTwo’da ise sadece 12 uçuş içinde 1 ölümcül görev gibi ürkütücü derecede kötü bir sicil var
Ancak Space Shuttle, çoğu görev için gerekenden çok daha büyük bir mürettebat kapasitesine sahipti. Apollo veya Soyuz’daki 3 kişinin aksine en fazla 8 kişi taşıyabiliyordu; Sovyet/Roscosmos, ESA ve CNSA görevlerinin çoğunun tamamen insansız otonom görevler olduğu düşünülürse, tehlikeye atılacak mürettebat zaten yoktu. Belki bu benzetme Kubernetes’e daha çok uyuyordur. Yüksek mühendislik ürünü, güçlü ve çok amaçlı; ama çok dikkat isteyen ve muhtemelen ihtiyaç olandan biraz fazla kullanılan bir sistem
En yaygın ölçüt olan yolcu-mil başına bakıldığında, Space Shuttle bugüne kadar yapılmış ve uçmuş en güvenli araçlardan biri sayılır
Çocukluğu tam olarak 1980’lere denk gelen biri olarak içtenlikle soruyorum: Bunu iyi hatırlamamak nasıl mümkün, bilmiyorum. Bu programı ve tüm görevlerini/başarılarını yalnızca geriye dönük olarak görecek kadar genç olup, bugünkü özel uzay yüklenicileri merkezli çağın havasıyla şekillenmiş bir bakış açısına mı sahipsiniz?
Richard Hipp’in SQLite kodunu havacılık standartlarına uyarlama hikâyesi de epey ilginç: https://corecursive.com/066-sqlite-with-richard-hipp/#testin...
Bu bölüm TypeScript kodunda exhaustiveness checking’i akla getiriyor. Her zaman kullanmaya çalışıyorum
https://www.typescriptlang.org/docs/handbook/2/narrowing.htm...
Daha yeni
satisfies neverbunun için çok iyi. Tercih olarakif elsezinciri kullandığınız durumlarda da kullanışlıts-patternhoşunuza gidebilirhttps://github.com/gvergnaud/ts-pattern
Tamamen önemsiz olmayan her
ifiçin açık birelseekleme durumu özelinde bakarsak, Kubernetes yazarlarıif/elseblokları yerine yapısal pattern matching etrafında tasarlamış olsaydı bu kodun ne kadar basitleşeceğini merak ediyorumYapısal pattern matching’i destekleyen birçok ana akım dilde, eşleşmenin eksiksiz olup olmadığını derleme zamanında kontrol eden araçlar var; sırf bu bile kodun bilgi yoğunluğunu artırırken deyimsel bir çözüm olabilir
2018’deki tartışma: https://news.ycombinator.com/item?id=18772873
Kodu yalnızca kabaca gözden geçirdim ama açıkçası o kadar kötü görünmüyor. Farklı yapacağım yerler olurdu, ama çok daha kötü kodlar gördüm
En azından bu kod tek bir kuralı izliyor; her şey düşünülerek yazılmış ve bu karmaşanın içinde kendine göre bir yöntem olduğu izlenimi veriyor. Defalarca gördüğüm stil karışıklıkları, tembel kodlama ve mantıksız yapı gibi tipik yamalı bohçalara karşı her zaman böyle bir kodu tercih ederim
“Güvenlik” pratiklerini yeniden icat ederken belgelenmiş yazılım mühendisliği en iyi uygulamalarının neden görmezden gelindiğini merak ediyorum
2.000 satırlık modüller, 200 satırlık metotlar ve 3-4 seviyeli
ifiç içeliği zararlı kabul edilir. Nedenini değil de yalnızca ne yaptığını söyleyen yorumlar da faydalı değildir ve gerçek kodla çelişmeye yatkındır. Gereksiznilkullanımı da görünüyor. Bağlılık ya da tek sorumluluk ilkesi gibi daha derin sorunlara girmeden, yüzeyde bile bunlar görülüyorBunların zararlı olduğunu düşünüyorsanız “John Carmack on Inlined Code” yazısını okumanızı öneririm
http://number-none.com/blow/john_carmack_on_inlined_code.htm...
“Armadillo roketinin uçuş kontrol kodu yalnızca birkaç bin satırdı, bu yüzden ana tic fonksiyonunu alıp tüm alt yordamları inline etmeye başladım. Gerçek bir düşüşe neden olabilecek gizli bir hata bulduğumu söyleyemem, ama birkaç kez ayarlanan bazı değişkenler ve biraz şüpheli görünen birkaç kontrol akışı buldum; nihai kod daha küçük ve temiz oldu.”
Carmack bu yaklaşımda değer gördüyse, bence aceleyle göz ardı edilmemeli. Devam yorumları da okumaya değer
“Bu yazıyı yazdıktan sonraki birkaç yıl içinde, C/C++’ta bile makul sınırlar içinde saf fonksiyonel programlamaya çok daha olumlu bakar oldum... Baş edilemeyecek hâle gelirse blokları saf fonksiyonlara ayırmanın bir yolunu bulun”
Bazen “başka yolu yok(TM)” durumu olur
Keyfi satır sayısı sınırları gereksiz parçalanmaya yol açmaya yatkındır. include’lar, lisanslar, yapıştırıcı kod ve yorumlar da eklenince yaklaşması zor bir spagettiye dönüşür. Yüksek performanslı kodda metotları 200 satırda tutmaya çalışırsanız, performans İkaros’un uçuşu gibi çakılabilir
Kodun yorumlarını okuduğunuzda, bu kodu tek bir modüle sadeleştirdiklerini; erişilebilir ve daha da önemlisi sürdürülebilir kılmak için içine muazzam miktarda know-how koyduklarını görebilirsiniz. Dili ya da mantığı bilmeyen biri için, kodun ne yaptığının genel hatlarını veren yorumlar çok yararlıdır. 6 ay sonra insanın kendi kodu bile yabancılaştığı için, kişinin kendisi için de yararlıdır.
Uzun süre bu tür “güvenli” bir tarzda yazmayı denedim, ama erken dönüş ile yapılan demiryolu tarzı hata işlemeye kıyasla çok daha fazla bug ürettim ve bunları düzeltmek de çok daha uzun sürdü
Her
ifbloğuna açık birelseeklemek, mevcut bağlamı akılda tutma karmaşıklığını patlatıyor. Bu kuralı “Herifkoşul bloğu ya erken dönüş yapar ya da karşılık gelen birelsebloğuna sahiptir” şeklinde değiştirmek bence mantıklı.if (cond) { özel işlem }kalıbı, erken dönüşe göre kesinlikle çok daha tehlikeli ve akıl yürütmesi daha zor hale getiriyor.Tek bir resmî en iyi uygulamalar paketi diye bir şey yoktur
Fonksiyon uzunluğu ya da bir dosyadaki kod satırı sayısı kendi başına ne zararlıdır ne de faydalı. Her dilin kodun nasıl düzenlenmesi gerektiğine dair bir bakış açısı vardır, ama bunların hiçbiri “en iyi uygulama” olduğunu iddia edemez. Go, kodu çok sayıda küçük dosyaya bölmeyi tercih eden bir dil değildir.
200 satırlık bir metod doğası gereği yanlış değildir. İçindeki kod doğrusal ilerliyor ve aynı soyutlama seviyesini koruyorsa en iyi tercih olabilir
Alternatif olarak 40 tane 5 satırlık metod oluşturmak daha kötü olabilir. Bütünü anlamak için oradan oraya zıplamanız gerekir ve çağrı sırasını da bozabilirsiniz. Seçilebilir permütasyon sayısı 40! kadardır.
Bu tür kod, deklaratif, kural tabanlı, tablo güdümlü bir sisteme taşımak için ideal bir aday gibi görünüyor
Böyle bir yaklaşım, geçici çözümlerle dolu imperatif
ifblokları yığınından daha anlaşılır ve doğrulanması daha kolaydır. Bu tür dağınık kod genellikle eksik bir soyutlamanın işaretidir.