iToverDose/Yazılım· 29 MAYIS 2026 · 20:03

C# ile yazılım geliştirirken kod mimarisi nasıl şekillenmeli?

C# projelerinizde kod mimarisini nasıl optimize edebilirsiniz? Fonksiyon odaklı domain tasarımı, CQRS’in yenilikçi yaklaşımı ve EF Core’un sunduğu avantajları keşfedin.

DEV Community4 dk okuma0 Yorumlar

Yazılım geliştirme dünyasında kod mimarisi, projenizin başarısında ve uzun vadeli sürdürülebilirliğinde kritik bir rol oynar. Ancak mimari kararlar verirken, sadece teknolojiye odaklanmak yeterli değildir. Şirket kültürü, takım dinamikleri, iş akışının formalitesi ve yazılım yaşam döngüsü gibi insani faktörler de mimari tercihlerinizi doğrudan etkiler. Bu noktada yapay zeka ne yazık ki devreye giremez; kararlar her zaman insanlar tarafından verilmelidir.

Geliştiriciler olarak karşılaştığımız en iyi kod mimarilerinden biri henüz resmi bir adı olmayan, farklı mimari desenlerin bir sentezi olan yaklaşımlardır. Bu makalede, C# ile yazılım geliştirirken kullanabileceğiniz fonksiyon odaklı domain tasarımı, CQRS’in evrimsel yaklaşımı ve EF Core’un sunduğu doğrudan avantajlar üzerinde duracağız.

Domain’inizi Düz Bir Fonksiyon Listesi Olarak Tasarlayın

Mimaride sıkça kullanılan aracılık (mediator) deseninin temelinde, aslında bir servis yerleştirici (service locator) yaklaşımı yatmaktadır. Örneğin, CreateUserCommand ve CreateUserCommandHandler sınıflarını yazmak, tek bir CreateUser metodu olan ICreateUserService ya da CreateUserService sınıflarıyla temelde aynı anlama gelir. Önemli olan, domain’inizi tek sorumluluğu olan ve tek bir süreci yöneten düz bir fonksiyon listesi olarak tasarlamaktır.

Bu yaklaşımın uzun vadeli faydaları oldukça belirgindir. Özellikle teknik borcun minimum düzeyde kalmasını ve kodunuzun zaman içinde kararlılıkla gelişmesini sağlar. Makalede "fonksiyon" terimini kullanacağız, ancak kastettiğimiz şey, aracılık komutları, işleyicileri ya da tek bir genel metoda sahip servislerdir. Önemli olan, fonksiyonların sorumluluklarını net bir şekilde tanımlamaktır.

CQRS: Okuma İşlemlerini Domain’in Bir Parçası Olarak Değerlendirin

CQRS (Command Query Responsibility Segregation), ilk olarak okuma ve yazma işlemlerinin altyapı düzeyinde ayrılması amacıyla geliştirilmişti. Çünkü birçok ticari uygulamada işlemlerin yaklaşık %90’ını okuma operasyonları, %10’unu ise yazma operasyonları oluşturmaktadır. Domain yazma işlemleri tek bir sistemde yoğunlaşırken, değişiklikler zamanla okuma odaklı optimize edilmiş ayrı bir sistemde görünür hale gelir.

Ancak bu yaklaşımın uygulanabilirliği, trafik yoğunluğuna bağlıdır. Örneğin, Çek Cumhuriyeti gibi nüfusu 10.5 milyon olan bir ülkede, seznam.cz gibi yüksek trafikli bir siteye sahip olmak nadir bir durumdur. Bu nedenle, çoğu proje için altyapı düzeyinde okuma-yazma ayrımına gitmek gereksizdir.

Buna rağmen, domain fonksiyonlarını okuma ve yazma olarak ayırmak, kod mimarisi açısından oldukça faydalıdır. Neden mi? Kullanıcılar, genellikle verilerin görüntülendiği bir arayüzle etkileşime girerler. Bu da, okuma işlemlerinin domain’in bir parçası olduğunu gösterir. Domain’in sadece yazma operasyonlarını içermesi gerektiğini savunmak, DDD puristlerinin bakış açısıdır ve aslında işin ticari gerekliliklerine aykırıdır. Eğer işletmeniz verilerin görüntülenmesini gerektiriyorsa, o verileri okuyan ve geri döndüren bir fonksiyon da domain’inizin bir parçası olmalıdır.

Yüksek Düzeyli Fonksiyonlarla Domain’inizi Katmanlandırın

Domain’inizi düz bir fonksiyon listesi olarak tasarladığınızda, karmaşık projelerde karşınıza bir ihtiyaç daha çıkacaktır: yüksek düzeyli fonksiyonlar. Bu fonksiyonlar, domain içindeki diğer fonksiyonları çağıran ve yeniden kullanıma sunan fonksiyonlardır. Örneğin, ikinci düzey bir fonksiyon, birinci düzeydeki temel fonksiyonları çağırabilir.

Bu noktada iki önemli kural dikkate alınmalıdır:

  • Herhangi bir yüksek düzeyli fonksiyon, doğrudan altında yer alan fonksiyonları kullanarak okuma ya da yazma işlemlerini gerçekleştirmelidir. Üçüncü düzey bir fonksiyon, sadece ikinci düzey fonksiyonları çağırabilir; ikinci düzey fonksiyonlar ise sadece birinci düzey fonksiyonları çağırabilir.
  • Aynı düzeydeki fonksiyonlar birbirlerini çağırmamalıdır. Bu kural, fonksiyonlar arasındaki bağımlılıkların kontrol altında tutulmasını sağlar ve kodunuzun daha modüler ve anlaşılır olmasına katkıda bulunur.

Bu yaklaşımla çalışırken, ikinci düzey fonksiyonlardan daha yükseğe nadiren ihtiyaç duyulur. Finansal alanlarda çalıştığım projelerde genellikle ikinci düzey fonksiyonlar yeterli olmuştur. Ancak ilk işim olan seyahat acentaları için geliştirilen monolitik bir uygulamada, üçüncü ya da dördüncü düzey fonksiyonlara ihtiyaç duyulabilirdi.

Domain’inizi Monolitik Olarak Tasarlayın

Domain’inizi, tek bir uygulama ya da API kapsamında modüler hale getirmek cazip gelebilir. Ancak bu yaklaşım genellikle gereksizdir. Domain fonksiyonlarını farklı .csproj dosyalarına yaymak yerine, domain’inizi mümkün olduğunca tek bir yerde tutun. Domain fonksiyonlarını başka bir projeye taşımak içinse, yalnızca yeni bir uygulama geliştirilmesi ve sorumlulukların yeniden dağıtılması gerektiğinde karar verin.

Domain Fonksiyonlarında Geçerli Olan Üç Temel Eylem

Domain fonksiyonlarınız içinde yalnızca üç temel eyleme izin verilmelidir. Bu eylemler herhangi bir sırada gerçekleştirilebilir:

  • Doğrulama: Fonksiyon içinde, bellekteki verilerin geçerli olup olmadığını kontrol edin. Örneğin, kullanıcı girişi sırasında e-posta formatının doğrulanması gibi.
  • Dönüşüm: Bellekteki verileri manipüle edin ya da dönüştürün. Örneğin, bir veritabanından alınan verileri kullanıcı arayüzüne uygun formatta sunmak için dönüştürmek.
  • Bağımlılık: Dış hizmetlere (repository dahil) veri göndermek, almak ya da her ikisini yapmak için istek gönderin. Örneğin, bir ödeme işlemi sırasında ödeme geçmişini kaydetmek için harici bir API’ye istek göndermek.

EF Core’un Doğrudan Kullanımı: Avantajları ve Gerekliliği

Çoğu projede Microsoft SQL Server (MSSQL) ya da başka bir ilişkisel veritabanı kullanılmaktadır. Bu noktada dikkat edilmesi gereken önemli bir gerçek var: veritabanı değiştirmek neredeyse hiç gerekmemektedir. Projenizin başından itibaren temiz bir veritabanı mimarisi oluşturulmamışsa, MSSQL’den PostgreSQL’e ya da MySQL’e geçiş, genellikle haklı gerekçelerle bile büyük bir çaba gerektirir.

Bu nedenle, DbContext soyutlamasını kullanmak yerine doğrudan EF Core’un sunduğu olasılıkları değerlendirmek daha mantıklı olabilir. Örneğin, DbContext zaten bir soyutlama katmanı sunmaktadır. Temiz mimari savunucuları, test edilebilirlik için DbContext’i soyutlamanın gerekliliğini vurgularlar, ancak bu ihtiyaç yıllar içinde ortadan kalkmıştır. EF Core’un test edilebilirliği, artık doğrudan DbContext üzerinde mock ya da substitute işlemleri yapabilme yeteneğiyle sağlanmaktadır.

Ayrıca, EF Core’un performans sorunlarına ilişkin endişeler de genellikle gereksizdir. Örneğin, .AsNoTracking() kullanarak sorguların performansını önemli ölçüde artırabilirsiniz. Clean Architecture’de sıkça önerilen Unit of Work deseninin ise çoğu durumda gereksiz olduğunu belirtmek gerekir. Örneğin, DbSet.Add işlemini IUserRepository.Add aracılığıyla soyutlamak ve ardından IUnitOfWork.Commit yerine DbContext.SaveChanges() çağırmak, genellikle YAGNI (You Aren’t Gonna Need It) ilkesine aykırıdır.

Yazılım geliştirme süreçlerinde mimari kararlar, projenizin geleceğini doğrudan etkiler. Fonksiyon odaklı domain tasarımı, CQRS’in esnek yaklaşımı ve EF Core’un sunduğu avantajlar, C# projelerinizde uzun vadeli sürdürülebilirliği ve performansı artırmak için etkili bir strateji sunar. Unutmayın, en iyi mimari, projenizin özel gereksinimlerine ve işletmenizin ihtiyaçlarına en uygun olanıdır.

Yapay zeka özeti

C# projelerinizde fonksiyon odaklı domain tasarımı, CQRS’in yenilikçi yaklaşımları ve EF Core’un sunduğu avantajları keşfedin. Kod mimarisini optimize etmek için ipuçları ve stratejiler.

Yorumlar

00
YORUM BIRAK
ID #W74J3I

0 / 1200 KARAKTER

İnsan doğrulaması

7 + 7 = ?

Editör onayı sonrası yayına girer

Moderasyon · Spam koruması aktif

Henüz onaylı yorum yok. İlk yorumu sen bırak.