C# ile Domain Driven Design (DDD) yaklaşımıyla bir proje geliştirirken neredeyse herkesin kafasında aynı soru belirir:

ddd-fluent-validation

“Bu doğrulamayı (validation) nereye yazmalıyım?”
“Entity içinde exception fırlatmak SOLID’e aykırı mı?”
“FluentValidation kullanırken Domain kuralları nasıl korunacak?”

Bu yazıda tüm bu soruları netleştiriyoruz.

1. Domain Validation Nedir?

Domain Validation, bir nesnenin ‘var olabilmesi’ için gerekli kuralları kapsar. Bu kurallar, o domain’in (iş kurallarının) ayrılmaz bir parçasıdır.

Örneğin bir Customer entity’si düşünelim:

  • Email boş olamaz
  • Müşteri adı en az 2 karakter olmalıdır
  • Telefon numarası belirli formatlarda olmalıdır

Bu kurallar domain’in kalbidir. Bu nedenle Domain Model içinde enforce edilmelidir.

Örnek bir Entity:

public class Customer : BaseEntity
{
    public string Name { get; private set; }
    public Email Email { get; private set; }

    private Customer() { }

    public static Customer Create(string name, Email email)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("Name cannot be empty");

        if (name.Length < 2)
            throw new DomainException("Name must be at least 2 characters");

        if (email is null)
            throw new DomainException("Email cannot be null");

        return new Customer
        {
            Name = name.Trim(),
            Email = email
        };
    }
}

Bu örnekteki doğrulamalar, Entity’nin “invariant” denilen bozulamaz kurallarıdır. Bunlar Domain’in bir parçası olduğu için Entity içinde bulunması doğrudur.

2. FluentValidation Neye Yarar?

FluentValidation genellikle şu amaçlarla kullanılır:

  • API request modellerinin doğrulanması
  • Form input kontrolleri
  • Kullanıcıya dönülecek hataların yönetilmesi
  • UI veya Application Layer seviyesinde validasyon

Yani FluentValidation, frontend-facing validation içindir. Domain’in içindeki kuralları temsil etmek için uygun değildir.

Neden?

Çünkü FluentValidation:

  • UI veya API katmanında çalışır
  • Domain katmanına bağımlılık oluşturur (DDD’ye aykırı)
  • Domain nesnesi uygulama dışında doğrulanamaz hale gelir

Aşağıdaki gibi bir kullanım, Domain kuralları için yanlıştır:

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MinimumLength(2);
        RuleFor(x => x.Email).NotNull();
    }
}

Bu kurallar API doğrulaması için idealdir. Ama Domain kurallarını buraya taşımak, mimariyi zayıflatır.

3. SOLID’in S Prensibi Bu Noktada Ne Diyor?

S: Single Responsibility (Tek Sorumluluk İlkesi)

DDD’de Entity’nin sorumluluğu şudur: “Kendi iş kurallarını korumak.”

Dolayısıyla şu doğrulamalar Entity’ye aittir:

  • Domain kuralları
  • İnvariant kontrolü
  • Mantıksal bütünlük

UI doğrulaması Entity’nin sorumluluğu değildir.
Ama domain kuralları Entity’nin bizzat görevidir.

Bu nedenle:

Domain Validation = S-prensibine uygundur.
UI Validation = FluentValidation veya farklı bir katmanda olmalıdır.

4. Application Validation (FluentValidation) ile Domain Validation Arasındaki Fark

Aşağıdaki tabloyu kullanarak blog yazının içinde güçlü bir anlatım sağlayabilirsin:

Tür Nerede Yapılır? Amacı Hata Yönetimi
Domain Validation Entity / Value Object Domain invariant’ları korur Exception
Application Validation API / UI / DTO modelleri Kullanıcı girişi kontrolü ValidationResult
FluentValidation Application layer Form ve request doğrulama Kullanıcıya gösterilir

5. Yanlış Kullanım Örneği

Domain kurallarının FluentValidation’a taşınması:

RuleFor(x => x.Username).NotEmpty().MinimumLength(3);

Bu durumda:

  • Domain nesnesi dışarıdan yanlış değerle oluşturulabilir
  • Domain bağımsızlığını kaybeder
  • Rich Domain Model yaklaşımı çöker

Bu DDD’nin temel prensiplerine aykırıdır.

6. Doğru Kullanım Örneği

Domain tarafında zorunlu kurallar:

if (string.IsNullOrWhiteSpace(username))
    throw new DomainException("Username required.");

Application tarafında kullanıcıya özel mesajlar:

RuleFor(x => x.Username)
    .NotEmpty().WithMessage("Please enter a username.")
    .MinimumLength(3).WithMessage("Username must be at least 3 characters.");

Bu ayrım doğru mimariyi sağlar.

Value Object İçinde Validation

public class PhoneNumber : ValueObject
{
    public string Value { get; }

    private PhoneNumber(string value)
    {
        if (!Regex.IsMatch(value, @"^\+?[0-9]{10,15}$"))
            throw new DomainException("Invalid phone number format.");

        Value = value;
    }

    public static PhoneNumber Create(string value)
        => new PhoneNumber(value);
}

Value Object’lerde validation daha da kritik hale gelir; çünkü bu nesne her yerde kullanılabilir.

Application Layer’da FluentValidation

public class RegisterUserRequestValidator : AbstractValidator<RegisterUserRequest>
{
    public RegisterUserRequestValidator()
    {
        RuleFor(x => x.Username)
            .NotEmpty().WithMessage("Username is required.")
            .MinimumLength(3).WithMessage("Minimum 3 characters.");

        RuleFor(x => x.Email)
            .EmailAddress().WithMessage("Invalid email format.");
    }
}

Buradaki validation:

  • API kullanıcılarını yönlendirir
  • Domain’i etkilemez
  • Kullanıcıya okunabilir hata mesajları sağlar

7. Sonuç

DDD projelerinde doğrulama konusu çoğu zaman FluenvValidation ile karıştırılır. Ancak doğru yaklaşım şudur:

  • Domain Validation: Entity veya Value Object içinde yapılır.
  • Application Validation: FluentValidation veya benzeri araçlarla yapılır.
  • Bu ikisi asla karıştırılmamalıdır.

Bu sayede:

  • Domain Validation, bir domain nesnesinin var olabilmesi için zorunlu kuralları içerir.
  • FluentValidation, kullanıcı girişleri ve API doğrulaması için uygundur.
  • Domain kurallarını FluentValidation’a taşımak, DDD’nin temel prensiplerine aykırıdır.
  • SOLID’in S ilkesi, domain kurallarını entity içinde tutmayı gerektirir.
  • UI/Application validation ile Domain validation farklı amaçlara hizmet eder.
  • DDD tabanlı projelerde en doğru yaklaşım:
    • Domain invariant’ları entity içinde koru

    • Kullanıcı dostu doğrulamaları FluentValidation ile API/UI layer’da yap

By tanju.bozok

Software Architect, Developer, and Entrepreneur

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir