Skip to main content
Yazılım Geliştirme

Clean Architecture ile .NET Proje Yapılandırması

Mart 06, 2026 6 dk okuma 17 views Raw
Ayrıca mevcut: en
Clean Architecture ile .NET proje yapılandırması
İçindekiler

Clean Architecture Nedir?

Clean Architecture, Robert C. Martin (Uncle Bob) tarafından ortaya konulan ve yazılım projelerinin sürdürülebilir, test edilebilir ve bağımsız bir şekilde geliştirilmesini amaçlayan bir mimari yaklaşımdır. Bu yaklaşım, uygulamanın iş mantığını dış bağımlılıklardan izole ederek, sistemin esnekliğini ve bakım kolaylığını en üst düzeye çıkarır.

Clean Architecture'ın temel prensibi, bağımlılık kuralıdır: kaynak kod bağımlılıkları her zaman içe doğru yönelmelidir. Dış katmanlar iç katmanlara bağımlı olabilir, ancak iç katmanlar asla dış katmanları bilmemelidir. Bu sayede iş kuralları, kullanıcı arayüzünden, veritabanından ve diğer harici sistemlerden tamamen bağımsız hale gelir.

Neden Clean Architecture Kullanmalıyız?

Günümüzde yazılım projeleri giderek daha karmaşık hale gelmektedir. Monolitik yapılar büyüdükçe bakımları zorlaşır, test edilmeleri güçleşir ve yeni özellikler eklemek riskli bir hal alır. Clean Architecture bu sorunlara sistematik bir çözüm sunar.

  • Bağımsız test edilebilirlik: İş kuralları, veritabanı veya kullanıcı arayüzü olmadan test edilebilir.
  • Framework bağımsızlığı: Uygulama belirli bir framework'e sıkı sıkıya bağlı değildir. Framework bir araç olarak kullanılır, sisteme hakim olmaz.
  • Veritabanı bağımsızlığı: SQL Server'dan PostgreSQL'e veya MongoDB'ye geçiş, iş kurallarını etkilemez.
  • UI bağımsızlığı: Kullanıcı arayüzü, iş mantığını değiştirmeden kolayca değiştirilebilir.
  • Sürdürülebilirlik: Proje büyüdükçe kodun anlaşılabilirliği ve bakım kolaylığı korunur.

Clean Architecture Katmanları

Clean Architecture, eşmerkezli daireler şeklinde temsil edilen katmanlardan oluşur. Her katmanın belirli bir sorumluluğu vardır ve bağımlılık kuralına uygun olarak tasarlanır.

Domain Katmanı (Entities)

En içteki katman olan Domain, uygulamanın iş kurallarını ve entity'lerini barındırır. Bu katman hiçbir dış bağımlılığa sahip değildir ve tamamen saf C# sınıflarından oluşur. Domain katmanında yer alan bileşenler şunlardır:

  • Entities: İş nesnelerini temsil eden sınıflar. Örneğin Order, Customer, Product gibi.
  • Value Objects: Kimliği olmayan, değerleriyle tanımlanan nesneler. Örneğin Money, Address, Email gibi.
  • Domain Events: İş süreçlerinde meydana gelen olaylar.
  • Enumerations: İş mantığına özgü sabit değer kümeleri.
  • Exceptions: Domain'e özgü hata sınıfları.

Application Katmanı (Use Cases)

Application katmanı, uygulamanın kullanım senaryolarını (use cases) içerir. Bu katman, Domain katmanına bağımlıdır ancak dış katmanlardan bağımsızdır. Burada iş akışlarının orkestasyonu gerçekleştirilir.

  • Interfaces: Repository, servis ve diğer dış bağımlılıklar için soyutlamalar.
  • DTOs: Katmanlar arası veri taşıma nesneleri.
  • Validators: Girdi doğrulama kuralları.
  • Behaviors: Cross-cutting concern'ler için pipeline davranışları.
  • Commands ve Queries: CQRS pattern'i uygulandığında komut ve sorgu nesneleri.

Infrastructure Katmanı

Infrastructure katmanı, dış dünya ile etkileşimi sağlar. Veritabanı erişimi, dosya sistemi, e-posta gönderimi, üçüncü parti servisler gibi tüm harici bağımlılıklar bu katmanda yer alır.

  • Data Access: Entity Framework Core DbContext, repository implementasyonları.
  • External Services: API istemcileri, mesajlaşma servisleri.
  • Identity: Kimlik doğrulama ve yetkilendirme implementasyonları.
  • File Storage: Dosya yükleme ve saklama servisleri.

Presentation Katmanı (Web API / UI)

En dıştaki katman, kullanıcı ile etkileşimi sağlar. ASP.NET Core Web API, MVC, Blazor veya herhangi bir sunum teknolojisi bu katmanda yer alır. Bu katman, Application katmanındaki servisleri ve komutları çağırarak kullanıcı isteklerini işler.

.NET Projesi Yapılandırma Adımları

Şimdi adım adım bir .NET çözümünü Clean Architecture prensiplerine göre yapılandıralım. Bu yapılandırma, gerçek dünya projelerinde kanıtlanmış en iyi pratiklere dayanmaktadır.

Solution Yapısı

Öncelikle çözüm yapısını oluşturalım. Her katman ayrı bir proje olarak tanımlanır ve bağımlılıklar katman kurallarına göre ayarlanır.

MyApp/
├── src/
│   ├── MyApp.Domain/
│   ├── MyApp.Application/
│   ├── MyApp.Infrastructure/
│   └── MyApp.WebApi/
└── tests/
    ├── MyApp.Domain.Tests/
    ├── MyApp.Application.Tests/
    └── MyApp.Infrastructure.Tests/

Proje Bağımlılık Hiyerarşisi

Bağımlılık kuralına uygun olarak projeler arası referanslar şu şekilde yapılandırılmalıdır:

  1. MyApp.Domain: Hiçbir projeye referans vermez. Tamamen bağımsızdır.
  2. MyApp.Application: Yalnızca MyApp.Domain'e referans verir.
  3. MyApp.Infrastructure: MyApp.Application'a referans verir ve dolaylı olarak Domain'e erişir.
  4. MyApp.WebApi: MyApp.Application ve MyApp.Infrastructure'a referans verir.

Domain Katmanının Oluşturulması

Domain katmanında entity'lerinizi ve iş kurallarınızı tanımlayın. Bu katmanda NuGet paketleri kullanmaktan mümkün olduğunca kaçının. Amaç, bu katmanın tamamen saf ve bağımsız kalmasıdır.

public abstract class BaseEntity
{
    public Guid Id { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

public class Order : BaseEntity
{
    public string OrderNumber { get; private set; }
    public decimal TotalAmount { get; private set; }
    public OrderStatus Status { get; private set; }
    
    public void Complete()
    {
        if (Status != OrderStatus.Processing)
            throw new DomainException("Yalnızca işlenen siparişler tamamlanabilir.");
        Status = OrderStatus.Completed;
    }
}

Application Katmanının Yapılandırılması

Application katmanında MediatR kütüphanesini kullanarak CQRS pattern'ini uygulayabilirsiniz. Bu yaklaşım, komutları ve sorguları net bir şekilde ayırarak kodun okunabilirliğini artırır.

public interface IOrderRepository
{
    Task<Order> GetByIdAsync(Guid id);
    Task<IEnumerable<Order>> GetAllAsync();
    Task AddAsync(Order order);
    Task UpdateAsync(Order order);
}

public record CreateOrderCommand(
    string CustomerName,
    List<OrderItemDto> Items
) : IRequest<Guid>;

public class CreateOrderCommandHandler 
    : IRequestHandler<CreateOrderCommand, Guid>
{
    private readonly IOrderRepository _orderRepository;
    
    public CreateOrderCommandHandler(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }
    
    public async Task<Guid> Handle(
        CreateOrderCommand request, 
        CancellationToken cancellationToken)
    {
        var order = new Order(request.CustomerName, request.Items);
        await _orderRepository.AddAsync(order);
        return order.Id;
    }
}

SOLID Prensiplerinin Uygulanması

Clean Architecture, SOLID prensipleriyle doğal bir uyum içindedir. Bu prensiplerin her birinin mimari içindeki rolünü inceleyelim.

Single Responsibility Principle (Tek Sorumluluk)

Her sınıf ve modül yalnızca bir sorumluluğa sahip olmalıdır. Clean Architecture'da bu prensip, katmanların ayrılmasıyla doğal olarak uygulanır. Domain katmanı yalnızca iş kurallarıyla, Application katmanı yalnızca kullanım senaryolarıyla ilgilenir.

Open/Closed Principle (Açık/Kapalı)

Yazılım varlıkları genişlemeye açık, değişikliğe kapalı olmalıdır. Yeni bir use case eklemek için mevcut kodu değiştirmek yerine yeni handler sınıfları oluşturursunuz. MediatR pipeline'ı bu prensibi mükemmel şekilde destekler.

Dependency Inversion Principle (Bağımlılık Tersine Çevirme)

Üst seviye modüller alt seviye modüllere bağımlı olmamalıdır. Her ikisi de soyutlamalara bağımlı olmalıdır. Clean Architecture'da Application katmanı interface'leri tanımlar, Infrastructure katmanı bunları implement eder. Bu sayede iş mantığı, veritabanı teknolojisinden tamamen bağımsız kalır.

Bağımlılık Enjeksiyonu ve Kayıt

ASP.NET Core'un yerleşik Dependency Injection mekanizması, Clean Architecture ile mükemmel bir uyum sağlar. Her katman kendi servislerini kaydetmek için bir extension method sağlamalıdır.

// Application katmanı kayıt
public static class DependencyInjection
{
    public static IServiceCollection AddApplication(
        this IServiceCollection services)
    {
        services.AddMediatR(cfg => 
            cfg.RegisterServicesFromAssembly(
                Assembly.GetExecutingAssembly()));
        services.AddValidatorsFromAssembly(
            Assembly.GetExecutingAssembly());
        return services;
    }
}

// Infrastructure katmanı kayıt
public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(
        this IServiceCollection services, 
        IConfiguration configuration)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                configuration.GetConnectionString("Default")));
        services.AddScoped<IOrderRepository, OrderRepository>();
        return services;
    }
}

Sık Yapılan Hatalar ve Kaçınılması Gerekenler

Clean Architecture uygularken dikkat edilmesi gereken kritik noktalar vardır. Bu hataları bilmek, projenizin sağlıklı kalmasını sağlar.

  • Domain katmanında framework bağımlılıkları: Entity Framework attribute'leri veya ASP.NET Core bağımlılıkları Domain katmanına eklenmemelidir.
  • Aşırı soyutlama: Her şeyi soyutlamak, gereksiz karmaşıklık yaratır. Yalnızca değişme olasılığı yüksek olan bileşenleri soyutlayın.
  • Anemic Domain Model: Entity'ler yalnızca veri taşıyıcısı olmamalıdır. İş kurallarını entity'lerin içinde tanımlayın.
  • Katman atlama: Presentation katmanından doğrudan Infrastructure katmanına erişim sağlanmamalıdır. Her istek Application katmanı üzerinden geçmelidir.
  • Gereksiz katman ekleme: Küçük projeler için tüm katmanları uygulamak aşırı mühendislik olabilir. Proje boyutuna göre karar verin.

Test Stratejisi

Clean Architecture, kapsamlı test stratejileri uygulamayı kolaylaştırır. Her katman için farklı test türleri uygulanabilir.

Birim Testler

Domain ve Application katmanlarındaki iş mantığı, herhangi bir dış bağımlılık olmadan test edilebilir. Mock nesneler kullanarak repository ve servis davranışlarını simüle edebilirsiniz.

Entegrasyon Testleri

Infrastructure katmanındaki veritabanı erişimi ve harici servis entegrasyonları, entegrasyon testleriyle doğrulanmalıdır. TestContainers gibi kütüphaneler, gerçek veritabanı ortamlarında test yapmayı kolaylaştırır.

Sonuç

Clean Architecture, .NET projelerinde sürdürülebilir, test edilebilir ve esnek bir yapı oluşturmak için güçlü bir çerçeve sunar. Bağımlılık kuralını doğru uygulayarak, projenizin büyümesiyle birlikte kodun karmaşıklığını kontrol altında tutabilirsiniz. SOLID prensipleriyle birlikte kullanıldığında, Clean Architecture ekibinizin verimliliğini artırır ve teknik borcu minimize eder. Ancak unutmayın ki mimari kararlar her zaman projenin boyutuna ve gereksinimlerine göre değerlendirilmelidir.

Bu yazıyı paylaş