- Bağımlılıklar ücretsiz özellikler gibi görünür, ancak gerçekte çeşitli maliyetler ve karmaşıklıklar getirir
- Yanlış bir bağımlılık; öğrenme eğrisi, ani arayüz değişiklikleri, dağıtım ve kurulum sorunları gibi çeşitli riskler doğurur
- Temsili bir örnek olarak TigerBeetle, güvenlik, performans ve operasyonel sadelik için "sıfır bağımlılık" politikasını benimser
- Yazar, bir bağımlılık değerlendirme çerçevesi (yaygınlık, kararlılık, derinlik, kullanılabilirlik, bütünlük) önerir
- İyi bağımlılıkla kötü bağımlılığı ayırt etmek için eleştirel düşünme ve bağımlılık seçerken yalnızca kısa vadeli üretkenliği değil toplam maliyet ve riski de hesaba katan dikkatli bir yargı şarttır
NIH (Not Invented Here)'den daha pahalı olan şey yanlış bağımlılıktır
Bağımlılıkların dezavantajları ve gizli maliyetleri
- Birçok geliştirici bağımlılık eklemeyi "bedava özellik" gibi görür, ancak gerçekte şu maliyetler ortaya çıkar
- Öğrenmek için gereken zaman ve karmaşıklık
- Bağımlılığın kurulmasının kendisi de sık sık zor olabilir
- Büyük sürüm yükseltmelerinde kendi kodumuzu da önemli ölçüde değiştirme yükü
- Sonuçta bağımlılığın dağıtım/kurulum ortamında mutlaka bulunması gerekir ve bu da karmaşıklık yaratır (container, bundling vb.)
- Yanlış bir bağımlılığın benimsenmesi, çekirdek işleve doğrudan bağlı olmayan karmaşık dağıtım yapıları da oluşturabilir
TigerBeetle'ın sıfır bağımlılık ilkesi
- TigerBeetle, Vanilla Zig tabanlı bir finans veritabanıdır ve sıfır bağımlılık politikası benimser
- Yalnızca Zig diliyle geliştirilir ve Zig toolchain'i dışında harici bağımlılık bulundurmaz
- Amaç; bağımlılıkların yol açtığı tedarik zinciri saldırısı riski, performans düşüşü ve kurulum süresinin uzaması gibi sorunlardan kaçınmaktır
- Yazılım altyapıya ne kadar derin yerleşmişse, bağımlılıklardan doğan maliyet tüm stack boyunca o kadar büyür
- Standartlaştırılmış küçük bir araç kutusunun kullanımı bakım ve geliştirme verimliliği açısından avantajlıdır
- Zig ile yeni sorunları hızlıca ele almaya ve karmaşıklığı azaltmaya odaklanır
Bağımlılık değerlendirme çerçevesi
- Tüm geliştiriciler tam anlamıyla bağımsız olmanın imkânsız olduğunu kabul etse de, bağımlılıkların dikkatle değerlendirilmesi gerektiği vurgulanır
- Yazar, bağımlılıkları şu 5 ölçütle değerlendirmeyi önerir
- Yaygınlık (Ubiquity): Hedef ortamda ne kadar yaygın bulunuyor? Ayrı dağıtım/kurulum gerekiyor mu?
- Kararlılık (Stability): Geriye dönük uyumluluk, API değişim sıklığı, desteğin kesilmesi gibi sorunlar ne kadar sık yaşanıyor?
- Derinlik (Depth): API'nin altında gizlenen gerçek işlev miktarı ne kadar? Bunu doğrudan kendin uygulaman ne kadar zor?
- Kullanılabilirlik (Ergonomics): API sezgisel/deklaratif ve kullanımı kolay mı, belgeleri ne durumda?
- Bütünlük (Watertightness): Soyutlama ne kadar iyi çalışıyor, alttaki teknolojiyle ne kadar az uğraşman gerekiyor?
- Geliştirici topluluğu çoğunlukla yalnızca kullanılabilirliği tartışıyor; diğer dört unsur ise sık sık göz ardı ediliyor
İyi bağımlılık örnekleri
-
POSIX sistem çağrıları
- Evrensellik: Linux, Android, macOS, BSD gibi neredeyse tüm platformlarda kullanılabilir
- Kararlılık: Arayüz uyumluluğu çok yüksektir ve neredeyse hiç değişmez
- Derinlik: Tek bir API, yüz binlerce satırlık çekirdek kodunu gizler
- Kullanılabilirlik: Biraz geleneksel C stili olsa da kullanımı ciddi sorun yaratmaz
- Bütünlük: Çoğunlukla sorunsuzdur, ancak depolama aygıtlarında verinin kalıcılığı gibi ayrıntılı konular vardır
-
ECMA-48 terminal kontrol kodları
- Evrensellik: Windows'taki cmd.exe dışında çoğu terminal tarafından desteklenir
- Kararlılık: 1991'den beri değişmemiştir
- Derinlik: Böyle bir standardı doğrudan oluşturmak son derece zordur
- Kullanılabilirlik: Esc karakterinin yarattığı okunaksızlık dışında makuldür
- Bütünlük: Donanım bağımlılığı konusunda endişe çok azdır
-
Web platformu (Web API, HTML, JS, CSS vb.)
- Evrensellik: Web tarayıcıları dünyanın neredeyse her ortamında kurulu durumdadır
- Kararlılık: Güçlü geriye dönük uyumluluk politikaları vardır
- Derinlik: Kendi tarayıcını üretmek pratikte imkânsıza yakın olacak kadar derindir
- Kullanılabilirlik: Bir miktar karmaşıklık olsa da dokümantasyon ve geliştirme araçları güçlüdür
- Bütünlük: Dosya, ses, video gibi istisnai durumlar dışında oldukça yüksek bütünlük sunar
Sonuç
- Kopyala-yapıştır ve bağımlılıkların aşırı kullanımı yerine eleştirel düşünme ve toplam maliyet analizi şarttır
- Bağımlılık eklerken her bağımlılığın maliyetini ve faydasını eleştirel biçimde değerlendirmek,
ayrıca tüm sistemin potansiyel risklerini ve maliyetlerini de mutlaka hesaba katarak dikkatli seçim yapmak uzun vadede çok daha ucuz ve güvenlidir
2 yorum
TigerBeetle: muhasebeye özel OLTP veritabanı
Hacker News görüşü
TigerBeetle diye bir örneği ilk kez duydum, o yüzden gidip kendim baktım. Eğer güvenlik ve performansın kritik olduğu, Zig tabanlı bir finansal muhasebe/veri tabanı sistemi yapıyorsanız ve tek bir CPU çekirdeğinde saniyede bir milyon işlemi kaldırmanız gerekiyorsa, bağımlılık eklemek ciddi risk getirdiği için bundan kaçınmak tamamen mantıklı. Ama çoğu sıradan geliştirici normal CRUD sistemleri yapıyor ve genelde bu kadar güçlü bir konumda değiller. Birçok bağımlılık hatalarla dolu olabilir ama çoğu zaman yine de geliştiricilerin kendilerinin yazacağından daha yüksek kaliteli oluyor. Şirketler de pratikte işe alabilecekleri geliştiricilerin seviyesiyle darboğaza giriyor. Herkesin durumu farklı; bu yüzden birbirine zıt tavsiyelerin kendi bağlamlarında aynı anda doğru olabileceğini akılda tutmak gerek
Ben gerçekten TigerBeetle'da çalışıyorum. Asıl mesele bağlam. TigerBeetle ya da rust-analyzer gibi projelerde güçlü bir geliştirme kültürü var ama çözdükleri problemler farklı olduğu için farklı kültürler oluşuyor. Yazıda bahsedilen bağımlılıklar POSIX, ECMA-48 ve web platformu gibi şeyler; yani kütüphaneden çok sistem arayüzü. Kütüphane bağımlılıklarında bir sorun çıkarsa yeniden yazabilirsiniz, ama sistem arayüzü gibi temel şeyleri değiştirmek fiilen imkânsız ya da çok pahalı. Yazılımın kapsamına uymayan işleri yapmama kararı güçlü bir tercih. Örneğin matris çarpımı kodu yazacak uzman bir ekibiniz varsa, çekirdek işle ilgisiz diğer kütüphanelerde dışarıdan çözüm kullanmak sorun olmayabilir; ama bence ürünün sorumluluk ayrımını daha iyi tasarlamak gerekir. Böylece zorunlu bağımlılıkları sistem içinde daha iyi izole edebilirsiniz
Bu bakış açısının sorunu, ancak taban seviyedeki geliştiriciler düşünülünce geçerli olması. Teknoloji alanında tavsiyeler en düşük seviyeye göre sulandırılma eğiliminde ve açıkçası benim çalıştığım yerlerde bozuk bir bağımlılığı klonlayıp sorunu çözemeyecek kadar zayıf geliştiricilerin olduğu ortam neredeyse hiç olmadı. CRUD'a karşı da gereksiz bir küçümseme var; kötü soyutlamalar CRUD projelerinde muazzam zaman kaybına ve acıya yol açıyor. Popüler araçlarda bile, gerçekten en temel tutorial düzeyi dışında birçok sorun ve verimsizlik var
Bu geliştirici seviyesinin kendisiyle ilgili değil. Hangi toolchain'i ya da ürünü kullanırsanız kullanın, sonuçta başkalarının yaptığı bağımlılıkları kullanıyorsunuz. Etrafımda matris çarpımı kodunu gerçekten kendi yazan insan sayısı çok az; onlar bile kendileriyle ilgisiz açık kaynak kütüphaneleri baştan yazmıyor. Genelde düzenleyici gereklilikler, kişisel ilgi ya da belirli bir kütüphaneye özel bağlılık olduğunda insanlar bağımlılığın kendisine takılıyor. Herkes bu prensibi tamamen uygulasaydı, sahilde kum toplayarak yaşıyor olurduk
"Ortalama CRUD geliştiricileri güçlü değildir" görüşü fazla kestirip atıyor. Çoğu geliştirici üzerinde çalışacağı sistemi seçemez ve geliştirme sürecinde kaynaklar her zaman yetersizdir. 'Ucuz' bağımlılıklardan yararlanmak, çalışan yazılımı hızlıca piyasaya çıkarmanın tek yolu olabilir. Bu yorum biraz bu gerçeklikten kopuk duruyor
TigerBeetle görece yeni çıkmış bir startup ve hâlâ 1.0 kararlı sürümüne ulaşmış değil. Bu yaklaşımın gerçekten işe yarayıp yaramadığını söylemek için çok erken bence
NIH (Not Invented Here) yaklaşımı, sorumluluğunuzu ne kadar üstleneceğinizi gerçekçi biçimde değerlendirerek kullanıldığında çok faydalı olabilir. Örneğin kendi alanıma tam uyan bir web frontend framework'ünü bağımsız olarak geliştirip sürdürmek çoğu zaman değerli olabilir. Ama veritabanı, oyun motoru, web sunucusu, kriptografiyle ilgili temel işlevler gibi konular başka. Eğer mevcut çözümlerle çözülemeyecek kadar zor bir problemse, önce problemi yeniden tanımlamayı düşünmek gerekir. SQLite testlerinin tamamını sıfırdan yeniden yapmaktansa, problemin kendisini yeniden çerçevelemek çok daha ucuz olabilir
Veritabanı, oyun motoru, web sunucusu, kriptografik primitive'ler gibi şeylerde de duruma göre kendiniz yapmanın daha iyi olduğu çok örnek var. Sadece basit dosyalar ve çalışma zamanında indeksler yeterliyse, SQLite bile çoğu zaman gereğinden ağır kalır. Birçok oyunda özellikle küçük ekipler için custom engine daha avantajlı olabilir. Hazır motorların asıl avantajı pipeline tarafında ama bunun da büyük bir overhead'i var. Web sunucusunun da bir FastCGI uygulamasına kıyasla karmaşıklık farkı yok. Kriptografide de her durum bir güvenlik problemi değil; örneğin basit hash doğrulaması gibi şeyleri kendiniz yazmanız sorun olmayabilir. Zor görünen konular karşısında öğrenilmiş çaresizlik geliştirmek iyi değil. Mevcut çözüm bir sorunu çözüyor diye onun en iyi ya da en verimli yol olduğunu varsaymamak da önemli
O zaman neden bu kadar çok veritabanı motoru var? Sonuçta karmaşık bilgisayar sistemlerinin her birinde farklı trade-off'lar bulunuyor. Kısıtlar, ölçeklenebilirlik, eşzamanlılık, güvenlik, veri özellikleri, saklama biçimi... seçenekler çok çeşitli. Benim görüşüm şu: Bir bağımlılığın maliyeti ne kadar yüksekse, o bağımlılığın kendi içinde başka bağımlılıkları en aza indirmeye çalışıyor olması bana o kadar güven veriyor. Otomatik bağımlılık yönetim sistemleri çoğu zaman sorunu daha karmaşık hale getiriyor; dikkatli elle yönetim yükü azaltabiliyor
Üçüncü taraf bağımlılık kullanmanın iki temel sebebi olduğunu düşünüyorum. (1) Hizmet sağlayıcının bunu doğrudan yayımlaması ve yaşam döngüsünün kabaca sizinkiyle hizalı olması. (2) Benim yazmak istemediğim karmaşık kodun yerini alması. (1) iş tarafında anlamlı olduğu için sorun değil; tabii hizmet güncellendiğinde büyük değişiklikleri kabullenmeniz gerekir. (2)'nin değeri ise kaçınmaya çalıştığınız kodun karmaşıklığına bağlı. Bir bağımlılığı eklemek demek, başkasının takvimine göre güncelleme/test için zaman ve kaynak harcamayı kabul etmek ve bunun sorumluluğunu üstlenmek demek
RDBMS ile çözülemeyen sorunlarla çabuk karşılaşırsınız. RDBMS'ler eşzamanlı veri değişikliği ve değişken veri kümelerini desteklemek etrafında şekillenmiştir; eğer bunlara ihtiyacınız yoksa, basit indeksler bile muazzam performans artışı sağlayabilir. Veri değişmezse, RDBMS'e kıyasla çok daha hızlı kendi çözümünüzü yazabilirsiniz
RDBMS örneği ilginç. Wikipedia'da 100'den fazla RDBMS var ve her biri bazı problemleri çözüp bazılarını çözemiyor. Bu da pratik çözüm arayışının ve gerçekten uygulamaya geçmenin sonucu
Bağımlılıklar risk yaratır ama hiç kullanmamak da geliştirme ve pazara çıkış rekabetçiliğinde geride bırakabilir. Bu yüzden bağımlılık yönetimi süreci önemli
4 ve 5 gerçekten çok önemli ama sık unutuluyor. Kişisel projelerde bile bir süre bırakıp geri dönünce bağımlılıkların eskidiğini ya da repoların silindiğini gördüm. Bu yüzden artık kaynağı özel olarak fork'layıp kendim derliyorum; hatta bağımlılıkların bağımlılıklarını bile kaynak seviyesinde fork'luyorum. Böylece ekosistem sonradan sert biçimde değişse bile zararı en aza indirebiliyorum. İkili artefact'lar yerine kaynak kütüphaneleri tercih etmeye başladım
Tüm kodlar en azından ağ bağlantısı olmadan derlenebilir olmalı. İkili artefact hiç olmaması en iyisi ama bu her zaman pratikte mümkün değil
Harika bir içgörü. Bunu kendi bağımlılık edinme prosedürü dokümanıma ekleyeceğim. Sorun, JavaScript gibi bağımlılık ağacının aşırı derin olduğu durumlar
Uzun deneyimime göre her şey dönüp dolaşıp "duruma bağlı" oluyor. Gençken sadece ilkelere bağlı kalıp hiç istisna olmamasına takılırdım; bunun sonucu olarak uygunsuz kütüphane ya da paradigma seçimlerini zorlayıp korkunç kodlar yazdığım oldu. Şimdi sık kullandığım şeyleri kendim kütüphaneleştirip paket olarak ayırıyorum, ihtiyaç duyup da yapamadığım kısımları ise dış bağımlılıkla tamamlıyorum. Kalite ve yönetilebilirlik konusunda ikna olursam dışarıdan gelen çözümleri de memnuniyetle kabul ediyorum
Enerji sektöründe bağımlılıklardan bilinçli olarak kaçınma eğilimi var. Çünkü dış bağımlılık eklendiğinde tüm değişiklikleri gözden geçirmek gerekiyor. AI kod araçları büyük fayda sağladı; en çok da CLI araçları üretmekte kullanıyorum. OpenAPI dokümanlarını da LLM ile oluşturup bunları Go standart kütüphanesiyle servis ediyorum. LLM'in kendisi dış bağımlılık ama onunla üretilen CLI araçları gerçek kodla doğrudan bağlantılı olmadığı için kalite gereksinimi daha düşük. Tabii frontend geliştiricileri React olmadan çalışmak istemez ama o tür ürünleri dışarıdan ele aldığımız için bu bir istisna. Mühendislerin kalite-bağımlılık takıntısını azaltan küçük araçlar sunarsanız, bağımlılığı en aza indirme politikası daha kolay uygulanıyor
İyi ve kötü bağımlılıkları ayırt edebilmek önemli bir yetkinlik. Bana göre ücretli bağımlılıklar çoğu zaman dezavantajlı. Bunları sunan şirketler büyük ihtimalle vendor lock-in yaratacak şekilde tasarlıyor. "Bağımlılık minimalizmi" iyi bir kavram (VitalikButerin'in ilgili tweet'i)
Ücretli bağımlılıklar yalnızca tek bir yerden destek aldığı için, sağlayıcı şirket kapanırsa tüm proje risk altına girer. Çoğu şirket sonsuza kadar yaşamayacağına göre, bağımlılığın geleceğinin projenizin rotasını etkileyip etkilemeyeceğini mutlaka değerlendirmek gerekir
Teknik olmayan ekiplerin dayattığı ücretli bağımlılıklarda kötü deneyimlerim oldu. Buna karşılık Sidekiq gibi toplulukta yaygın kullanılan "open-core" bağımlılıklar çok daha güvenilir; bir anda ortadan kaybolma ihtimalleri daha düşük. Ücretli tarafın avantajıysa, şirket sağlıklı biçimde yürüdüğü sürece destek konusunda endişelenmemeniz
Şirketlerin sunduğu ücretli ya da ücretsiz tüm bileşenlerde vendor lock-in vardır. Risk yönetimi entegrasyon ekibinin işidir; alternatif bulmalı ya da modülerleştirerek riski kontrol etmelidirler
Ücretli bir şey alıyorsanız, lock-in'i önlemek için mutlaka açık standartlara ya da alternatif uygulamalara sahip bir arayüz üzerinden teslim edilmesi gerekir. Başka seçenekler varsa geçiş seçeneğiniz korunur
Ücretli bağımlılıkların kötü olduğunu söylemek, bazen yeterli bütçe olmadığına işaret ediyor olabilir. Koduma destek vermenin birilerinin 'işi' olmasını isterim. Çok sayıda destekçi ya da gönüllü olarak sorumluluk alan geliştirici varsa bu daha güvenlidir; bireysel projelerde de kaynak açık olsa bile sorun çıktığında destek verecek birilerine ihtiyaç vardır. Şirket işten çekilse bile terk etmeme sorumluluğu önemli
Birçok insan yeni kod yazmaya fazlasıyla odaklanıyor ama gerçekte berbat bir bağımlılığı kullanmak bile çoğu durumda çok daha verimli; muhtemelen zamanın %90'ında
Bağımlılıklar iki ucu keskin bıçak. Büyük yazılım şirketleri çoğu zaman kodu sürdürmektense yeniden yazmanın daha ucuz olduğu için bunu yapıyor. Küçük web/branding ajanslarında yüksek kaliteli backend'e fiilen ihtiyaç olmayabiliyor. Buna karşılık o korkulan enterprise pattern'ler, beş yıl sonra dokümantasyon ve kurumsal hafıza kaybolsa bile dış bağımlılıklara bağlı olmadan kodun izole edilip bakımının yapılabilmesi için ortaya çıktı. Dış bağımlılıklar iki risk taşır: desteğin kesilmesi ya da kırıcı değişiklikler gelmesi. Sonuçta bunlar özellik geliştirme akışını etkiler. İç bileşenlerde ise bu trade-off'lar kurum içinde kontrol edilebilir. SaaS yapıyorsanız kısa vadeli başarı için bağımlılıkları hızlıca kullanmak mantıklı; güvenlik ve uzun vadeli destek zorunluysa daha uzağı düşünmek gerekir. Yeni kod yazmak neredeyse hiçbir zaman organizasyonun asıl darboğazı olmuyor
Şirketinizin güvenlik açıklarını ve lisansları ne kadar ciddiye aldığını merak ediyorum. Eskiden bağımlılıklara daha rahattım ama güvenlik ve lisans konusunda çok katı bir şirkete geçince bakışım ciddi biçimde değişti
Kütüphane ile framework arasındaki fark da önemli. Kütüphane tek bir işi iyi yapan araçtır; framework ise uygulamanın genel yapısını belirler. Go topluluğu büyük framework'lerden kaçınır; standart kütüphane, hafif kütüphaneler ve gerekirse source copy/paste tercih edilir. Örneğin Gin (web API) ve GORM (ORM) gibi framework'ler kullanışlıdır ama iç yapıyı kısıtlar ve karmaşıklığı artırır. Go'nun standart SDK'sı zaten oldukça güçlü olduğu için, gereksiz bağımlılık eklememek daha doğru geliyor
Yazar Yeni Zelandalı. Yeni Zelanda'daki Number 8 wire ruhu, yani 'elde olan ve biraz beceriyle bir şekilde çözmek' yaklaşımı arka planda etkili görünüyor (Number 8 wire wiki maddesi)
Yeni Zelandalı olmayan birçok deneyimli geliştirici de benzer şekilde düşünüyor. Yanlış bağımlılık seçimi ya da gereksiz kütüphane güncellemeleri yüzünden acı çekmeyen neredeyse yok
Ben de Yeni Zelandalıyım ve bana kalırsa Number 8 Wire zihniyeti zaten 20 yıl önce yok oldu
Bunu bugün ilk kez öğrendim. Avustralya'daki "She'll buff out, mate" deyişini hatırlattı
Bir bağımlılığın büyük ölçekte ve ticarî kullanımda kendini kanıtlamış olması ölçeklenebilirlik açısından da etkili. Benden 100 ila 1000 kat daha büyük ölçekte dağıtım yapan yerlerde kullanılan bir araçsa, benim problemimde sınırlarına çarpma olasılığı düşer. O ölçekte hatalar da daha önce bulunup düzeltilmiş olur; sonuçta bana daha güvenli bir şekilde geri döner
Büyük kütüphaneler küçük ölçekli ortamlarda bazen hiç çalışmayabiliyor. Örneğin Swift protocol buffers derleyicisi bir zamanlar beklenmeyen alanlarda crash oluyordu. Birçok büyük şirket de büyük ölçekli kullanım dışında o yolları gerçekten test etmiyor
Meta, Google, Microsoft gibi büyük şirketlerin geliştirdiği popüler kütüphanelerde ciddi hatalar bulduğum oldu. Issue açsanız da düzeltilmesi uzun sürüyor ve değişime direnç yüksek. Böyle durumlarda sonunda kendim uygulayınca daha hızlı ilerledim ve performans da arttı. Özellikle danışmanlık tarafında müşterilerin mantıksız talepleri işin yönünü sık sık değiştiriyor. Geliştirici olarak bir şeyi kendim yapabileceğime dair güvenim arttıkça, devasa dış bağımlılıklar yerine bazen kendi çözümümü yazmak daha mantıklı geliyor. Tabii browser ya da AI model gibi gerçekten çok büyük şeylere girmiyorum; ama örneğin lokal çalışan bir inference engine, HTML renderer ya da kendi yazdığım bir graph database gibi şeyleri yapıyorum. Müşterinin beklentisi çoğu zaman yenilik değil, riskin azaltılması. Bir şeyi kendim geliştirdiğimde takvime uymak çok daha kolay oluyor. Google'ın ya da başka devlerin dokümantasyonunda saatler harcamaktansa kendim yapmak daha verimli gelebiliyor. Son 3 aydır önceki ekibin kaderine terk ettiği bir projeyi kurtarmak için günde 12 saat çalışırken bu konuları gece geç saatlerde epey düşündüm