Merhaba,
Modern yazılım projeleri büyüdükçe, onların davranışlarını yönetmek ve karmaşik iş kurallarını (business rules) düzenli şekilde ele almak zorlaşır. Bu nedenle iki yaklaşım özellikle öne çıkar: Olay güdümlü mimari (Event-Driven Architecture) ve Alan odaklı tasarım (Domain-Driven Design – DDD). .NET Core ekosistemi, bu iki yaklaşımı uygulamak için oldukça uygun bir altyapı sunar. Bu yazıda her iki yaklaşımı da basit ve anlaşılır şekilde ele alacağım.
Event-Driven Architecture
Temel Mantık
Bu yaklaşım, sistem içindeki bileşenlerin olayları birbirine göndermesi ve diğer bileşenlerin bu olaylara tepki vermesi prensibine dayanır. Sistem doğrudan birbirine bağlı nesneler yerine, olaylar üzerinden iletişim kurar.
Gerçek Dünya Örneği
Bir e-ticaret sistemi düşünelim:
- Kullanıcı bir ürün satın aldığında Sipariş Oluşturuldu olayı tetiklenir.
- Bu olayı dinleyen başka bir servis fatura üretir.
- Başka bir servis kargolama işlemini başlatır.
- Bir başka servis stoktan düşme işlemi yapar.
Bu servisler birbirini doğrudan bilmez; sadece olaylara tepki verir. Böylece servislerin bağımlılığı azalır.
.NET Core’da Nasıl Uygulanır?
En popüler yöntemler:
- Mesaj kuyrukları: RabbitMQ, Azure Service Bus, Kafka
- Event Publisher / Subscriber (Yayıncı – Abone) yapısı
Avantajları
- Gevşek Bağlılık: Servisler birbirini doğrudan tanımaz.
- Yüksek Ölçeklenebilirlik: Yoğun veri yüklerinde kuyruk sistemi devreye girer.
- Esnek Genişleme: Yeni bir servis olaya abone olduğunda sistemi bozmaz.
- Gerçek Zamanlı Tepki: Olay üretildiği anda işlem tetiklenir.
Dezavantajları
- Hata Takibi Zordur: Olayların nereden nereye aktığını anlamak karmaşık olabilir.
- Gecikme Olabilir: Kuyruk yapıları küçük gecikmelere neden olabilir.
- Tutarlılık (Consistency – Tutarlılık) Sorunları: Olaylar sıralı gelmeyebilir veya geç gelebilir.
Domain-Driven Design
Temel Mantık
Domain Driven Design, yazılımın iş alanına odaklanmasını sağlayan bir tasarım yaklaşımıdır. Amaç, modelleri iş kurallarını en doğru şekilde temsil edecek biçimde tasarlamaktır.
Gerçek Dünya Örneği
Bir banka sistemi düşünelim:
- Hesap (Account – Hesap)
- Para aktarımı (Transfer – Para aktarımı)
- Limit kontrolü
- İşlem geçmişi
Bu kavramların her biri iş alanına ait kavramlardır ve kod içinde doğrudan bu domain kavramlarıyla tanımlanır.
Örneğin:
public class BankaHesabi
{
public decimal Bakiye { get; private set; }
public void ParaYatir(decimal miktar)
{
if (miktar <= 0)
throw new Exception("Yatırılacak miktar pozitif olmalıdır.");
Bakiye += miktar;
}
}
Burada iş kuralı (“miktar pozitif olmalı”) nesnenin kendi içinde yönetiliyor. Bu yaklaşım DDD'nin temelidir.
.NET Core'da DDD Katmanları
Genelde dört temel katman kullanılır:
-
Domain (Alan)
-
Entity (Varlık), Value Object (Değer Nesnesi), Domain Event (Alan Olayı)
-
-
Application (Uygulama)
-
İş akışlarını yöneten servisler
-
-
Infrastructure (Altyapı)
-
Veri tabanı, mesaj kuyrukları, dış servis bağlantıları
-
-
API (Sunum)
-
İstekleri karşılayan kontrolcüler
-
Bu yapı, özellikle kurumsal .NET Core projelerinde standart bir pratik haline gelmiştir.
Avantajları
- Karmaşık İş Kurallarını Düzenler
- Kod Gerçek İş Sürecine Benzer: Teknik ve iş ekipleri ortak dil kullanır.
- Test Edilebilirlik Yüksektir
- Uzun Ömürlü Projeler İçin Uygundur
Dezavantajları
- Başlangıçta Karışık Görünebilir
- Küçük Projeler İçin Fazla Ağır Olabilir
- Doğru Uygulanmazsa “Aşırı Mimarileştirme” sorunu yaratır
Olay Güdümlü Mimari + DDD Birlikte Kullanılabilir mi?
Evet. genelde birçok büyük .NET Core projesi bu iki yaklaşımı birlikte kullanır.
Örnek mimari:
-
Domain içinde Alan Olayı (Domain Event) üretilir.
-
Bu olay Application katmanına yansır.
-
Application katmanı bu olayı dış dünyaya Olay Yayıncısı (Event Publisher) ile gönderir.
-
Başka servisler bu olaya abone olur.
Bu entegrasyon şu senaryolarda çok kullanışlıdır:
-
Mikroservis (Microservice – Mikroservis) mimarileri
-
Fatura, sipariş, stok yönetimi gibi bağımsız süreçler
-
Bankacılık ve sigorta gibi karmaşık domain’ler
Gerçek Dünya Senaryosu: E-Ticaret Ödeme Süreci
-
Sipariş Servisi, “Sipariş Oluşturuldu” olayını yayınlar.
-
Ödeme Servisi, bu olayı dinler ve ödeme işlemini başlatır.
-
Ödeme başarılı olunca domain içinde “Ödeme Başarılı” olayı tetiklenir.
-
Bu olay fatura servisine ve stok servisine iletilir.
-
Tüm servisler birbirinden bağımsız çalışır.
Bu yapı hem DDD hem Event-Driven prensiplerinin birleşimidir.
Sonuç
bu iki yaklaşım:
- Daha ölçeklenebilir,
- Daha düzenli,
- Daha sürdürülebilir,
- Daha profesyonel
projeler geliştirmemizi sağlar.
Diğer Bloglarımda görüşmek üzere 👋