Ask HN: Yazılım tasarımını öğrenmek için en iyi kod tabanları hangileri?
(news.ycombinator.com)- Yazılım tasarımı becerilerini geliştirmeye çalışıyor ve mevcut, iyi tasarlanmış kod tabanlarını incelemesi yönünde tavsiye almış
- Kamuya açık olarak erişilebilen kod tabanları arasında, yazılım tasarımında altın standart sayılanların hangileri olduğunu merak ediyor
1. Önerilen kod tabanları
- Büyük/temsilî projeler
- Git, Postgres, CPython
- Linux Kernel'in "lieutenants model"i
- UNIX v6, BSD'ler
- Framework'ler/kütüphaneler
- Spring Framework
- Laravel
- Rust
stdkütüphanesi - Codemirror 6
- Sistemler/sunucular
- Oyunlar/özel örnekler
- Eğitim amaçlı/öğrenme kaynakları
- xv6 (MIT işletim sistemleri dersi)
- pytudes (Peter Norvig)
- Diğer
- Monocypher (kriptografi kütüphanesi)
- Tcl dilinin gerçekleştirimı
2. Kod okuma vs belge/tasarım öğrenimi
- Sadece kodla sınırlılıklar
- Kod tabanı implementasyonu gösterir, ancak tasarım niyetini veya trade-off'ları gizler
- Tasarım belgelerinin önemi
- ADR (Architectural Decision Records), Rust RFC'leri, Python PEP'leri gibi karar kayıtları, tasarım öğrenimi için çok daha faydalıdır
- Tasarım belgesi yazmanın kendisi de bir eğitim olabilir
- Kitap/literatür önerileri
- The Architecture of Open Source Applications
- Code Reading (Spinellis)
- Beautiful Code (O’Reilly, ISBN-10: 0596510047)
- Refactoring / Legacy Code ile ilgili kitaplar
3. Pratik merkezli öğrenme yaklaşımı
- Deneyim ve deneme-yanılma
- Tasarım, sorunları tekrar tekrar yaşayıp bunlardan nasıl kaçınılacağını öğrenerek kazanılır
- Sadece kod okuyarak öğrenilmez; doğrudan yazıp başarısızlıkları çözme sürecinde öğrenilir
- İlgi temelli öğrenme
- Kişi ancak ilgisini çeken projeleri yaparken derinlemesine öğrenir
- Düşük başarısızlık maliyeti
- Yazılımda başarısızlık maliyeti fiziksel mühendisliğe göre daha düşüktür; bu yüzden deneme ve başarısızlık yoluyla öğrenme etkilidir
4. Yazılım mühendisliğinin doğası üzerine tartışma
- Olgunlaşmamış mühendislik görüşü
- Beş mühendisi bir araya getirince beş farklı çözüm çıkması, bunun bir mühendislik disiplini olarak olgunlaşmamış olduğunun kanıtı olarak görülüyor
- Deneye elverişli yapı görüşü
- Yazılım daha az kısıta sahip olduğu için çok çeşitli çözümler vardır; fiziksel mühendislikteki gibi tek bir doğru cevap sabit değildir
- Sanat ve mühendislik arasındaki sınır
- Tasarım, estetik unsurlar taşıyan sanatsal bir eylem olsa da, işlevsel gereksinimleri karşılama yönüyle mühendisliktir
- Yazılım, sanatsal esneklik ile mühendislik titizliği arasında durur
5. Alternatif öğrenme yöntemleri
- Kötü kod analizi
- Yalnızca iyi tasarlanmış kodları değil, kötü kod tabanlarını düzeltmeye çalışmayı da çok öğretici buluyorlar
- Kendi kod tabanından öğrenme
- Ekip içindeki kod tabanı, en çok şey öğrenilebilecek kaynak olarak gösteriliyor
- Ancak ekip kodu zayıfsa, dış örneklerle birlikte ilerlemek gerekiyor
- Alan odaklı öğrenme
- Çözmek istediğiniz probleme benzeyen kod tabanlarını okumak en etkili yöntem
Temel içgörüler
- İyi tasarlanmış kod tabanları faydalıdır, ancak öğrenme; tasarım niyetini anlamak ve deneme-yanılmayı yaşamakla birlikte ilerlemelidir
- Kod okumanın kendisinden çok tasarım belgeleri ve karar kayıtları temel öğrenme materyalidir
- Temsilî yüksek kaliteli projeler (Git, Postgres, CPython, Rust
stdvb.) yüksek öğrenme değerine sahiptir - Yalnızca iyi koddan değil, kötü koddan ve kendi kodunuzdan öğrenmek uzun vadede daha pratiktir
Öne çıkan yorumların özeti
Temsilî kod tabanı önerileri (CraigJPerry)
- Postfix mail server
- Güvenlik odaklı mimarisiyle, mikroservis kavramından önce bile benzer bir yapı gösteriyor
- Modern mikroservisler büyük organizasyonlarda dağıtımı öne çıkarırken, Postfix güvenlik ve sadelik için tasarlanmış
- Spring Framework
- Kurumsal ortamdaki Java geliştiricilerinin ihtiyaçlarını derinlemesine dikkate alan bir kültürü yansıtıyor
- Kullanıcı odaklı tasarım yaklaşımı öğrenilebilir
- Git
- Nesne veritabanı (blob, tree, commit) ve referans kavramını anladıktan sonra geri kalanı bunun kademeli genişlemesi
- Çekirdek kavramların tutarlı biçimde genişletilmesi, iyi tasarım örneği olarak sunuluyor
- Varnish
- Yüksek performanslı bir reverse proxy olmasının yanı sıra, öğrenme aracı olarak da kullanılabilecek kadar iyi düzenlenmiş bir kod tabanı
- Linux Kernel Lieutenants Model
- Bir kod tabanı değil, ama büyük ölçekli yazılım yönetim modeli olarak incelenmeye değer
- Bunlar sadece "iyi tasarlanmış kod" örnekleri değil, tasarım kararlarının güçlü iz bıraktığı örnekler olarak öne çıkıyor
Gerçek iş kod tabanında öğrenmeyi vurgulayan görüş (crystal_revenge)
- En büyük öğrenme değeri kendi ekibinizin kod tabanında bulunabilir
- Gerçek gereksinimlerle implementasyon arasındaki karmaşık bağlantı sürecinde hem iyi hem kötü tercihleri aynı anda deneyimlersiniz
- Gerçek dünyadaki kısıtların en büyüğü zaman baskısıdır; ideal tasarımla gerçeklik arasındaki dengeyi öğrenmek asıl konudur
- İyi yazılım, kullanıcı ihtiyaçlarını çözen yazılımdır; tekrar eden deneyimlerle başarı şansını artıran tasarımlar öğrenilir
Geçmiş tartışmalar ve kaynak bağlantıları (sprobertson)
- HN'de aynı konu birkaç kez ele alındı
Kod vs tasarım belgesi (alphazard)
- Kod tabanı yalnızca implementasyonun çıktısıdır; tasarımın kendisi değildir
- Tasarım öğrenimi için tasarım belgesi yazmak daha etkilidir
- Belge, başka birinin doğrudan implementasyon yapabileceği kadar açık olmalıdır
- Alternatifleri sıralayıp neden elendiklerini kaydetmek, tasarım değerlendirmesinin kanıtı olur
- İyi tasarımcı, daha geniş bir tasarım alanını değerlendirip uygun noktayı seçen kişidir
Tüm sistemi anlamayı vurgulayan görüş (RossBencina)
- Bir kod tabanının tamamını anlama süreci çok değerlidir
- Bu, yalnızca iyi tasarlanmış kodları değil, sistemin büyük resmini görme alıştırmasını da sağlar
- UML gibi diyagramlarla ilişkileri görselleştirmek yardımcı olur
- Öğrenme yaklaşımı:
- Geliştirmekte olduğunuz şeye benzeyen yazılımların kodunu okumak etkilidir
- Halihazırda iyi bildiğiniz bir alanın kodu (web framework'leri, web sunucuları, Python standart kütüphanesi, VSCode vb.) başlangıç noktası olarak önerilir
- İlk başta küçük programlar ve aşina olunan alanlardan başlamak daha iyidir
İyi tasarımın ölçütü (mamcx)
- İyi tasarım hedefler ve fikirlerdir; kod tabanı ise bunun ne ölçüde uygulandığını gösterir
- İyi tasarım, yalnızca "hızlı, güvenli" gibi sıfatlardan ibaret değil; somut değerlendirmeler ve trade-off kayıtları da içermelidir
- Örnekler: Erlang, erken dönem Pascal ve birçok RDBMS tasarımında bu özellikler görülebilir
- Rust'ın
stdkütüphanesi, güvenlik ve tutarlılığı vurgular; kod ve belgeler de bunu sadakatle yansıttığı için iyi bir öğrenme materyalidir
Görünmeyen tasarım kararları (ben30)
- İyi tasarlanmış bir kod tabanına bakarken en önemli kısım görünmeyen şeylerdir
- Karmaşıklığı dışarıda bırakmak, gereksiz soyutlamalardan kaçınmak, belirli örüntüleri reddetmek gibi yokluk kararları asıl meseledir
- Bunu tamamlamak için ADR (Architectural Decision Records) kullanımı öneriliyor
- Alternatifleri, neden elendiklerini ve seçimin gerekçesini kaydederek bağlamı korur
- Gelecekteki bakımcılar ve yapay zeka araçları için de büyük fayda sağlar
- Öğrenirken, sadece koda değil ADR, RFC, PEP gibi tasarım karar belgeleriyle birlikte gelen projelere bakmak daha etkilidir
5 yorum
Evan You'nun (Vue.js ve Vite'ın yaratıcısı) express.js'in yaratıcısı TJ'nin bunu temiz ve güzel şekilde tasarlanmış olarak anlattığı bir röportajı vardı; ben de kodu birkaç kez okuyup inceledim. Büyük resmi anlayabildiğimi söyleyemem ama genel olarak kodun karmaşık olmadığı, temiz olduğu ve tam gerekli mantığın yazıldığı hissini güçlü biçimde aldım.
Yorumlar da iyi yazılmıştı; 10 yıllık bir kod olmasına rağmen tip çıkarımını ya da DTO formatını anlamak için iyiydi.
Spam yorumlarla kaplı bir blogun 2009 tarihli yazısını referans almak da neymiş..
Hacker News yorumu
Bilmiyorum sadece bana mı öyle geliyor ama, gerçek hayatta aynı tür sorunlara defalarca çarpıp onlardan nasıl kaçınacağını kendi kendine öğrenmenin en etkili yol olduğunu düşünüyorum. Bunu yaptıkça, ileride ne tür sorunların çıkabileceğini zihninde doğal olarak simüle etmeye başlıyorsun; sonuçta tasarım dediğin şey de gelecekte ortaya çıkabilecek çeşitli sorunları önceden öngörüp kaçınmak, hangi sorunu ne kadar çabayla önleyeceğine ve tek bir tasarımla birden fazla sorunu çözüp çözemeyeceğine dair ödünleşimleri dikkatle tartmakla ilgili bir muhakeme işi
Ben de aynı şekilde düşünüyorum. “Alıştırma çözmek” ya da “kod tabanı incelemek” gibi yöntemler bana pek uymadı. Gerçekten ilgimi çeken bir şeyi üretirken, örneklerde doğruluk ve titizliğin peşine düşerek doğal biçimde öğreniyorum. Ama bazen hâlâ yeterince iyi olmadığımı hissediyorum. Kodu bir kitap okur gibi akıcı şekilde okuyup kafamda nasıl çalıştığını canlandırabilsem, çalışmanın kendisi de çok daha eğlenceli olurdu diye düşünüyorum
Sorunlara defalarca çarparak öğrenmekten söz edilince, bana daha çok yazılım mühendisliği alanının henüz olgunlaşmamış olduğu hissini veriyor. Köprüleri ya da evleri böyle inşa ettiğimizi, ya da cerrahların böyle eğitildiğini düşünmek bile ürkütücü olurdu. Zamanla standartlar ve normlar oturacaktır ama şu an gerçekten çok akışkan bir durumdayız. Beş yazılım mühendisine aynı problemi verirsen sadece beş tamamen farklı çözüm çıkmakla kalmaz, hangi yaklaşımın doğru olduğu konusunda da sert fikir ayrılıkları yaşanır. “İyi çözümü görünce tanırım” tavrının tek başına gerçek mühendislik sayılmayacağını düşünüyorum
Ben de şimdiye kadar hep bu şekilde düzenli olarak öğrendim ve muhtemelen böyle devam edeceğim. Gerçek production kodundan öğrenmek benim için yeni bir meydan okuma olurdu. Ne kadar değerli olur bilmiyorum ama kesinlikle eğlenceli olur gibi geliyor
Bence bu, araba kullanmayı ilk kez direksiyona geçip kaza yaparak, sonra da ders çıkarıp bir dahaki sefere kaza yapmamaya çalışarak öğrenmeye benziyor. Gerçekte ikisine de ihtiyaç var. Normal yolda giderken sınırları zorladığımız durumlar pek olmaz, o yüzden birebir uygulanması zor; ama yarışta mesela, aracı tam olarak nereye kadar itebileceğini bilmek şarttır. Tabii işimizi bir spor müsabakası gibi görmek zorunda değiliz. Ama kitap okumaz, çalışmazsan bu iş sadece çok uzun sürmekle kalmaz, aynı zamanda bitmeyen kazalara ve arızalara da yol açar. O yüzden ben hep oku, yine oku derim. Şu an gerekli gelmeyebilir ama bir gün deneyim kazandıkça o bilgi mutlaka bir yerde işine yarar; yokuş aşağı inerken motor freni için düşük vitese geçmen gerektiğini ilk kez öğrenen biri gibi afallamazsın
Mesele tam olarak bu
Bu soruya ilk tepkim “ekibinin kod tabanı” olur. Gerçek problemlerde iyi ve kötü çözümlerin neden seçildiğini derinlemesine anlamaktan daha etkili bir yazılım tasarımı öğrenme yolu yok. Yazılım özünde kullanıcı ihtiyaçları ile makinenin davranışı arasında duran karmaşık bir ara katmandır. Bu karmaşa olmasaydı zaten otomatikleştirilmiş olurdu ve yazılıma ihtiyaç kalmazdı. Yazılımda soyut bir ideale saplanmak çoğu zaman kötü kararlara yol açar. Asıl önemli olan, “hangi baskılar yüzünden bu tercih yapıldı” sorusunu kavrayıp deneme-yanılmayı azaltmaktır. Aynı zamanda hızlı ve etkili çalışmanın pratik yollarını da öğrenmek gerekir. Gerçek dünyadaki en büyük zorluk zaman kısıtıdır. Bu, teorik yazılım tasarımında neredeyse hiç ele alınmaz ama pratikte neredeyse her zaman kodu hızlı teslim etme baskısı altında çalışırsın. İstediğin ya da ideal yöntemi uygulamaya çoğu zaman vaktin olmaz. İyi yazılım, kullanıcının gerçek ihtiyacını çözen yazılımdır. Daha sık başarılı sonuç üreten tasarım çözümleri vardır ve bunları bulmanın en iyi yolu, bizzat yazdığın kodu derinlemesine incelemektir
Peki soruyu soran kişi, kendi ekibinin yazılımının berbat olduğunu düşünüp dışarıdan tavsiye arıyorsa ne yapmalı? Ya da sadece bir üniversite öğrencisiyse?
Uygulama için gereken sürenin de tasarım kalitesini değerlendirmede bir ölçü olabileceğini hiç düşünmemiştim ama gerçekten mantıklı geliyor. Ben de ekibimin kod tabanından çok şey öğreniyorum. Bunun büyük kısmı, iyi tasarlanmış bölümlerden doğru şeyleri görmek; kötü kısımlarda ise Google’da araya araya öğrenmeye devam etmek şeklinde oluyor
Biraz eski olsa da, pek çok açık kaynak proje liderinin katkıda bulunduğu "The Architecture of Open Source Applications" diye bir seri var ve internette ücretsiz okunabiliyor
https://aosabook.org/en/index.html
Bu soru daha önce de birkaç kez sorulmuştu; bakılabilecek bazı bağlantıları topladım
Yanderedev kaynak kodu
Doğru cevabı verecek kadar yetkin değilim ama yaklaşık 15 yıl önce "Code Reading" adlı kitabı gerçekten keyifle okumuştum. Konuyla tam örtüşen bir kitap
https://www.spinellis.gr/codereading/
İçindekiler için: https://www.spinellis.gr/codereading/toc.html
Benzer isimli başka bir kitap daha vardı sanki ama tam hatırlamıyorum
Gerçekte kod tabanları çoğu zaman tasarımdan çok uygulamayı içerir. Örneğin her şeyi başka bir dile tamamen yeniden yazsan bile tasarım korunabilir. Tasarım dokümanı yazma alıştırması yapmanı öneririm. Dokümanın nasıl görünmesi gerektiğine fazla takılma, bir şablona da bağlı kalmak zorunda değilsin. En önemlisi, bu dokümanı alan birinin onu olduğu gibi hayata geçirebilmesi. Ayrıca doküman, “düşünülmüş olmanın kanıtı” işlevi de görebilir. Hangi yaklaşımı seçtiğini, başka hangi alternatiflerin değerlendirildiğini ve neden seçilmediğini açıkça yazman yeterli. Alternatifleri önceden kabul edip karşılaştırarak, okuyucuya yeterince düşündüğün konusunda güven verebilirsin. “İyi” sistem tasarımcılarının yaptığı şey, başkalarından daha geniş bir tasarım alanına bakıp tutarlı biçimde iyi noktaları seçebilmektir. Bir problem seç, farklı tasarım alanlarını dene, hangisinin neden daha iyi olduğunu açıkla ve hepsini kayda geçir
Önce şu soruyla başlamak gerekir: “Ben hangi problemi çözmek istiyorum?” Sonra o problemi çözen kod tabanlarını bulup gerçekte nasıl uygulandıklarını ayrıntılı biçimde incelemek. İyi tasarımın, belirli alan bağlamlarına çok sıkı bağlı olduğunu unutmamak gerekir. Bence Wonham’ın Internal Model Principle’ı kod için de geçerli. Örneğin gömülü hedefler için birim testi sorununu çözmek istedim ve ilgili açık kaynak projeleri inceledim; kodun neden o şekilde yazıldığını eleştirel biçimde değerlendirdim. Kendi çözümümü geliştirirken de önceki kodlara tekrar tekrar dönüp baktım ve alan bilgim derinleştikçe daha çok şey öğrenmeye devam ettim
Kendi deneyimime göre (30 yıl yazılım, 25 yıl mimari pratiği, MIT sistem mimarisi yüksek lisansı), soyut anlamda “iyi” diye bir tasarım aslında yok. Açıkça kötü tasarımlar vardır, yani kötü sonuçlar üretenler; ama “iyi”nin ölçütü bağlama göre değişir. Ne inşa ettiğin, güvenlik/emniyet gibi gereksinimler ve hepsinden önemlisi, bunu gerçekten uygulayacak ekip ile o ekibin yapısı belirleyicidir. Tamamen junior geliştiricilerden oluşan bir ekip, çok zarif bir tasarımı yanlış anlayıp mahvedebilir. Conway yasasında olduğu gibi, geliştirme ekibinin yapısı yazılımın içine yansır
Yazılım tasarımı öğrenirken benim için netleşen şeylerden biri de sihirli bir çözüm olmadığı oldu. Keşke öyle bir şey olsa; farklı mimariler ve paradigmalar arasında en uygun çözümü seçmek bazen gerçekten bunaltıcı olabiliyor. Yine de gereksinimleri netleştirmek seçenekleri epey daraltıyor. Şu anda emniyetin özellikle kritik olduğu bir gömülü sistem üzerinde çalışıyorum ve bu ortam yüzünden başka koşullarda asla vermeyeceğim kararlar almak zorunda kalıyorum
Sonuçta mesele, gerçekten saçma uzlaşmalardan kaçınmak ve daha geniş açıdan bakınca en kötü seçeneklerden de uzak durmak. Sahada sürekli hissettiğim şey, bunun “en iyi mimariyi kurma”dan çok “temelden kötü kararları engelleme” savaşı olduğudur
Bir zamanlar çok kısa bir öneri listesi hazırlamıştım, hâlâ geçerli
https://medium.com/@012parth/what-source-code-is-worth-studying-8755f88f8de5
Arada bir tuzak var..
Yanderedev kaynak kodu mu... hahaha