Mimari nedir, ne değildir
"Mimari, sonradan değiştirmesi pahalı olan kararlar bütünüdür." - Ralph Johnson
Mimari, "hangi framework'ü kullandık" değildir - bu bir uygulama detayıdır. Mimari, kod tabanınızı dolaştığınızda hissedilen şekildir: modüller nasıl ayrılmış, bağımlılıklar hangi yönde akıyor, hangi koddan hangi koda çağrı yapılabilir.
İyi bir mimari, bir geliştiricinin yeni bir feature eklemek için nereye yazması gerektiğini belirsizlik olmadan söyler. Kötü mimari, bu soruyu her seferinde tartışma haline getirir.
Mimari kararların maliyeti
Bir mimari kararın gerçek maliyeti, alındığı anda değil, ona dayanan kararların sayısı arttıkça ortaya çıkar. Üç ölçü:
- Tersine çevirme süresi - kararı geri almak için kaç hafta?
- Etki alanı - karara dayanan kaç dosya / modül var?
- Bilişsel yük - yeni bir geliştirici kararı anlamak için kaç saat ister?
Bir kural koymadan önce sorun: bu kararın üç ay sonra yanlış olduğunu fark edersem, geri almak ne kadar acı verir?
Niyet ve uygulama
Mimari, almayı düşündüğünüz kararların toplamıdır; kod tabanı ise gerçekte inşa edilendir. İkisi arasındaki fark mimari kaymadır - ve bir saat sürmesi gereken bir değişiklik bir hafta sürene kadar sessizce büyür.
İş, bir kez mükemmel diyagramı çizmek değildir. Niyet ile uygulamayı, diyagramın kodun nasıl davrandığını hâlâ öngörebileceği kadar yakın tutmaktır.
Katmanlı (n-katman)
Klasik ayrım: sunum → uygulama → alan → veri. Her katman yalnızca altındakini çağırabilir. Öğretmesi en kolay, ihlali de en kolay modeldir - arayüzden doğrudan veri katmanına tek bir çağrı, ve katmanlama bir kurgudan ibaret kalır.
Ekip küçük ve domain basitken kullanın. Zayıf yanı, iş mantığının yukarıda controller'lara, aşağıda veritabanına sızma eğilimidir.
Altıgen · Portlar ve Adaptörler
Alan merkezde durur ve dış dünyadan hiçbir şey bilmez. Veritabanı, HTTP, mesaj kuyruğu gibi dışsal olan her şey, alanla adaptörlerin uyguladığı portlar (arayüzler) üzerinden konuşur.
Kazanç test edilebilirlik ve değiştirilebilirliktir: testlerde Postgres'i bellek-içi bir sahteyle, ya da REST'i gRPC ile, tek satır alan kodu değiştirmeden takas edebilirsiniz.
Clean Architecture
Hexagonal mimarinin bir adım ötesi: bağımlılıkların yalnızca içeriye, domain varlıklarına doğru baktığı iç içe halkalar. Framework'ler, arayüz ve veritabanları en dış halkada durur; bunlar çekirdek değil, ayrıntıdır.
Size hiçbir altyapı olmadan derlenen ve test edilen bir domain kazandırır. Bedeli ek kalıptır: daha çok arayüz, daha çok eşleme. Uzun ömürlü sistemler için değer, basit bir CRUD yönetim paneli için fazlalık.
DDD - Alana Dayalı Tasarım
DDD bir framework değil, bir dil disiplinidir. "Aggregate", "bounded context", "anti-corruption layer" - bunlar problemi tanımlamak için ortak bir kelime dağarcığıdır.
Ne zaman DDD?
- Domain karmaşıktır ve teknik karmaşıklıkla karıştırılır.
- Birden fazla ekip aynı domain üzerinde çalışıyor.
- İş tarafıyla geliştirici tarafı farklı dilde konuşuyor.
DDD her proje için değildir. CRUD yoğun bir admin paneli için fazla geliyorsa, muhtemelen öyle.
Büyük Çamur Topu
Belirgin bir mimari yok: her şey her şeye bağlı, durum küresel olarak paylaşılıyor ve bir değişikliği anlamanın tek yolu onu çalıştırmak. Çoğu sistem buraya bir kararla değil, bin teslim tarihiyle gelir.
Büyük çamur topu baştan yazılmaz; strangler deseniyle adım adım küçültülür. Bir sınır belirleyin, tek bir yeteneği temiz bir arayüzün arkasına taşıyın, tekrarlayın. AppArch'ın bağımlılık haritası bu sınırların nereden geçebileceğini gösterir.
Antipattern: Tanrı modülü
"Tanrı modülü", projenin her tarafından çağrılan, içinde her şey olan modüldür. Utils, Common, Shared isimleri uyarı işaretidir.
# bunu tespit eden bir kural - id: GOD-001 max_fan_in: 25 message: "Module imported by >25 files - split or rename"
Çözüm: kabaca üç parçaya böl. Birinci grup gerçek altyapı (logger, config). İkinci grup domain primitif (money, id). Üçüncü grup - büyük ihtimalle ayrı bir modül.
Döngüsel bağımlılıklar
A modülü B'ye, B de A'ya ihtiyaç duyar. Artık hiçbiri tek başına anlaşılamaz, test edilemez veya dağıtılamaz, ve derleme sırası yazı-turaya döner. Döngüler, kimsenin dokunmak istemediği bir modülün en güvenilir habercisidir.
Döngüyü, paylaşılan kavramı ikisinin de bağımlı olduğu üçüncü bir modüle çıkararak ya da bir yönü bir arayüzle tersine çevirerek kırın. AppArch döngüyü merge request'te ortaya çıktığı anda işaretler.
Sızdıran soyutlamalar
Bir soyutlamayı doğru kullanmak için arkasında nasıl çalıştığını bilmeniz gerekiyorsa, o soyutlama sızdırıyordur: SQL istisnaları fırlatan bir repository, çağıranları eskimiş veriyle uğraşmaya zorlayan bir önbellek. Bir ayrıntıyı gizlemeye söz vermiş ama gizleyememiştir.
Ya sızıntıyı kapatın, altyapı hatalarını sınırda kendi hata türlerinize çevirin; ya da soyutlamayı kaldırın. Sızdıran bir soyutlama hiç olmamasından kötüdür: dolaylılığın bedelini ödersiniz ama yalıtımı elde edemezsiniz.
Mimari inceleme
İnceleme, merge'leri durduran bir bariyer değildir; bir değişikliğin sistemi hedeflenen biçimine yaklaştırıp yaklaştırmadığı üzerine bir konuşmadır. En iyi incelemeler 'bu şu an doğru mu?' yerine 'bu, ileride neyi zorlaştırıyor?' diye sorar.
Hafif ve sürekli tutun. Her önemli merge request'te yapılan kısa bir inceleme, herkesin atlatmaya çalıştığı, üç ayda bir toplanan bir mimari kuruldan iyidir.
Mimari Karar Kayıtları (ADR)
Bir ADR tek bir kararı yakalar: bağlam, değerlendirilen seçenekler, seçim ve sonuçları - bir-iki paragraf, kodun yanında sürümlenmiş. Altı ay sonra önemli olan tek soruyu yanıtlar: bu neden böyle?
ADR'yi karar verildiği anda yazın, sonradan değil. Eski kararı silmeyin, yenisiyle geçersiz kılın: fikrinizi neden değiştirdiğinizin izi, güncel cevap kadar değerlidir.
Büyük yeniden düzenleme
Tek seferde merge edilen dev bir refactor, kılık değiştirmiş bir baştan yazımdır ve ilk sorunda geri alınır. Gerçek refactor, her biri tek başına yayına alınabilen, küçük ve davranışı koruyan adımlardan oluşur.
Yeni yolu eskinin yanına ekleyin, çağıranları kademeli olarak taşıyın, sonra eski yolu silin. Testler güvenlik halatıdır; onlar olmadan yeniden düzenleme yapmıyorsunuz, kumar oynuyorsunuz.