- Paket kurmanın varsayılan hâline geldiği geliştirme kültürü; güncellemeler, yamalar, denetimler ve geçişli bağımlılık yönetimiyle süren dependency churn’ü büyüterek üretkenliğin gizli maliyetini oluşturuyor
- JavaScript ve Rust gibi paketleme altyapısı iyi gelişmiş ekosistemlerde etkisi daha büyük; yeni bir Tokio projesinin 28 crate, Rocket’ın 172 crate, MiniJinja CLI’ın ise 142 bağımlılık getirmesi gibi örnekler var
terminal_size gibi uzun süredir kararlı olan işlevlerde bile platform soyutlama kütüphanelerindeki değişimler yüzünden ek crate’ler ve tekrarlanan sürümlerle uğraşma paradoksu ortaya çıkıyor
- Küçük işlevler için ChatGPT veya Cursor ile bağımlılıksız bir uygulama üretmek, bağımlılık arayıp sürekli yükseltmekten daha hızlı olabilir ve dış kodu derleme yükünü de azaltır
- HTTP, QUIC, grafikler, tokio gibi zor alanlardaki kütüphaneler gereklidir; ancak tek bir fonksiyon için büyük bir bağımlılık grafiğini kabul etme kararı daha fazla sorgulanmalı
Bağımlılık artışının yarattığı bakım treadmill’i
- Geliştiriciler üretkenlik gerekçesiyle paketleri kolayca kuruyor; bunun sonucunda güncellemeler, yamalar, denetimler ve geçişli bağımlılık yönetimi hiç bitmeyen bir dependency churn hâline geliyor
- Paketleme çözümlerinin iyi oturduğu ekosistemlerde bu sorun daha belirgin; JavaScript ve Rust özellikle güçlü biçimde etkileniyor
- Rust örnekleri:
- Yeni bir Tokio projesi 28 crate getiriyor
- Yeni bir Rocket projesi 172 crate’e kadar çıkıyor
- MiniJinja’nın kendisi tek bir bağımlılıkla var olabilirken, CLI varyantı 142 bağımlılık getiriyor
- Temel sorun, küçük bir işlev için gerçekten gereken koddan çok daha fazla dış kodu derleyip yönetmek zorunda bırakan yapı
terminal_size’ın gösterdiği kararlı kod paradoksu
terminal_size, adından anlaşılacağı gibi terminal boyutunu öğrenen bir crate
- Bu işlevin kullandığı temel API, bilgisayar terminallerinin ilk dönemlerinden beri fiilen kararlı olsa da işletim sistemine bağlı olarak 3-4 ek crate getiriyor
- Terminalin 80x25 mi yoksa 120x40 mı olduğunu kontrol etmek için binlerce başka fonksiyonun derlendiği bir durum ortaya çıkıyor
- Söz konusu crate 26 kez yayımlandı, ancak aynı işlev için 10 yıl önce bir projeye eklenmiş kendi uygulaması güncelleme almadan hâlâ çalışıyor
- Çok sayıda sürüm çıkmasının nedeni işlevin kendisinin değişmesi değil, alttaki platform soyutlama kütüphanelerinin sürekli değişmesi
- UNIX’te
libc bağımlılığına ihtiyaç duyulması bir istisna
- Çünkü Rust, platformun libc sabitlerini dışa açmıyor ve bu sabitler standartlaştırılmış değil
- Yine de
libc yaygın ve hafif bir bağımlılık olduğundan kaçınması zor
Güvenlik ve kod yeniden kullanımı kültürü bağımlılıkları güçlendiriyor
- “big supply chain” yaklaşımı, fonksiyonları kopyalayıp eklemeye veya doğrudan
unsafe kullanmaya temkinli yaklaşıyor ve işi platform soyutlama katmanlarına bırakma yönünde baskı kuruyor
- Bağımlılık sorununu ele alan araçlar sağlayan şirketler de var; güvenlik adı altında bağımlılıkları korumayı ve güncel sürümlere yükseltmeyi teşvik ediyorlar
- Ancak çok sayıda bağımlılığın kendisi güvenlik sorunlarının başlıca kaynaklarından biri olabilir
- Kodun hedefi, bir noktada kararlılığa ulaşıp artık güncelleme gerektirmeyecek şekilde yazılmak olmalı
- Rust ekosisteminde, kararlı biçimde çalışsa bile hata takipçisi bir miktar pasif olan bir bağımlılık RUSTSEC tarafından düşük değerlendirilebilir
- Kurumsal kod inceleme kültürü de açık kaynağı etkiliyor
- Yeni ve parlak bir kütüphane getiren mühendisin azar işitmekten çok ödüllendirilme olasılığı daha yüksek
- Bunun sonucunda Dependabot gibi araçlar ortaya çıktı ve projelere sürekli bağımlılık güncelleme PR’ları geliyor
- Şirket içinde ise vendoring, iç denetimler ve şirket çapında yükseltmeler tek başına bile mühendislik ekiplerini sürekli meşgul edebilir
Küçük işlevler doğrudan yapılabilir
- Daha basit yol, gereken kodu kendiniz yazmak
- Başta daha fazla iş çıkarabilir; ancak kod yazıldıktan sonra yeni crate gerekmez ve upstream yazarının edge case’i düzeltmesini beklemek zorunda kalınmaz
- Kod kendi kullanım yerinizde bozulursa doğrudan düzeltirsiniz; çalışan kodun mutlaka bakım treadmill’ine çıkması gerekmez
- 2025 itibarıyla ChatGPT veya Cursor, sık rastlanan küçük işlevler için bağımlılıksız uygulamaları hızlıca üretebilir
- Birçok küçük fonksiyonun bakım yükü düşüktür ve sürekli bağımlılık yükseltmelerinden daha az zahmetli olabilir
- Birkaç satırlık kod için tek bir işlev uğruna başkasının binlerce satır kodunu derlemek gerekmez
Düşük bağımlılığı daha değerli görmek
- Tüm bağımlılıklar kötü değildir
- Karmaşık sürücüleri soyutlayan grafik kütüphaneleri
- HTTP ve QUIC gibi protokol uygulamaları
- tokio gibi çıkarılamayan ve çıkarılmak da istenmeyen önemli kütüphaneler
- Ancak yalnızca tek bir fonksiyon kullanırken yüzlerce fonksiyon derleniyorsa bunu bir uyarı işareti olarak görmek gerekir
- Küçük fonksiyonları doğrudan yazarak geçişli bağımlılık grafiğinden kaçınma tercihi daha fazla takdir edilmeli
- Büyük crate grafiklerine daha kuşkuyla yaklaşılmalı; birkaç yıl dokunmadan kalabilen basit ve kararlı kod olumlu görülmeli
sha1-smol başlangıçta sha1 adıyla SHA1 hash hesaplamanın standart crate’i olmuştu; ancak daha sonra adını rust-crypto’ya devretmesi ve daha büyük crypto ekosistemine uyum sağlaması yönünde baskı gördü
- Yeni
sha1 crate’i kullanıldığında 10 bağımlılık beraberinde geliyor
- registry’deki ad önemli olduğu ve trait uyumluluğu gereksinimi bulunduğu için bundan kaçınmak zordu
- MiniJinja, README’de düşük bağımlılığı vurguluyor
$ cargo tree
minimal v0.1.0 (examples/minimal)
└── minijinja v2.6.0 (minijinja)
└── serde v1.0.144
- MiniJinja’da son bağımlılığı kaldırmaya yönelik bir PR bulunuyor
- Uygun durumlarda kendin yapmayı kutlamalı, düşük bağımlılıklı ya da bağımlılıksız açık kaynak kütüphaneler üreten yazarlara daha fazla takdir göstermeliyiz
1 yorum
Hacker News yorumları
Rust dilinin kendisi iyi, ama Rust bağımlılık ekosisteminden hoşlanmıyorum. C++ için bağımlılık eklemenin zor olduğundan çok şikâyet edilir, ama bu bana aksine bir özellik gibi geliyor. Çünkü gerçekten gerekli olup olmadığını düşündürüyor
C++’ta bağımlılıkları ben kontrol ederim; Rust’ta ise kısa sürede 100’ü geçer ve pes edersiniz. Güvenlik açısından, açıkçası ne dağıttığımı bilmem mümkün olmuyor
Ayrıca Rust’ta ABI uyumluluğu da yok, paylaşımlı kütüphane kültürü de yok. Bu yüzden işletim sistemi paket dağıtım modelini bozuyormuş gibi hissettiriyor. Bir Linux dağıtımı seçerken, o dağıtımı derleyen insanlara güvenirsiniz; Rust ise herkesin PyPI’a bir şey yükleyebildiği Python’a daha yakın görünüyor
Docker/Python/Rust peki? Docker imajımı, PyPI paketimi, Rust crate’imi oluşturan insanları hiç tanımıyorum
Fiilen EXE ve DLL’leri ZIP olarak birbirimize gönderdiğimiz günlere geri dönmüş olduk. Sadece artık buna konteyner diyoruz ve gururla root yetkisiyle çalıştırıyoruz
Yazarın dediği gibi, bazen bağımlılığın kaynak kodunu doğrudan birleştirmek en iyi çözümdür. Eskiden buna vendoring denirdi ve Rails/Ruby’de epey önemliydi. Sonradan kötü niyetli paket ele geçirmelerinden etkilenmeme gibi büyük bir avantajı vardır; isterseniz upstream güvenlik yamalarını da kendiniz birleştirebilirsiniz
NIH sendromunun net olumlu etki yarattığı bir proje aklıma gelmiyor. Zorunlu olmayan bağımlılıklar bile ciddi zaman kazandırır
İsteğe bağlı bağımlılıkların bir kısmını her projede yeniden yaparsanız, ek hataları ve sınır durumlarını, alt bağımlılıkların farklı sürümlerini, birden çok platform desteğini düzeltmeye zaman nereden bulunuyor merak ediyorum
Buna PyPI, npm, Cargo gibi herkesin yükleme yapabildiği ve kürasyonun zayıf olduğu depolar ile küçük bir standart kütüphane birleşirse, acıya hazır olmak gerekir
Hangi bağımlılığın alınacağını geliştirici seçer. Kimsenin kullanmadığı bağımlılıklar kaybolur; çoğu kütüphanenin çok bağımlılığa sahip olmasının nedeni de birçok geliştiricinin bağımlılıkların üzerine bir şeyler inşa etmeyi tercih etmesidir
Konu derleme sistemi ise Cargo, Crates.io kullanımını zorunlu kılmaz. Sadece kolaylaştırır. CMake/Vcpkg, Conan gibi yol tabanlı bağımlılıklar da kullanabilir, kütüphaneleri kendiniz de oluşturabilirsiniz
Crates.io kullansanız bile değişimden hoşlanmıyorsanız sürüm sabitlemesi yapabilirsiniz. Sadece en yeni sürümü kolayca almanızı sağlar
Rust’ta mevcut yazılımın üzerine yazılım inşa etmek kolaydır. Mevcut yazılımı veya onun değişim hızını sevmiyorsanız Cargo’yu suçlamayın, istediğiniz şekilde yapın
Dağıtımlar hâlâ Rust paketlerini kaynaktan derliyor ve crate bağımlılıklarını depoya vendoring ile dahil ediyor. Bağımlılıklar daha fazla ve güncellemeler daha sık olduğu için daha acılı, ama bu paylaşımlı kütüphanelerden ayrı bir konu
Terminal boyutunu öğrenmeye yarayan API’nin 50 yıldır kararlı olduğu sözü doğru değil. TIOCGWINSZ ioctl bildiğim kadarıyla hiçbir zaman standartlaştırılmadı; Unix ve BSD’lerde adları da çeşit çeşit
tcgetwinsize()işlevi POSIX’e ancak 2024’te girdi ve bu konunun tamamının oldukça talihsiz bir geçmişi var https://news.ycombinator.com/item?id=42039401. Yani Windows tarafına gitmeden önce bile durum böyleBazen bu sorun olmaz; ama farklı kullanım senaryoları olan kişiler veya sizin anlamadığınız ve kullanmadığınız sistemlerde çalıştıran kişiler için yazılım daha kötü hâle gelebilir
Kütüphanenin gerçek değeri, basit görünen problemlerde bile aslında çok fazla karmaşıklık olduğunu ele almasındadır. Windows/Linux ikisinde de çalışan bir kütüphanenin 3-4 bağımlılığa sahip olmasını da o kadar fazla bulmuyorum. İyi bir durumda, o kütüphaneyi kullanan kişi ilgili alanda daha deneyimlidir ve benim bilmediğim bilinmeyen tarafları da halledebilir
ioctl’da kesinlikle sorunlar var, ama
terminal-sizeveya bağımlılıklarında birden fazla sürüme yol açan değişikliklerioctl/TIOCGWINSZsabiti ya dawinsizeyapısıyla ilgili değil. O kod değişmediterminal-sizecrate’i sadece Rustix’intcgetwinsizeişlevini çağırıyor, Rustix de tekrar libc’nintcgetwinsizeişlevini çağırıyor. Yani aynı işi doğrudan yaparsanız bağımlılıkları epey azaltabilirsiniz; bedeli de aşağı yukarı Windows desteği olurBu API’nin 50 yıl mı 25 yıl mı kararlı olduğu ayrıntıdan ibaret. Söz konusu bağımlılık o karmaşıklığı ele alıyormuş gibi bile yapmıyor; o işlevin yakın gelecekte değişmesi veya kaldırılması da düşük ihtimal
Çoğu kişi doğrudan ona yazar, ama terminal boyutu veya raw mode gibi özellikler karmakarışıktır ve
ioctlgibi şeyler gerekir. Açıkçası pek iyi değilAma kütüphaneler daha da kötü.
ncursese link etmek istemiyorsanız Tanrı yardımcınız olsunYakın zamanda 2006’da yaptığım ilk startup web uygulamasını yeniden hayata döndürdüm. Medya paylaşımı odaklı bir sosyal medya sitesiydi ve o dönem için oldukça basit bir LAMP stack kullanıyordu. PHP 5, MySQL 3.2 idi ama dönemin sosyal medya özelliklerinin çoğunu barındırıyordu
Yeni CI/CD teknolojilerini bizzat denemek istediğim için bu uygulamayı öğrenme amacıyla gereğinden fazla mühendislik uygulayarak dağıtım sürecini kuruyorum. WordPress ya da Hello World uygulaması da kullanabilirdim ama bu çok daha eğlenceli
PHP’nin neredeyse tamamını kendim yazmıştım. Kimlik doğrulama/yetkilendirme, şablonlar, form işleme vb. için kütüphaneleri de kendim yapmıştım; yalnızca e-posta gönderimi için bir PEAR kütüphanesi kullanmıştım. Ön yüz saf HTML’di, neredeyse hiç JavaScript yoktu ve medya oynatma için Flash kullanıyordu. 2006’da çoğu şey böyle yapılıyordu
19 yıllık uygulamayı yeniden çalıştırmam yalnızca yaklaşık bir saat sürdü. Eski PHP
mysqlsürücüsünümysqliile değiştirdim, MySQL 8’e uyması için şemayı ve bazı sorguları ayarladım. Çoğunlukla artık ayrılmış sözcük olan kelimeleri backtick içine almak ve daha katı hâle gelen sütun varsayılan değerlerini düzeltmekten ibaretti. Çalışmayan tek şey Flash olduBuna karşılık mevcut iş yerimde Java 8 ile yazılmış onlarca Spring Boot uygulaması işletiyoruz ve onlarca bağımlılıktan kaynaklanan güvenlik açığı listeleri sayfalarca birikmiş durumda. Birini güncelleyince başka kütüphaneleri de peş peşe yükseltmek gerekiyor ve geçişli bağımlılıklar yüzünden kâbusa dönüşüyor. Bu yüzden yalnızca en kritik güvenlik açıklarını asgari düzeyde ele alıyoruz; tamamını yükseltmek için gerçekçi bir plan yok
Komik olan, 2006’daki PHP uygulamasının yaptığı işle bugünkü Spring Boot uygulamalarının yaptığı işin pek de farklı olmaması. Sonuçta hepsi CRUD; sadece etrafına çok daha fazla kurumsal süs ve araç eklenmiş durumda
Kontrol listesindeki her madde için ayrı bir bağımlılık çekmiyorsunuz. Tekrarlı iş çıkabilir ama yükseltme yolu çok daha kolaylaşıyor
scpile dağıtılan eski bir LAMP uygulamasında bunlar genelde sorun olmazÖrneğin FHIR veya HL7 gibi standart iletişim mesajı formatlarında, zaten karmaşık olan standart tanımının tamamını kendiniz uygulamak istemezsiniz
Şifreleme fonksiyonlarını da kendiniz yazarsanız çoğu zaman kendi ayağınıza sıkarsınız; yıllar içinde bulunan ciddi güvenlik sorunları bunu kanıtladı
Şu an, çözümün nasıl düzgün inşa edildiğinden çok iş problemini çözmeye odaklanmak istediğimiz bir dönem. Yapay zeka ortaya çıktıktan sonra tüm kodlar gözü kapalı birbirine yapıştırılmış gibi hissettirdiği için bu nokta daha da önemli hâle geliyor
Her şeyi kendiniz yapmaya zaman harcamak uzun vadede avantajlı olabilir ama önce rekabette hayatta kalmanız gerekir. Rakibiniz başta hızlı ve atılabilir kodla pazarı çoktan ele geçirmiş olabilir
Yakın zamanda Java 8, Spring Boot 2, Swagger’dan Java 17, Spring Boot 3.3, OpenAPI 3’e geçtik ve oldukça painless oldu
Hâlâ bazı doğrudan bağımlılıkları ve geçişli bağımlılıkları daha yükseltmemiz gerekiyor ama en büyük engel migrasyonla aşılmış oldu
Ama bir C kütüphanesine link etmediğiniz sürece private geçişli bağımlılıklar hiç önemli değildir. Aynı bağımlılık ağacında SemVer uyumlu olmayan crate sürümlerinden istediğiniz kadar bulundurabilirsiniz; gerekirse birden fazla sürüme doğrudan bağımlı da olabilirsiniz
Java tarzı büyük ölçekli toplu yükseltmelere gerek yok; güvenlik açığı olan tek şeyi yükseltmeniz yeterli. C#’ta da benzer bir özellik olduğunu biliyorum ama biraz daha laf kalabalıklı
%100 katılıyorum. NodeJS kariyerimi ciddi şekilde etkiledi ama NPM, karmakarışık çocukluğumdan bile daha büyük bir travma bıraktı
Yeni bir programcının arkadaşlarına göstermek için yeni bir uygulama yaptığını hayal edin. Yeni bir bağımlılık eklemek istiyor ama başka bir bağımlılıkla uyuşmuyor, bu yüzden hepsini güncellemeye karar veriyor. Bir sonraki anda hiçbir şey çalışmıyor ve Babel bağırıp çağırıyor
Yine de bir şekilde çözülür diye düşünüyorsunuz ama kısa süre sonra en temel şeylerin bile kelimenin tam anlamıyla çalışmadığı açık Git issue’larını görüyorsunuz. Örneğin Expo’da, varsayılan yeni React Native projesinin Android’de build edilememesiyle ilgili açık bir issue var
Yarısında kimse umursamıyor gibi görünüyor; öyleyse çözüm de Node ekosisteminde değil, Android ekosisteminin bir yerinde oluyor. En dibe kadar koli bandı. Yine de milyarlarca dolarlık bir proje çalışmayan bir template yayımlayabiliyorsa, benim side project’imin yarısının çalışmaması yüzünden impostor sendromu hissetmemem gerektiğine dair bir özgüven de veriyor
İlk bağımlılığı içeri aldığım anı kişisel bir başarısızlık gibi görmeye başladım. Çünkü o anda, sıradan JS’i basitçe bir script etiketiyle yüklemek yerine, tek bir
package.jsonkullanmak için paketleme ve organizasyonun tamamı gerekli hâle gelmiştiGo’dan Rust ekosistemine geçince beni şaşırtan noktalardan biri buydu. Olgun bir Go projesi, örneğin bir şirketin üretimdeki web arka ucu, geçişli bağımlılıklar dahil yalnızca 10–20 bağımlılığa sahip olabilir.
Yazıda söylendiği gibi küçük bir Rust projesinin bile bundan çok daha fazlasına çıkma olasılığı yüksek; asenkron işler yapıyorsanız bu neredeyse garanti.
Bunun kültürden mi yoksa dil özelliklerinden mi kaynaklandığından emin değilim. Örneğin Go’da arayüzler örtük olarak karşılandığı için, “bunu implemente ediyorum” demek adına bir şey içe aktarmanız gerekmez.
Go’da dilin veya standart kütüphanenin içinde olup Rust’ta bağımlılık gerektiren şeyler arasında green thread’ler, kanallar, düzenli ifadeler, HTTP istemcisi, HTTP sunucusu, zaman, komut satırı bayrakları, logger, animasyonlu GIF okuma/yazma vb. var.
Go dilinin kendisini çok sevdiğim söylenemez ama araçlar ve standart kütüphane konusunda önde; kullandıklarım arasında açıkça en iyisi.
Ana fikre büyük ölçüde katılıyorum. Başka kütüphanelerin soyutlamalarını kendi kütüphanenizin dışına sızdırmaya izin vermenin pek çok gizli maliyeti var. Bunu asla yapmayın demiyorum, ama karar anında gelecekteki maliyetleri dengeli değerlendirmek gerekiyor.
Sarmalayan paket tasarımını veya hedefini sık sık değiştirirse istikrarsızlık doğar. Yazılım mühendisliğinde aslında en basit garanti biçimi olan özellikler ortadan kalkar ya da parçalanır.
Ayrıca kariyerini açık kaynak katkıcılığına adamamış olsa da belirli bir alanı iyi bilen sahiplerin ekosisteme katılmasını zorlaştırır. “X’i temiz biçimde yapmanın bir yolunu yaptım” ifadesi, “insanlar Z’yi de sevebilir, o yüzden X’in Y’nin altına uyması gerekir” şeklinde haftalar süren tartışma, pazarlık ve politikaya dönüşürse herkesin zamanı boşa gider.
Hayatta öğrendiğim şeylerden biri, en basit olanın en uzun süre hayatta kaldığı. Minilith’leri ve monolitleri daha sık övmeliyiz. Bu yalnızca Rust’a özgü bir sorun da değil; birçok dilde gördüm. Açık kaynak topluluğu çoğu zaman atom boyutunda paketleri güçlü biçimde itiyor; bunun gerçek kullanıcı topluluğunun çıkarından çok bayrak dikme veya sahipliği devretme amacı taşıyıp taşımadığını sık sık merak ediyorum.
2025’te, yaygın işlevlerin bağımlılıksız implementasyonlarını ChatGPT veya Cursor’a yaptırmanın daha hızlı olduğu görüşüne bir şekilde tesadüfen vardım ve giderek daha çok katılıyorum. Özellikle büyük React uygulamalarındaki bağımlılık cehennemini yaşadıktan sonra.
SaaS veya üçüncü taraf servis bağımlılıklarını da düşünmek gerekiyor. Bunların çoğu yaygın kalıplar ve zaten çözülmüş problemler; LLM’ler bunları hızlıca yeniden üretebilir.
Kapsamı sınırlı problemler için oldukça etkili ve yapay zekaya, benim doğrudan yazacağımdan daha eksiksiz ve sağlam bir implementasyon yaptırabiliyorum.
Daha sonra kütüphane eklemeye karar versem bile doğal bir kapsülleme oluşuyor. Yalnızca kendi fonksiyonumun implementasyonunu kütüphaneyi kullanacak şekilde değiştirmem yeterli; onu kullanan her yeri mutlaka elden geçirmem gerekmiyor. Zamanı geldiğinde birden çok kütüphaneyi denemek de kolaylaşıyor.
İronik biçimde oldukça ilginç. Armin, Python web framework’ü Flask’in ilk yazarı. Benzer dönemde Bottle adlı çok benzer bir kütüphane de vardı.
Özellikleri neredeyse aynıydı ama Flask büyük popülerlik kazandı; ben ise her zaman Bottle’ı tercih ettim. Çünkü tek dosyaydı, bağımlılığı yoktu ve projeye doğrudan kopyalaması çok kolaydı.
İçini değiştirip uyarlamak da kolaydı; sonunda tamamını anlayabilecek hâle gelmiştim. Sunucu ve WebSocket’ler için Gevent’i bağlamıştım ama bu şekilde oldukça ağır projeler bile yapabildim.
Bugün bile küçük web projelerinde Bottle kullanmak için güçlü bir dürtü hissediyorum. Yalnız Python’ın yıllar içinde benimsediği modern pratiklerin çoğunu takip edemediği için artık biraz eski görünmesi üzücü.
Kendin yapmak yetkin mühendislik becerisi gerektirir. NPM veya PyPI gibi ekosistemlerde sürekli hazır kütüphane çekmeye alışmış mühendislerden oluşan bir ekibiniz varsa, pek çok problemin çözümünü kendileri geliştirmekte zorlanırlar. Özellikle de çözümün uzun ömürlü olması ve gerekli esnekliği taşıması gerekiyorsa.
“Kendini programlayarak çıkmaz sokağa sokmamak” çok pratik gerektirir.
Mevcut kütüphanelerden kolayca daha iyisini yapabileceğiniz durumları da sık gördüm. Bir projede, dosyanın başında meta veriler bulunan bir Markdown varyantı için parser implemente etmiştim. Küçük bir sözdizimi kullandım ve bir ekranı bile doldurmayan kodla parser ortaya çıktı.
Fakat aynı dosyayı parse eden frontend kütüphanesi beklediğimden çok daha kötüydü. Meta veri tanımlayıcısında tire varsa bozuluyordu; meğer meta veri tanımlayıcılarını doğrudan nesne üyesi adı olarak kullanıyormuş. Basit bir JSON nesnesi kullanmak yerine ad seçimini yapay biçimde kısıtlamış,
something-somethinggibi tire içeren adlarda bozulmasına yol açmıştı.Sonunda benim parser’ım çöpe atıldı; gerekçe insanların onu “bakımını yapmak” zorunda kalacağıydı. Oysa çalışıyordu ve sözdizimi değişikliklerine kolayca uyum sağlayabiliyordu. Parser’lar hakkında azıcık bilginiz varsa anlaşılması zor da değildi.
İnanması güç ama ekipte benden başka parser generator kütüphanesiyle parser yazmış kimse yok gibiydi. Bunun gibi daha pek çok örnek var.
Tek bir fonksiyon kullanmak için yüzlercesini derlemek gerekiyorsa alarm zilleri çalmalı. Yaklaşık bir yıl önce üçüncü taraf bağımlılıkları güncelleme projesi yürütmüştük.
Bunlardan biri, her türlü matematik fonksiyonunu içeren kapsamlı bir matematik kütüphanesiydi. Biraz kurcalayınca bizim kullandığımız tek şeyin, bir listedeki medyanı bulan tek bir metot olduğunu gördük.
Sorumlu mühendise Wikipedia sayfasını gösterip, bağımlılığı kaldırmasını ve o matematik işlemini yapan tek bir metot yazmasını söyledim.
Ancak asıl sorun üçüncü taraf bağımlılık kullanmanın kendisi değil; bir kütüphanenin yalnızca dar bir parçasını alma kavramına ihtiyaç olması. Dev bir kütüphanenin yalnızca küçük bir bölümüne ihtiyacınız varsa neden tamamını çekmek zorundasınız? Bunun için bir yaklaşım olarak “mikroframework” önerildiğini duymuştum.
Ne yazık ki insanlar bağımlılıkların kullandığı varsayılan özellik kümesine dikkatlice bakıp bunları aktif biçimde azaltıyor gibi görünmüyor. Ek özellikleri dahil etmenin sözdizimi basit; ama varsayılan olarak açık gelen isteğe bağlı özellikleri kaldırmak için
no-default-featuresbelirtmeniz ve yine de istediğiniz varsayılan özellikleri tek tek yeniden eklemeniz gerekiyor, bu da daha zahmetli.Daha da kötüsü, bir kütüphanenin kendi bağımlılıklarındaki gereksiz özellikleri budayabilmesini sağlamak istiyorsanız, kendi özelliklerinizi oluşturup bunları her bağımlılığın özelliklerine eşlemeniz gerekiyor. Örneğin 5 bağımlılığınız varsa ve her birinin 1 zorunlu bağımlılığı ile 4 isteğe bağlı bağımlılığı bulunuyorsa, kullanıcının geçişli özellikleri tamamen kontrol edebilmesi için kendi kütüphanenizde 20 eşleme özelliği oluşturmanız gerekir. Kendi kodunuz için alt kullanıcıları düşünerek oluşturacağınız özellikler buna dahil bile değil.
Giderek, özellikler etrafındaki kullanılabilirliğin, özellikle gereksiz şişkinliği azaltma tarafında, o kadar kötü olduğunu ve bunun Rust derleme süresi sorununun katalizörü haline geldiğini düşünüyorum. Böyle konular gündeme gelse de geniş çapta tartışılmıyor gibi; mevcut durum devam ettiğinde işaret edebilmek için bu konudaki güçlü görüşlerimi bir blog yazısına dökmem gerekebilir.
Güven sistemi iyiyse bir yandan bunun sorun olmadığını düşünüyorum.
Shadcn benzeri yaklaşımı, yani bir bileşeni beğenirseniz kendi kütüphanenize kopyalama fikrini de bir ölçüde seviyorum. Ama bir güvenlik açığı ortaya çıkarsa bundan etkilenip etkilenmediğimi bilemem.
Bazı kodlarda sorun olmayabilir, ama başka kodlarda gerçekten mümkün olduğunca çok kişinin göz attığı şeye güvenmek gerekir.
Median(list) { let len = length(list) if len % 2 == 0 { let x = floor(len/2) return (list[x] + list[x+1]) / 2 } return list[len/2] }Tabii listenin zaten sıralı olduğunu varsayıyor. Burada
is_oddçağırma isteğine direndim.