2 puan yazan GN⁺ 2024-08-07 | 1 yorum | WhatsApp'ta paylaş
  • 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 if için karşılık gelen bir else koyar 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.VolumeName ile pv.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, Kubernetes persistentvolume paketindeki PersistentVolumeController uygulama dosyasıdır
  • Bu controller, PersistentVolumeClaim ile PersistentVolume durumlarını uyumlu hale getirir
    • PersistentVolume değişikliklerini izleyen cache controller’ı
    • PersistentVolumeClaim değ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 if ifadesi için karşılık gelen bir else bulunduran 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

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 style korunmalı 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
  • 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.ClaimRef değiştirilir
    • Ardından PVC.Spec.VolumeName değiştirilir
  • 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 persistentVolumeOrderedIndex
    • claims 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.Spec güncellemesi
    • volume.Status güncellemesi
    • claim.Spec güncellemesi
    • claim.Status gü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
    • claimQueue
    • volumeQueue
  • 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 AnnBindCompleted annotation’ının varlığına göre dallanır
    • annotation yoksa syncUnboundClaim
    • annotation varsa syncBoundClaim
  • 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 DeletionTimestamp varsa hata
    • PV kapasitesi PVC’nin istediği kapasiteden küçükse hata
    • storageClassName farklıysa hata
    • VolumeAttributesClass feature gate’i açıksa VolumeAttributesClassName eşleşmesi kontrol edilir
    • Feature gate kapalıyken claim veya volume üzerinde VolumeAttributesClassName varsa hata
    • volumeMode uyumlu değilse hata
    • Access mode uyumlu değilse hata
  • Tüm koşullardan geçerse nil dö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 WaitForPodScheduled olarak 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.VolumeName boşsa, kullanıcı belirli bir PV istememiş durumdadır
  • Bu durumda controller claim’in gecikmeli bağlama modunu kontrol eder ve findBestMatchForClaim ile 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 provisionClaim ile dinamik provisioning denemesi yapar
    • Aksi halde kullanılabilir PV de StorageClass da olmadığını belirten FailedBinding event’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 syncClaim bağlamayı tamamlar

Belirli bir PV isteyen PVC’nin işlenmesi

  • claim.Spec.VolumeName boş değilse, kullanıcı belirli bir PV istemiş durumdadır
  • İstenen PV cache’te yoksa PVC durumu Pending olarak güncellenir ve daha sonra yeniden denenir
  • İstenen PV varsa ve volume.Spec.ClaimRef yoksa, PV henüz claim edilmemiş durumdadır
    • checkVolumeSatisfyClaim ile gereksinimler kontrol edilir
    • Gereksinimleri karşılamıyorsa VolumeMismatch event’i kaydedilir ve PVC Pending kalı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 FailedBinding event’i kaydedilir ve Pending bı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

syncBoundClaim: Zaten bağlanmış PVC’nin işlenmesi

  • syncBoundClaim, AnnBindCompleted annotation’ı olan PVC’leri işler
  • Zaten bağlı bir claim’de claim.Spec.VolumeName boşsa claim durumu ClaimLost olarak 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 ClaimLost olarak değiştirilir
    • Event mesajı, bound claim’in PersistentVolume’u kaybettiğini ve verinin kaybolduğunu belirtir
  • PV var ama volume.Spec.ClaimRef yoksa volume’un unbound duruma geldiği kabul edilir ve yeniden bind çağrılır
  • PV’nin ClaimRef.UID değeri claim’in UID’siyle aynıysa normal bağlama durumu kabul edilir ve bind ç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 Lost olarak 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.ClaimRef yoksa kullanılmayan volume olarak kabul eder ve phase’i Available yapar
  • ClaimRef var ama UID boşsa belirli bir PVC için ayrılmış PV olarak kabul eder ve phase’i Available yapar
    • İ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, ClaimRef iç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 Released yapılır ve reclaimVolume çalıştırılır
    • Mevcut phase Failed ise üzerine yazılmaz
    • Reclaim policy Retain ise var olmayan bir claim’e referans veren PV olduğuna dair log bırakılır

PV ile PVC bağlantısı uyuşmadığında

  • Claim mevcut ama claim.Spec.VolumeName boşsa PVC henüz PV adını almamış durumdadır
  • volumeMode uyuşmuyorsa hem PV hem PVC tarafında VolumeMismatch event’i kaydedilir ve syncClaim atlanır
  • Mismatch yoksa claim, claimQueue’ya eklenerek syncClaim’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.VolumeName değeri mevcut volume adıyla aynıysa normal bağlama kabul edilir ve volume phase’i Bound olarak 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 Delete ise Released olarak işaretlenir ve reclaimVolume çalıştırılır
    • Controller’ın bağladığı volume ise unbindVolume ile 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çin unbindVolume çağrılır

Durum güncelleme ve event yayımlama

  • updateClaimStatus, PVC status’unu API sunucusuna kaydeder
    • Phase değişikliği
    • Volume yokken AccessModes, Capacity, CurrentVolumeAttributesClassName sıfırlama
    • Volume varken access mode, capacity ve current volume attributes class adını güncelleme
  • Claim’in Bound olduğ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
  • VolumeAttributesClass feature gate’i açıksa, pending’den bound’a geçiş sırasında CurrentVolumeAttributesClassName ayarlanır
    • Daha sonra bunu resizer veya admin override ele almalıdır; controller sürekli ayarlarsa race condition olasılığı oluşur
  • updateClaimStatusWithEvent ve updateVolumePhaseWithEvent, 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 false döndürür
  • Varsayılan class varsa claim.Spec.StorageClassName alanı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.go 2038 satır, 1864 LOC, 91 KB boyutundadır
  • Sağlanan metin, dosyanın başından bindVolumeToClaim fonksiyonunun 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

 
GN⁺ 2024-08-07
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ş if blokları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 if için karşılık gelen bir else yorumu olduğu açıklaması her durumda doğru gibi görünmüyor. Karşılığı olmayan iflerin önemli bir kısmı basit if (err != nil) { kontrolleri ya da başka erken dönüşler, ama bunları çıkarsak bile karşılığı olmayan ifler var gibi.
      Öte yandan kurumsal yazılım deneyimime göre ek yorumlar o kadar da çok değildi. Kod tabanında // end if yorumları 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.

    • "Son üç sürümün her biri 420 bin satırdı ve her birinde birer hata vardı" tam olarak ne demek, merak ediyorum. Üç sürümün her birinde tam olarak bir bug varsa, bu önceki iki düzeltmenin işe yaramadığı ya da yeni bir bug eklediği anlamına gelen tuhaf bir ifade değil mi?
    • NASA yaklaşımıyla SpaceX yaklaşımının nasıl farklı olduğunu karşılaştırmak ilginç olurdu. SpaceX de insanlı görevler yaptığına göre gereksinimler oldukça benzer görünüyor.
    • 5000 / 17 ≈ 295. Aynı karmaşıklıktaki ticari bir programın 295 kat daha az kişi-saat harcadığını varsaymak adil olur mu?
    • Space Shuttle geliştirme metodolojisinin sorunu, inanılmaz pahalı ve yavaş olmasına rağmen %100 bugsız olmaması.
      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.
    • En sevdiğim yazılardan biri. 1996’dan kalma bir internet yazısının hâlâ erişilebilir olması şaşırtıcı.
  • // 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:

      Özetle, bilgisayar yazılımı kontrol sistemi ve bu konudaki tutum en yüksek kalitededir. Solid Rocket Booster ya da Space Shuttle Main Engine güvenlik sistemlerinde tipik olarak görülen, standartları düşürürken yavaş yavaş kendini kandırma süreci burada görülmez.

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

    DO-178B. Güvenlik açısından kritik havacılık ürünleri için kalite standardıdır... Testler, ortaya çıkan ikili koddaki her dal işlemının en az bir kez çalıştırılmasını ve en az bir kez geçilmesini sağlamalıdır... Haftada 60 saat çalışarak 1 yıl sürdü... Muazzam bir fark yarattı. Sonraki 8-9 yıl boyunca fiilen hiç hata olmadı

  • 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 never bunun için çok iyi. Tercih olarak if else zinciri kullandığınız durumlarda da kullanışlı

    • ts-pattern hoşunuza gidebilir

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

  • Tamamen önemsiz olmayan her if için açık bir else ekleme durumu özelinde bakarsak, Kubernetes yazarları if/else blokları yerine yapısal pattern matching etrafında tasarlamış olsaydı bu kodun ne kadar basitleşeceğini merak ediyorum
    Yapı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 if iç 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. Gereksiz nil kullanı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üyor

    • Bunları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.

Yorumlar, kodun ve kod tabanının bir parçasıdır. Çevredeki kodu düzeltirken yorumları da birlikte güncellemezseniz, koda bir dokümantasyon hatası eklemiş olursunuz. Derleyici tarafından işlenmiyor diye işlevsel bir parça olmadığı anlamına gelmez. Özünde yorumlar bilgidir; kodun içine gömülmüş araştırma notlarıdır ve yazdığınız kodun bakımını yaparken çalışan koddan daha değerli olabilir.

En iyi uygulamalar yasa ya da katı kurallar değil, yönergelerdir. Kod tabanına uyduklarında uygulanmalıdır; körü körüne izlenip sorunlu bir kod tabanı yaratılmamalıdır. Bazen kuralları esnetmek ve kendi yolunuzu çizmek gerekir; ne yaptığınızı biliyorsanız bu tamamen kabul edilebilir.
  • 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 if bloğuna açık bir else eklemek, mevcut bağlamı akılda tutma karmaşıklığını patlatıyor. Bu kuralı “Her if koşul bloğu ya erken dönüş yapar ya da karşılık gelen bir else bloğ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 if blokları 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.

    • Go’nun ideolojisi temelde, C ile yazacağınız kodu bir ölçüde doğrudan aktarıyormuş gibi her şeyi açık açık yazmaya ve bir şeyleri soyutlamaya çalışmamaya yakındır.