Clean Architecture kararı için endpoint sayısını esas almak kolay ama yanıltıcıdır. Üç endpoint kullanan bir uygulamanın karmaşık fiyatlandırma kuralları olabilir. Elli endpoint kullanan başka bir uygulama ise ağırlıklı olarak veri bakım ekranlarından oluşabilir. Kararı dosya sayısı değil, değişimin nereden geldiği belirler.
Küçük bir katalog API’si düşünelim. Ürün listesi, ürün detayı ve yetkili güncelleme işlemi var. Ayrı deployment, dış sistem entegrasyonu veya karmaşık domain kuralı henüz yok. Bu uygulamada her entity için repository, service, handler ve mapper üretmek bakım maliyetini artırabilir. Aynı sorgu dört dosyadan geçiyor, fakat bu dosyalar bağımsız bir değişim sınırını korumuyorsa kazancı sorgulamak gerekir.
Clean Architecture kararı için önce değişim senaryosunu yazmak
Katalog API’sinin ilk sürümünde müşterinin ihtiyacı ürün bilgisini görüntülemek olsun. Ürün adı, aktiflik durumu ve satış fiyatı bir tabloda tutuluyor. İlk bakışta Domain, Application, Infrastructure ve API projeleri kurmak tanıdık bir çözüm olabilir. Ancak bu çözümün hangi değişikliği kolaylaştıracağını söyleyemiyorsak henüz mimari faydayı göstermiş olmayız. Bir sonraki isteğin ürün açıklamasına yeni alan eklemek olması, çoğu katman şemasında bütün dosyalara yayılabilir. Mimariyi değerlendirirken yalnızca dosyaların düzenli görünmesini değil, değişikliklerin neden farklı yerlere dokunduğunu incelemek gerekir.
Şimdi ikinci bir senaryo ekleyelim. Kurumsal müşteriye farklı fiyat uygulanıyor, kampanyaların birlikte kullanılması bazı koşullarda yasaklanıyor ve aynı fiyatlandırma toplu teklif job’ında da çalışıyor. Bu noktada HTTP endpoint içine yazılan kuralların tekrar kullanılabilmesi gerekir. Request nesnesi veya HTTP status code, fiyatlandırma kararının doğal parçası değildir. Application işlemi ve domain kuralı ayırmak somut fayda sağlayabilir. İki uygulamanın endpoint sayısı aynı olsa bile mimari ihtiyacı değişmiştir. Dolayısıyla Clean Architecture kararını API yüzeyinin büyüklüğüyle eşitlemek, işin karmaşıklığını gözden kaçırır.
Üçüncü senaryoda dış bir ERP’den katalog bilgisi geliyor. ERP’nin veri modeli sık değişiyor ve bağlantısı zaman zaman kesiliyor. Burada bir adapter sınırı, dış sistemin alan isimlerini ve hata biçimini uygulamanın kendi anlamından ayırabilir. Bunun için her entity’ye repository eklemek gerekmeyebilir. Gerçek sınır dış sistemin contract’ıdır. İçerideki sade sorgular aynı biçimde kalabilir. Böyle bir örnek, mimariyi uygulamanın her yerine eşit yoğunlukta dağıtmanın gerekli olmadığını gösterir. Değişim sebepleri farklıysa korunacak sınırlar da farklı olabilir.
Karar görüşmesinde soyut bir bağımsızlık hedefi yerine üç olası değişikliği masaya koyun. Yeni business rule, yeni giriş kanalı ve yeni dış sistem gibi senaryolarda hangi kodların değişeceğini işaretleyin. Bir katman bu değişikliklerin etkisini gerçekten sınırlıyorsa maliyetini savunabilirsiniz. Katmanın yalnızca parametreleri başka metoda geçirdiği görülüyorsa gerekçesi zayıftır. Bu çalışma gelecek bütün ihtiyaçları tahmin etmeyi gerektirmez. Yakın ve makul değişimler üzerinden bugün nasıl bir düzenin yeterli olacağını tartışmayı sağlar. Bilinmeyen geleceği bütün interface’leri üretmek için sınırsız gerekçe olarak kullanmayın.
Katmanların maliyeti nasıl görünür hale gelir?
Bir ürün detayı isteğinin endpoint, handler, application service, repository ve mapper üzerinden geçtiğini düşünelim. Her parçanın ayrı sorumluluğu olabilir; örneğin authorization, business orchestration ve query translation farklı işlerdir. Ancak beş parçanın hepsi yalnızca aynı kimliği bir sonraki metoda veriyorsa abstraction maliyeti oluşmuştur. Yeni bir alan ekleyen geliştirici hangi contract’ın müşteriye, hangisinin uygulama içine ait olduğunu çözmek zorunda kalır. Değişiklik yüzeyi büyüdükçe review sırasında asıl davranışı görmek de zorlaşabilir. Bu maliyet dosya sayısından çok takip edilmesi gereken karar zinciridir.
Interface sayısı test kalitesinin güvenilir ölçüsü değildir. Her dependency mock’lanabiliyor olsa bile test yalnızca repository metodunun çağrıldığını doğrulayabilir. Ürünün bulunmaması halinde doğru HTTP yanıtının üretilmesi, query’nin provider tarafından çevrilmesi veya tenant filtresinin uygulanması bu testte görülmeyebilir. Öte yandan saf fiyatlandırma kuralını database olmadan çalıştırabilmek güçlü bir avantajdır. İki durumu ayırmak gerekir. Mimari, gerçek kuralı bağımsız sınayabiliyorsa değerlidir; uygulamada kural olmayan bütün sorgular için aynı test kalıbını üretmek değerini kendiliğinden artırmaz.
Operasyonel maliyet de yalnızca runtime performansı değildir. Bir hata oluştuğunda geliştirici log’daki metodun hangi feature’a ait olduğunu bulabilmeli, deployment konfigürasyonunu anlayabilmeli ve problemin kaynağına ulaşabilmelidir. Çok genel isimlerle oluşturulmuş service ve handler zincirleri bu takibi zorlaştırabilir. Bunun yanında her feature’ın bütün infrastructure detaylarını kopyalaması da farklı bir bakım riski yaratır. Ortak logging, hata eşleme ve authentication düzeni ile business akışının yerini ayrı değerlendirin. Ortak bir ihtiyaç görmek, business işlemlerini tek dev bir service içinde toplamak için gerekçe değildir.
Clean Architecture kararı sırasında bakım maliyetini ekip üzerinden de düşünün. İki kişinin geliştirdiği küçük bir iç uygulamayla farklı ekiplerin uzun süre yöneteceği büyük bir sistem aynı onboarding ihtiyacını taşımaz. Bununla birlikte büyük ekip, her işleme aynı sayıda katman koymayı haklı çıkarmaz. Açık ownership, tutarlı feature isimleri ve belgelenmiş bağımlılık kuralları çoğu zaman daha doğrudan fayda sağlar. Seçilen düzenin günlük bir değişiklikte nasıl kullanıldığını gösteren küçük bir örnek hazırlamak, klasör ağacı çizmekten daha açıklayıcı olabilir. Mimari karar kullanıcıya ulaşan davranış üzerinden değerlendirilmelidir.
Sade başlamak düzensiz başlamak değildir
Tercihim, bu kapsamda feature odaklı bir düzen ve doğrudan, açık bağımlılıklar. Products klasöründe endpoint, request ve sorgu birlikte bulunabilir. Ortak hata yönetimi ve authentication host seviyesinde kalır. İş kuralları büyüdüğünde domain modeline taşınır; endpoint’i bütün uygulamanın iş mantığı haline getirmeyiz.
Aşağıdaki .NET 10 Minimal API, sade başlangıç fikrini gösterir. dotnet new web --framework net10.0 ile çalıştırılabilir; dış paket gerekmez. Veri deposu bilerek bellektedir. Gerçek projede persistence, authorization, validation ve operasyon gereksinimleri ayrıca eklenir.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var products = new Dictionary<int, ProductDto>
{
[1] = new(1, "Keyboard"),
};
app.MapGet(
"/products/{id:int}",
(int id) =>
products.TryGetValue(id, out var product)
? Results.Ok(product)
: Results.NotFound()
);
app.Run();
public sealed record ProductDto(int Id, string Name);
Dictionary sabittir ve yalnızca okunur. Örneğe mutable yazma endpoint’i ekleyip eşzamanlı dictionary değişikliğini güvenli kabul etmeyin. Bu API’nin amacı bir production katalog sistemi sunmak değil, basit bir sorgu için zorunlu olmayan katmanları görünür hale getirmektir.
Hangi değişim abstraction gerektirir?
Bir fiyatlandırma kuralı HTTP dışında job veya mesaj consumer tarafından da kullanılıyorsa, transport’tan ayrılmış application işlemi değerlidir. Birden fazla dış ödeme sağlayıcısı varsa onların contract’ını domain’den korumak da anlamlıdır. Buna karşılık yalnızca EF Core çağrılarını isim değiştirerek saran bir interface, her zaman bağımsızlık sağlamaz.
Clean Architecture’ın dependency yönü esas alınabilir; her projede aynı fiziksel proje şeması kurulmak zorunda değildir. Mevcut Clean Architecture yazısı ile birlikte değerlendirirken, hangi kuralın Infrastructure bağımlılığından korunacağını açıkça yazın. Bir sınırı tanımlayamıyorsanız yeni katman açmadan önce senaryoyu netleştirin.
Test maliyetini de karara katmak
Basit bir API’nin yalnızca mock kullanılan unit testlerle doğrulanması, query translation veya gerçek constraint davranışını göstermez. Application katmanı eklemek de bu eksikleri otomatik kapatmaz. İş kuralları için hızlı testler, veritabanı ve HTTP davranışı için entegrasyon testleri farklı sorulara cevap verir.
EF Core test stratejisi dokümantasyonu, gerçek provider ve test double seçeneklerinin farkını ele alıyor. Hedefiniz kolay test yazmak kadar, hangi davranışın doğrulandığını doğru sınırlandırmak olmalı.
Kararım; domain karmaşıklığı, birden fazla giriş kanalı, bağımsız değişen dış sistemler veya ekip ownership ihtiyacı büyüdüğünde değişir. O noktada katman ayrımı maliyetini karşılayabilir. Başlangıçta olmayan gereksinimler için tüm şemayı kurmak yerine, sade yapıyı yeni sınırları çıkarabilecek kadar açık tutmak yeterlidir.
Minimal API örneğinin kapsamını doğru okumak
Örnekte WebApplication.CreateBuilder host hazırlığını başlatıyor, Build uygulamayı oluşturuyor ve MapGet bir route tanımlıyor. /products/{id:int} şablonunda kimlik integer olarak alınır. Dictionary’de ürün varsa DTO, yoksa NotFound sonucu döner. Bu kodun kısalığı bütün katalog sisteminin birkaç satırdan oluşabileceğini kanıtlamaz. Gösterilen davranış tek bir okuma isteğidir. Fiyatlandırma, yazma yetkisi ve persistence işlemleri henüz bulunmuyor. Öğretim örneğiyle kapsamlı uygulamayı aynı düzeyde yorumlarsak gereksiz katman eleştirisini gerekli sorumlulukları silmeye dönüştürebiliriz.
Sabit dictionary, veri yaşam döngüsünü kolaylaştırmak için seçildi. Veri yalnızca uygulama başlarken ekleniyor ve endpoint çalışırken değiştirilmiyor. Bu yüzden örnek üzerinde bir yönetim yazma endpoint’i bulunmuyor. Yazma eklenirse concurrency, validation, authentication ve authorization gibi konular yeniden tasarlanır. Mevcut örneğin okuma testinin geçmesi, bu ek davranışların güvenli olduğunu göstermez. Basit bir kodu genişletirken her yeni davranışın getirdiği garantiyi ayrı düşünmek gerekir. Kısa örneğin sınırlarını korumak, makalenin mimari argümanını zayıflatmaz; tersine argümanı daha doğru konumlandırır.
Buradaki DTO dışarıya verilecek veri biçimini açık hale getirir. Gerçek EF entity’sini doğrudan response olarak döndürmek navigation property, iç alan veya persistence davranışının API contract’ına taşınmasına yol açabilir. Bunun önlenmesi için mutlaka ayrı bir mapper framework gerekmez. Küçük bir projection veya açık bir constructor çağrısı yeterli olabilir. Hangi alanların istemciye açıldığını kolayca görmek, araç seçiminin önündedir. Daha sonra model büyürse mapping düzeni yeniden değerlendirilebilir. Sade mimari, istemci contract’ını iç modelden ayırma sorumluluğunu kaldırmaz.
Feature düzeni büyürken hangi kod nereye gider?
Ürün okuma feature’ı içinde route kaydı, request bilgisi ve response modeli bir arada bulunabilir. Aynı feature’ın EF sorgusunu da yakın tutmak, yeni alanın nasıl üretildiğini anlamayı kolaylaştırır. Buna karşılık fiyatlandırma kuralı başka feature tarafından kullanılmaya başlarsa onu endpoint dosyasından çıkarmak gerekir. Ayrımı teknik dosya türlerine göre değil, paylaşılan kararın anlamına göre yapmak daha kullanışlıdır. Bir sınıfın adı service olduğu için bağımsız iş sorumluluğu kazanmaz. Ürünün fiyatını hesaplayan karar ile HTTP’den parametre okuyan mekanizma farklı sorumluluklardır.
Tekrarlanan kod görüldüğünde hemen ortak base class üretmeyin. İki endpoint’in bugün benzer olması, yarın birlikte değişeceği anlamına gelmez. Ortak kodun gerçek sebebini inceleyin. Aynı authorization politikasını uygulamak ortak ihtiyaç olabilir. Farklı iş kurallarının aynı property adlarını kullanması ise ortak domain modeli için yeterli değildir. Gereksiz ortaklık, sonraki değişiklikte koşul parametreleri ve override metotlarıyla büyüyebilir. Feature düzeni içinde küçük tekrarları kabul etmek bazen daha açık bir tasarımdır. Ancak güvenlik politikalarının kopyalanarak farklılaşması gibi etkisi yüksek tekrarlar merkezi bir mekanizmayla korunmalıdır.
Bir feature dosyası çok büyüdüğünde ilk çözüm yeni katman yaratmak olmayabilir. Birden fazla kullanım senaryosu aynı dosyadaysa işlemleri ayırabilirsiniz. Bir sorgunun projection’ı büyükse response modelini yanına taşıyabilirsiniz. Business kararları yoğunlaşmışsa onları saf bir modele çıkarabilirsiniz. Böylece büyümenin sebebiyle yapılan ayrım arasında ilişki kurulur. Dosya satır sayısı yararlı bir sinyaldir, fakat mimari gerekçenin tamamı değildir. Yeni bir interface oluşturduğunuzda hangi bağımlılığın korunacağını tek cümlede açıklayabilmek iyi bir kontrol noktasıdır.
İş kurallarını transport ve persistence’tan ayırmak
Kurumsal fiyatlandırmada müşterinin sözleşmesi, ürün grubu ve kampanya koşulları kararı etkileyebilir. HTTP request yalnızca bu işlemin başlatıldığı kanallardan biridir. Aynı karar arka plan job’ında da çalışacaksa fiyatlandırmayı doğrudan HttpContext kullanan bir sınıfa bağlamak yeniden kullanım alanını daraltır. Burada application işlemi transport bilgisini anlamlı girdilere çevirebilir. Domain modeli fiyatın nasıl hesaplanacağını veya hangi kombinasyonun geçersiz olduğunu belirler. Response status code ise endpoint’te seçilir. Bu ayrım, gerçekten aynı karar birden fazla kanalda kullanılacaksa değerini hemen gösterir.
Persistence açısından da her alanın business rule olması gerekmez. Bir ürün listesinde filtreleme ve sayfalama ağırlıklı olarak query sorumluluğu olabilir. Buna karşılık sipariş durumunun geçiş koşulu bir invariant olabilir. İkisini aynı generic service kalıbına sokmak, hem query’yi hem domain’i gereksiz yere karmaşıklaştırabilir. Application katmanı orchestration yaparken transaction sınırını da açık tutmalıdır. Bir repository’nin kendi içinde bağımsız SaveChanges çalıştırması, kullanım senaryosunun iki değişikliği atomik yapma ihtiyacını bozabilir. Katmanların varlığı bu davranışı otomatik olarak doğru hale getirmez.
Clean Architecture kararı ve test stratejisi
Örnek API için ilk anlamlı kontroller var olan ürünün 200 ile beklenen DTO’yu dönmesi ve olmayan ürünün 404 üretmesidir. Bu kontroller gerçek HTTP davranışını sınar. Sadece dictionary’nin içinde ürün bulunduğunu test etmek route’un doğru çalıştığını göstermez. Authentication eklendiğinde anonim ve yetkisiz kullanıcı durumları ayrıca ele alınmalıdır. Request validation eklendiğinde hangi hata biçiminin döneceği kontrol edilmelidir. Her yeni sınır, uygulanmış bir davranışla birlikte doğrulanmalıdır. Henüz bulunmayan özellikler için test sayısını artırmak mevcut örneğe fazladan güven atfetmemelidir.
Fiyatlandırma modeli çıkarıldıktan sonra çoğu kural testini host başlatmadan çalıştırmak mümkündür. Müşteri grubu, kampanya ve geçersiz kombinasyonlar hızlı testlerle kontrol edilebilir. EF query’sinin gerçekte nasıl çalıştığını anlamak için ise provider uygunluğu gerekir. Mock nesnesi bütün kayıtları bellekte filtrelediğinde SQL çevirisini, collation farklarını veya constraint davranışını göstermeyebilir. Dolayısıyla hızlı unit test ve integration test birbirinin yerine geçirilmemelidir. İkisinin de hangi soruya cevap verdiği açıksa sade bir mimariyle güçlü doğrulama kurulabilir. Katman sayısını test güvencesinin vekili olarak kullanmayın.
Test kolaylığı için repository ekleme kararı özellikle dikkat ister. Repository gerçekten uygulamanın veri erişim sınırını tanımlıyorsa mock ile bazı orchestration testleri anlamlı olabilir. Ancak yalnızca DbSet metodunu aynı isimle sarmalıyorsa SQL davranışı yine başka yerde test edilmelidir. Bunun yanında test double üzerinden kurulmuş başarı yolu production’da oluşan hata biçimini gizleyebilir. Domain doğruluğu ile database doğruluğunu ayrı düşünmek, hangi abstraction’a ihtiyaç duyulduğunu daha iyi gösterir. Test yazma süresini azaltan her tasarımın doğrulanan davranış alanını koruduğunu varsaymayın.
Dependency kuralını fiziksel proje ağacından ayırmak
Clean Architecture’ın merkezindeki bağımlılık fikri, içteki iş kurallarının dıştaki mekanizmalara gereksiz şekilde bağlanmamasıdır. Bu fikri uygulamak için her çözümde aynı sayıda assembly gerekmez. Küçük bir sistemde namespace ve açık reference düzeni yeterli olabilir; daha güçlü derleyici sınırı gerektiğinde ayrı proje eklenebilir. Microsoft’un web uygulaması mimarileri rehberi bu yaklaşımın sorumluluk ve bağımlılık yönünü açıklıyor. Buradan her endpoint için zorunlu dosya şablonu çıkarmak, ilkeyi mekanik bir üretim kuralına indirger.
Fiziksel ayrımın da açık faydaları vardır. Domain projesinin EF Core veya ASP.NET Core paketine reference taşıyamaması, bazı ihlalleri derleme sırasında engeller. Buna karşılık projeler arasında ortak tip tasarımı, build düzeni ve navigation maliyeti oluşur. Karar bu iki tarafla birlikte verilmelidir. Sınırın sık ihlal edildiği, birden fazla ekibin çalıştığı veya domain modelinin farklı host’larda kullanılacağı durumda ayrı assembly daha güçlü gerekçe taşır. Küçük bir katalog okuma API’sinde aynı şema fazladan bakım alanı yaratabilir. Bağımsızlığın hangi tehditten korunacağını belirtmek gerekir.
Güvenlik ve operasyon sorumlulukları sade yapıda da kalır
Katmanları azaltmak authorization kontrolünü azaltma hakkı vermez. Ürün güncelleme endpoint’i eklendiğinde kullanıcı kimliği ve yetkisi açık biçimde kontrol edilmelidir. Tenant kullanılan bir sistemde kimlik üzerinden başka tenant’ın kaydına erişilememesi ayrıca sınanmalıdır. Bu sorumluluğu genel bir repository’nin varlığına emanet etmek yeterli değildir. Endpoint’ten query’ye kadar erişim bağlamının nasıl taşındığı anlaşılmalıdır. Sade bir tasarımda bu akış daha kolay görülebilir; ancak görünür olması kendiliğinden doğru olduğu anlamına gelmez. Kritik erişim kuralları gerçek davranış testleriyle korunmalıdır.
Hata yönetimi, log, trace ve timeout kararları da her feature’ın kendi tercihine bırakılmamalıdır. Beklenmeyen hatanın ayrıntısını istemciye açmayan ortak yanıt düzeni ve operasyon için yeterli correlation bilgisi gerekir. Bu ortak mekanizmalar katman sayısından bağımsızdır. Bir katalog okumasında database yavaşladığında hangi sorgunun süreyi tükettiği anlaşılmalıdır. Ölçmeden Minimal API’nin veya Clean Architecture’ın daha hızlı olduğu iddia edilemez. Performans maliyetini deployment, I/O ve query davranışıyla birlikte incelemek gerekir. Kaynak kodunun kısa olması, çalışma süresinin kısa olduğunun kanıtı değildir.
Katman eklemek için somut eşikler belirlemek
Bir karar kaydında bugün hangi yapının seçildiğini, hangi gereksinimler nedeniyle yeterli olduğunu ve hangi koşullarda değişeceğini yazabilirsiniz. Aynı business işlemi HTTP ile job arasında paylaşılacaksa application sınırı güçlendirilebilir. Dış sağlayıcıların farklı contract’ları uygulamaya yayılıyorsa adapter eklenebilir. İş invariant’ları endpoint koşullarında çoğalıyorsa domain modeli çıkarılabilir. Bu eşikler, ekibin mimariyi kişisel zevke göre değil gözlenen ihtiyaçla büyütmesine yardım eder. Eşiklere sayı vermek zorunlu değildir; değişimin türünü ve doğurduğu maliyeti belirtmek yeterlidir.
Mevcut sade API’den geçiş yaparken bütün endpoint’leri aynı gün taşımak yerine gerçek kuralı olan bir kullanım senaryosu seçin. HTTP yanıtını ve mevcut davranışı testle sabitleyin. Ardından business kararı endpoint’ten çıkarın, persistence sorumluluğunu açık tutun ve exception eşlemesini gözden geçirin. Yeni sınıflar eklenmiş olsa bile davranış değişmemelidir; değişiyorsa bunun sebebi ayrıca açıklanmalıdır. Bu adımla elde edilen fayda diğer feature’lara genellenmeden önce değerlendirilmelidir. Bir kullanım senaryosunda faydalı olan katman, bütün okuma sorgularında aynı faydayı üretmeyebilir.
Son karar için geliştiricinin yeni bir alan veya kural eklerken izleyeceği yolu deneyin. Değişiklik anlaşılır, test edilebilir ve sınırlı bir alana dokunuyorsa mevcut düzen yeterli olabilir. Değişiklik sürekli farklı transport ve dış sistem detaylarına takılıyorsa korunacak sınır bulunmuştur. Tercihim bu kanıtla ilerlemek: Sade feature düzenini başlangıç kabul etmek, gerçek iş ve entegrasyon sınırları oluştuğunda katmanları eklemek. Bu yaklaşımın bedeli, mimarinin zamanla bilinçli biçimde yeniden değerlendirilmesidir. Başlangıçta eksiksiz şema kurmak bu değerlendirme sorumluluğunu ortadan kaldırmaz.
Review sırasında sorulabilecek iki kritik soru
İlk soru, yeni abstraction’ın tüketiciden hangi bilgiyi sakladığıdır. Cevap yalnızca sınıfın adının değişmesi veya metodun başka dosyaya taşınmasıysa sınırın faydası henüz görünmüyordur. Cevap dış sağlayıcının hata modeli, veri erişim biçimi veya business invariant’ın korunmasıysa daha güçlü bir gerekçe vardır. İkinci soru, abstraction kaldırıldığında hangi bağımsız değişiklik imkânının kaybedileceğidir. Bu soru gereksiz interface ile anlamlı contract’ı ayırmaya yardım eder. Her interface’in ikinci implementasyonu bulunmak zorunda değildir; fakat mevcut implementasyon ayrımının neyi koruduğu anlaşılmalıdır.
Bu soruları review’da bir veto listesine dönüştürmek yerine değişikliğin amacıyla ilişkilendirin. Acil bir düzeltmede mevcut düzeni korumak en düşük riskli seçenek olabilir. Yeni bir feature’da aynı düzenin sorunlarını büyütmemek daha anlamlıdır. Mimari tercih yalnızca ideal tasarım üzerinden değil, geçiş maliyeti ve mevcut davranışın korunması üzerinden de değerlendirilir. Clean Architecture kararı bu nedenle tek seferlik doğru şablon seçimi olarak görülmemelidir.
