Yazılım mimarisi, bir sistemde yayına girdikten sonra geri alınması pahalıya mal olan kararların toplamıdır; ölçü diyagramın büyüklüğü değil, o bedeldir. Bedeli belirleyen şey kararın içeriği değil zamanı; koddan önce kapanan varsayım sonraki işi tanıma çevirir, geç ulaşan varsayım çoktan yazılmış kayıtların üstüne çekilir. Vipkurum çatısındaki her kurum kendi öğrenci ve ödeme kaydını tutar; hiçbir kayıt komşu kurumun içinde görünmez.
Geri alınamayan kararlar hangileri
Bir kararın mimari olup olmadığını, sonradan geri almanın ne kadar zor olduğu belirler. Bunu en net devraldığınız bir sistemde görürsünüz: dokunabildiğiniz yer, önceki kararların açık bıraktığı yerdir.
Ölçüt soyut kalmasın. Vipkurum çatısındaki yedi kurumun her biri kendi öğrencisini, kendi ders programını ve kendi ödeme kaydını tutuyor; bu kayıtların hiçbiri kurum sınırını geçmiyor. Sınır arayüzde değil, veri modelinin içinde duruyor: kayıt yazıldığı anda hangi kiracıya ait olduğu bellidir. Arayüze sonradan eklenen bir kontrol aynı işi göremez, çünkü kaydın kendisi kime ait olduğunu taşımaz. Taşımayan kaydı bir ekran koruyabilir, bir rapor koruyamaz. Çizgiyi platform yayına girdikten sonra çekmeye kalksanız, çoktan yazılmış her kaydın sahibini yeniden tanımlamanız gerekir.
Bağlantı varsayımı da aynı sınıfta. AlgoKlima’nın saha uygulaması ağ beklemiyor; teknisyen kazan dairesinde ya da asansör boşluğunda kayıt açıyor, kayıt önce telefonun yerel kuyruğuna yazılıyor. Bu bir kuruluş kararı: kaydın ilk yazılacağı yeri belirlediği için sonradan eklenemiyor. Sunucuya yazan bir uygulamayı çevrimdışı çalışır hâle getirmek yeni bir ekran eklemek değildir; kaydın ilk yazıldığı yeri değiştirmektir. O yer değişince kaydın kimliği, sırası ve çakışma davranışı da yeniden tanımlanır.
Bir başkası daha sessiz işliyor. Vipkurum’da değerlendirme türü koda gömülmedi, kurumun kendisine tanımlatıldı. Gömülseydi Avrupa ve Türkiye ölçütleri aynı sınav altyapısında yan yana duramazdı; bunu düzeltmek de sınav motorunu yeniden yazmak olurdu.
Listenin tersi de aynı ölçüte uyuyor. Ekran düzeni, rapor kolonları, panelin menü yapısı diyagramda yer kaplar ama yarın değiştirilebilir; kayıt yapısına dokunmadıkları sürece mimari karar sayılmazlar. Ölçüt her zaman aynı soruyla ölçülüyor: bu kararı geri almak için kaç kaydı yeniden tanımlamak gerekiyor. Cevap hiçbiri ise ortada mimari karar değil, bir tercih vardır. Bu ayrım pratikte zaman kazandırıyor, çünkü koddan önceki tartışmayı geri alınamayan avuç dolusu karara daraltıyor.
Bir mimari kararın en kısa hâli
Koddan önce her sınırı tek cümleye indiriyoruz. Sınır cümlesi, sistemin hiçbir yerinde ihlal edilemeyen tek cümledir. Cümle hem yazılım yazmayan biri hem de yazan biri için işlemeli: biri okuyup ne vaat edildiğini anlayabilmeli, öteki ihlal ettiği anda cümleyi görünür biçimde yanlış hâle getirmeli. Diyagram ihlal edildiğinde sessiz kalır.
Yürüttüğümüz sistemlerin sınır cümleleri şöyle görünüyor.
Vipkurum: öğrenci, veli ve ödeme kaydı kiracı sınırını hiçbir koşulda geçmez. Bir raporun komşu kurumun verisine uzanması bu cümleyi bozar, bozduğu anda da fark edilir.
AlgoKlima: saha uygulaması bağlantı bekleyen bir form değil, kendi başına çalışan bir kayıt defteridir. Kayıt sunucuya değil, önce telefonun yerel kuyruğuna yazılır.
Diş kliniği CRM: randevu, tedavi planının belirli bir adımına bağlıdır. Adım değişince ya da araya seans girince takvim de kayar; hiçbir randevu boşa işaret eden bir kayıt hâline gelmez.
Resterm ısıtıcı seçim yazılımı: bir teklif kaleminin hangi ısıtma ihtiyacı girdisinden çıktığı geriye doğru okunabilir kalır. Hesabın seçtiği ısıtıcı sepete, sepet projeye, proje müşteriye bağlanır; kayıtlar tek zincirde durur. Zincirin herhangi bir yerinde elle taşınan bir değer varsa cümle çoktan bozulmuştur.
Bu cümlelerin ortak yanı şu: her biri ihlal edilebilir. Sınırı yazarken aradığımız şey de bu. İhlal edilemeyen cümle sınır değil, temenni.
Kararın zamanı, sonradan neyi değiştirebileceğinizi belirler
Aynı kararın erken ya da geç alınması, elinizde ne kadar hareket alanı kaldığını belirler. Erken alınan karar yeni işi tanıma çeviriyor: sistem o kararı zaten bekliyor, gelen istek kod değil kayıt üretiyor. Geç ulaşan karar ise mevcut yığının bıraktığı boşlukla sınırlanıyor. Aşağıdaki satırların hepsi kendi işlerimizden; sütunlarda olan biten yazıyor.
| Karar ne zaman alındı | Sonradan ne yapılabildi | Hangi işte |
|---|---|---|
| Kiracı sınırı çekirdek kurulurken veri modeline çizildi | Yeni kurum eklemek yeni kurulum değil, yeni kiracı tanımı oldu | Vipkurum |
| Bağlantı varsayımı mobil taraf kurulurken reddedildi; kuyruğun oluşturulma sırasına göre boşalacağı da o zaman seçildi | Teknisyen kapsama dışında kayıt açtı; çakışan değişiklikler çakışma çözümüyle tek kayıtta birleşti | AlgoKlima |
| Stok hareketinin iş emrinden düşeceği, veri modeli kurulurken karara bağlandı | Fatura aynı kayıttan kesildi; maliyet ve gelir iki programda eşleştirilmedi | AlgoCar |
| Canlı yayın katmanı istemciler çoğalmadan kuruluyor; ürünü şu an inşa ediyoruz | Hedef: web ve mobil istemci aynı Reverb yayınını dinliyor, ikinci güncelleme yolu yazılmıyor | Secretum (geliştirme aşamasında) |
| Depolama düzeni ve önbellek kararı sistem yayındayken bize ulaştı | Değişiklik yalnız sayfa yükünün biriktiği yerlere yapıldı; mevcut çatının dışına çıkılamadı | KGM SsangYong kurumsal site |
Son satır diğerlerinden farklı. Orada karar geç alınmış değil; karar bize geç ulaşmış. Sistem zaten ayaktaydı ve işleyen bölümleri vardı. Yayındaki bir sistemde mimari soru artık hangi tasarımın doğru olduğu değil, ne kadar hareket alanı kaldığıdır.
Üçüncü satır aynı mekanizmayı muhasebe tarafında gösteriyor. AlgoCar’da stok hareketinin iş emrinden düşeceği, veri modeli kurulurken karara bağlandı; bu yüzden faturayı aynı kayıttan kesmek sonradan bir bağlantı kurmayı gerektirmedi. Aynı karar geç alınsaydı, iş emri ile fatura arasındaki bağ çoktan yazılmış kayıtlar üzerine sonradan çekilirdi; geçmiş kayıtlar için o bağ ancak tahminle kurulabilirdi.
Kuyruğun bağlantı dönünce oluşturulma sırasına göre boşalması da bu yüzden erken bir karar. Sıra kuralı sonradan seçilseydi, sahadan ve ofisten gelen çakışan değişikliklerden hangisinin kazanacağını çoktan yazılmış kayıtlar üzerinde çözmek gerekirdi; üstelik hangi kaydın hangi anda oluştuğunu güvenilir biçimde bilmeden.
Kaç yüzey aynı çekirdeği dinleyecek
Bir sistemin kaç arayüzü olacağı ilk bakışta ekran sayısı sorusu gibi görünür. Değildir. Bütün arayüzlerin bağlandığı ortak sunucu tarafına, bu yazıda çekirdek diyoruz. Yüzey sayısı, çekirdeğin kime ne göstereceğini ve verinin hangi yolla güncelleneceğini belirler; çekirdek kurulduktan sonra değiştirilmesi en pahalı varsayımlardan biridir.
Tahlil.com’da bu soru baştan kapandı. Değerlerin girildiği hasta sitesi, yorumun yazıldığı hekim paneli ve yorum onaylandığında hastayı geri çağıran mobil uygulama tek Laravel çekirdeğine bağlı. MySQL kayıtları tutuyor, Redis önbelleği taşıyor, OneSignal yorum hazır olduğunda bildirimi gönderiyor. Yüzeylerin hepsi aynı veri modelini okuyor; aralarındaki fark yetki.
AlgoKlima’da aynı ayrım ofisle saha arasında duruyor. Ofis paneli Laravel ve Inertia ile, saha uygulaması React Native (Expo) ile kurulu. İkisi ayrı kopyalar tutmuyor; aynı MySQL çekirdeğindeki aynı müşteri ve cihaz kaydını okuyor. Sahadan ve ofisten gelen değişiklikler çakışma çözümüyle tek kayıtta birleşiyor. Ayrı kopyalar tutulsaydı, hangi kopyanın doğru sayılacağını belirleyen kural sistemin ortasına sonradan yazılmak zorunda kalırdı.
Şu an inşa ettiğimiz Secretum’da aynı kararı istemciler çoğalmadan bağlıyoruz. Laravel tarafında kurulan tek Reverb yayınını hem Vue 3 web arayüzü hem React Native (Expo) istemcisi dinliyor; ikinci bir güncelleme yolu yazılmıyor. İkinci yol açılsaydı, her yeni özellik iki ayrı yerde güncellenmek zorunda kalırdı ve ikisinin ayrışmadığını kimse garanti edemezdi.
Karşı durum da var: her iş çok yüzey istemez. Tek panelle çalışan bir sistemde ikinci yüzey için altyapı kurmak boşa maliyettir. Kural şu: yüzey sayısı sorusu çekirdek kurulmadan sorulur.
Türetilen kayıt mı, ikinci kez girilen kayıt mı
Bir bilgi sistemde iki yerde yaşıyorsa er ya da geç birbirinden ayrışır. Bunu önleyen karar teknik değil yapısal: hangi kaydın kaynak, hangisinin türev olduğunu sistemin ilk günü belirlersiniz.
AlgoCar’da parça tüketimi iş emrine yazıldığı anda stoktan düşüyor. Depo hareketi ayrı bir ekranda ikinci kez elle girilmiyor. Fatura da aynı kayıttan kesiliyor: iş emri, tüketilen parça ve fatura tek kayıt zincirinde ilerliyor. Bir işin maliyeti ile geliri iki ayrı programda eşleştirilmiyor, çünkü ikisi zaten aynı zincirin üstünde duruyor. Bu, veri modeli kurulurken verilen bir karardı; stok hareketinin iş emrinden düşeceği baştan yazıldı.
Şantiye personel takip sisteminde aynı ayrımı hak ediş üzerinde kurduk. Hak ediş ayrı bir hesap tablosunda tutulmuyor, eşleşen giriş-çıkış kayıt çiftlerinden üretiliyor. QR kod kimin okuttuğunu, konum hangi sahada olduğunu belirliyor ve ikisi tek giriş kaydında birleşiyor. Açık kalan bir giriş, çıkışı okutulana kadar eksik kayıt olarak görünür duruyor. İtiraz çıktığında dayanak, kaynak kayıt çiftinin kendisi oluyor.
Karşı durum burada net. Türetme zinciri ancak kaynak kayıt sistemin içinde oluşuyorsa kurulabilir. Devralınan bir sistemde kaynak kayıt dışarıda oluşuyorsa, yani başka bir programda ya da elle tutulan bir tabloda, zinciri sonradan kurmak sistemi yeniden yazmak demektir. Bu yüzden soru mimari sorusudur: cevabı geç verildiğinde ortada verilecek cevap kalmaz.
Devraldığınız sistem, ödünç aldığınız kısıtlardır
Bu yazıyı okuyanların çoğu boş bir depoyla başlamıyor. Elinde çalışan ama yaşlanmış bir sistem var ve sıfırdan yazmak istemiyor. KGM SsangYong’un kurumsal sitesi bize böyle geldi.
Sıra şuydu: önce kod tabanını okuduk, çalışan bölümlere dokunmadık, sonra ağırlığın nerede toplandığını bulup oradan başladık. Devralınan bir sistemde ilk mimari iş yeni bir tasarım çizmek değil, hangi kısıtların ödünç alındığını yazmaktır. Sınır şuydu: yapılan her değişiklik sitenin bugün çalışan davranışını olduğu gibi bırakacaktı. Bu kısıt neyi yapabileceğimizi olduğu kadar hangi sırayla yapabileceğimizi de belirledi; önce ağırlığın nerede olduğunu gördük, sonra dokunduk.
Katalog okumalarını Redis önbelleğine aldık; aynı sorgu artık her ziyaretçi için baştan çalışmıyor, MySQL yalnız veri değiştiğinde devreye giriyor. Araç görsellerini tek adlandırma ve klasör düzenine taşıdık; hangi modelin hangi dosyayı kullandığı kod okumadan görülüyor. İkisi de sistemi yeniden yazmadan yapılabilecek işlerdi; önceki kararların bıraktığı hareket alanı buydu.
Kapalı olan karar çatıydı. Mevcut Laravel, Tailwind ve jQuery setinin dışına çıkmadık; önbellek katmanı dışında hiçbir şey eklemedik. Devralarak iyileştirme, yazılım danışmanlığı işlerimizin çoğunun nasıl başladığını da anlatıyor: elde çalışan bir sistem var ve soru onun yerine ne konacağı değil, içinde ne yapılabileceğidir. Bu noktadan sonrası ayrı bir karar: sistemi kimin sürdüreceği sorusunu bakımı kimin üstlendiği üzerine yazdığımız yazıda açıyoruz.
Yığın seçmek de bir mimari karardır
Yığın seçimi genelde teknoloji tercihi sayılır. Biz geri alması en pahalı kararlardan biri olarak görüyoruz, çünkü sistemi kimin ayakta tutabileceğini belirliyor.
Proje başına yeni yığın seçmiyoruz; yıllarca bakılabilecek tek yığın seçiyoruz. Çekirdekte Laravel, MySQL ve Redis var, arayüzde Inertia ve Tailwind. Masadan çıkan her telefon uygulaması React Native (Expo) ile kuruluyor ve ofis paneliyle aynı çekirdeğe bağlanıyor. AlgoKlima’da saha uygulamasıyla panelin ayrı kopyalar yerine aynı müşteri ve cihaz kaydını okumasının nedeni bu.
Uzman çalışma zamanı yalnız problem zorladığında giriyor: görüntü işleme için Python ve OpenCV, üretken model gerektiğinde Gemini ya da OpenAI. Vipkurum çatısı altında geliştirilen optik okuma ve soru kırpma araçları bu istisnadan çıktı. İstisnanın kuralı şu: uzman araç problemin kendisini çözmek için giriyor, çekirdeğin yerine geçmek için değil. Okunan optik form yine aynı kayıt düzenine düşüyor.
Yığını dar tutmanın nedeni beğeni değil bakım. Bakımı sürdürecek ekibin bildiği araçların dışına çıkmak, sonradan geri alması en pahalı hamlelerden biri. SsangYong’da bunu tersinden gördük: yeni bir bağımlılık o haftaki işimizi kolaylaştırırdı, ama siteyi mevcut yığınının dışına taşırdı. Set korundu, iş setin içinde bitti.
İlk satır yazılmadan önce neyi bağlarız
Koddan önce kapattığımız başlıklar sabit, sıra da genelde şöyle işliyor.
Önce sistem haritası çıkıyor: veri kaynakları, aktörler, entegrasyonlar. Tahlil.com’da bu harita bütün yüzeyleri tek bir Laravel çekirdeğine bağladı; hangi yüzeyin hangi kaydı hangi yetkiyle okuyacağı o aşamada belli oldu.
Sonra yüksek riskli yol yürünüyor. Aynı projede yapay zekâ ön okumayı hazırlıyordu, ama hastaya ulaşan metnin son sözü hekimde kalacaktı. Bu bir sorumluluk sınırı ve veri sınırından ayrı bir karar sınıfı: veri sınırı hangi kaydın nereye gideceğini, sorumluluk sınırı kimin neyi onayladığını belirliyor. İkincisi de koddan önce bağlandı, çünkü onay adımı sonradan eklenen bir ekran değil akışın kendisi.
Bu sıra keyfi değil. Harita çıkmadan sınır cümlesi yazmak, hangi aktörün hangi kaydı göreceği bilinmeden kural koymak olur; kural o zaman ekranların diline yazılır ve ekran değişince anlamını kaybeder. Yüksek riskli yolu önce yürümenin nedeni de bu: sistemin en pahalı varsayımı orada duruyor ve yanlış çıkarsa haritayı da beraberinde değiştiriyor.
Ardından kısıtlar yazılıyor: bakımı kim sürdürecek, sistem hangi ortamda çalışacak, neyin çalışmaya devam etmesi gerekiyor. Devralınan işlerde bu sorular mimarinin kendisi oluyor.
En son her sınır tek cümleye iniyor. Cümlenin ihlali görünür olmayacaksa, o sınır henüz yazılmamış demektir.
Erken bağladığımız üç karar
Yeni bir sistem kurarken de yaşlanmış bir sistemi devralırken de erken verdiğimiz kararlar şunlar.
- Her sınır tek cümleye iner. İhlal edildiğinde görünmeyen sınır, sınır değildir; Vipkurum’daki kiracı sınırı bu modelin en net hâli.
- Bağlantı, kiracı, sorumluluk ve yüzey sayısı gibi varsayımlar koddan önce kapanır. AlgoKlima’nın yerel kuyruğu bu kararın çalışan hâli.
- Yığın, sistemi ayakta tutacak ekibin bildiği araçlardan seçilir; devralınan bir sistemde hareket alanını bu karar belirler.
Bu maddeler sistem mimarisi çalışmasında masaya ilk koyduklarımız. Geri kalan her şey, desenler, klasör düzeni ve o dönemin gözde çatısı, sonradan değişebilir. Bunlar değişmiyor.