Domain-Driven Design

Application created with Flexbase Domain-Driven Design Patterns & Best Practices

πŸ—οΈ Domain-Driven Design Implementation

The Application created with Flexbase demonstrates sophisticated Domain-Driven Design (DDD) patterns through its Handler-Domain-Domain Method architecture, showcasing enterprise-grade best practices and clean separation of concerns.


🎯 Core DDD Architecture

Three-Layer Domain Pattern

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Handler Layer (Application)         β”‚ ← Orchestrates business operations
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Domain Layer (Business Logic)       β”‚ ← Contains pure business logic
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Infrastructure Layer (Data)         β”‚ ← Handles persistence and external concerns
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key DDD Principles Implemented

  • Rich Domain Models - Business logic encapsulated in domain entities

  • Ubiquitous Language - Domain terms used consistently across all layers

  • Aggregate Roots - Domain entities manage their own state and invariants

  • Domain Events - Business events published for side effects

  • Repository Pattern - Clean data access abstraction


πŸ”§ Handler Layer - Application Orchestration

Handler Responsibilities

The Handler layer acts as the Application Service in DDD, orchestrating business operations without containing business logic.

// Handler Pattern - Application Service
public partial class AddOrderHandler : IAddOrderHandler
{
    // Dependencies injected - Clean Architecture
    protected readonly ILogger<AddOrderHandler> _logger;
    protected readonly IFlexHost _flexHost;           // Domain access
    protected readonly RepoFactory _repoFactory;      // Data access
    
    // Domain model instance
    protected Order? _model;
    protected FlexAppContextBridge? _flexAppContext;  // Context

    public virtual async Task Execute(AddOrderCommand cmd, IFlexServiceBusContext serviceBusContext)
    {
        // 1. Context Extraction - DDD Context Management
        _flexAppContext = cmd.Dto.GetAppContext();
        
        // 2. Repository Initialization - Infrastructure Setup
        _repoFactory.Init(cmd.Dto);
        
        // 3. Domain Method Invocation - CORE DDD PATTERN
        _model = _flexHost.GetDomainModel<Order>().AddOrder(cmd);
        
        // 4. Persistence Layer - Infrastructure Concern
        _repoFactory.GetRepo().InsertOrUpdate(_model);
        int records = await _repoFactory.GetRepo().SaveAsync();
        
        // 5. Event Publishing - DDD Event-Driven Architecture
        await this.Fire(EventCondition, serviceBusContext);
    }
}

Handler Best Practices Demonstrated

1. Single Responsibility Principle

  • Only orchestrates - No business logic in handlers

  • Manages dependencies - Coordinates between domain and infrastructure

  • Handles transactions - Ensures data consistency

  • Publishes events - Triggers side effects

2. Dependency Inversion Principle

  • Depends on abstractions - Uses interfaces, not concrete implementations

  • Domain-first approach - Handler calls domain, not vice versa

  • Infrastructure abstraction - Repository pattern for data access

3. Command Pattern Implementation

  • Encapsulates requests - Commands contain all necessary data

  • Type safety - Strongly-typed command parameters

  • Validation - Command-level validation before domain processing


πŸ›οΈ Domain Layer - Business Logic Encapsulation

Domain Model Structure

Domain models are Aggregate Roots that encapsulate business logic and maintain invariants.

// Domain Model - Aggregate Root
public partial class Order : DomainModelBridge
{
    // Domain Properties - Business State
    public Guid Id { get; set; }
    public string CustomerId { get; set; }
    public decimal TotalAmount { get; set; }
    public string Status { get; set; }
    public DateTime CreatedDate { get; set; }
    
    // Navigation Properties - Domain Relationships
    public virtual Customer? Customer { get; set; }
    public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
    
    // Audit Properties - Cross-cutting Concerns
    public string? CreatedBy { get; set; }
    public string? LastModifiedBy { get; set; }
    public DateTime? LastModifiedDate { get; set; }
}

Domain Model Best Practices

1. Rich Domain Models

  • Behavior over data - Methods contain business logic

  • Encapsulation - Internal state protected from external modification

  • Invariants - Business rules enforced within the domain

2. Aggregate Root Pattern

  • Single entry point - All operations go through the aggregate root

  • Consistency boundaries - Ensures data integrity within the aggregate

  • Transaction scope - One aggregate per transaction

3. Value Objects and Entities

  • Entities - Have identity (Order, Customer)

  • Value Objects - No identity, immutable (Money, Address)

  • Clear boundaries - Well-defined domain concepts


βš™οΈ Domain Methods - Business Logic Implementation

Domain Method Pattern

Domain methods contain the core business logic and are the heart of DDD implementation.

// Domain Method - Business Logic Implementation
public virtual Order AddOrder(AddOrderCommand cmd)
{
    // 1. Input Validation - Domain Invariants
    Guard.AgainstNull("Order command cannot be empty", cmd);
    
    // 2. DTO to Domain Mapping - Data Transformation
    this.Convert(cmd.Dto);
    
    // 3. Business Logic Application - Core DDD
    this.CreatedBy = cmd.Dto.GetAppContext()?.UserId;
    this.LastModifiedBy = cmd.Dto.GetAppContext()?.UserId;
    
    // 4. Domain State Management - Aggregate State
    this.SetAdded(cmd.Dto.GetGeneratedId());
    
    // 5. Business Rules Enforcement - Domain Invariants
    this.ValidateOrderTotal();
    this.ApplyBusinessRules();
    
    // 6. Domain Event Publishing - Event-Driven DDD
    this.RaiseEvent(new OrderCreatedEvent
    {
        OrderId = this.Id,
        CustomerId = this.CustomerId,
        TotalAmount = this.TotalAmount,
        CreatedAt = DateTime.UtcNow
    });
    
    return this;
}

Domain Method Best Practices

1. Business Logic Encapsulation

  • Pure business logic - No infrastructure concerns

  • Domain invariants - Business rules enforced

  • Validation - Domain-level validation

  • State management - Aggregate state changes

2. Command Pattern Integration

  • Command objects - Encapsulate all necessary data

  • Type safety - Strongly-typed parameters

  • Context preservation - User and request context maintained

3. Event-Driven Architecture

  • Domain events - Business events published

  • Side effects - Triggered by domain events

  • Loose coupling - Modules communicate through events


πŸ”„ Complete DDD Flow Example

AddOrder Operation - DDD in Action

graph TB
    subgraph "Handler Layer (Application)"
        Handler[AddOrderHandler.Execute]
        Context[Extract Context]
        Repo[Initialize Repository]
        Persist[Persist Changes]
        Event[Publish Events]
    end
    
    subgraph "Domain Layer (Business Logic)"
        Domain[Order Domain Model]
        Method[AddOrder Method]
        Rules[Business Rules]
        Validation[Domain Validation]
        State[State Management]
    end
    
    subgraph "Infrastructure Layer (Data)"
        Repository[Repository Factory]
        Database[(Database)]
        MessageBus[Event Bus]
    end
    
    Handler --> Context
    Context --> Repo
    Repo --> Domain
    Domain --> Method
    Method --> Rules
    Method --> Validation
    Method --> State
    Method --> Event
    Handler --> Persist
    Persist --> Repository
    Repository --> Database
    Event --> MessageBus

Step-by-Step DDD Implementation

Step 1: Handler Orchestration

// Handler coordinates the operation
public virtual async Task Execute(AddOrderCommand cmd, IFlexServiceBusContext serviceBusContext)
{
    // Extract application context
    _flexAppContext = cmd.Dto.GetAppContext();
    
    // Initialize infrastructure
    _repoFactory.Init(cmd.Dto);
    
    // Delegate to domain - CORE DDD PRINCIPLE
    _model = _flexHost.GetDomainModel<Order>().AddOrder(cmd);
    
    // Handle infrastructure concerns
    _repoFactory.GetRepo().InsertOrUpdate(_model);
    await _repoFactory.GetRepo().SaveAsync();
    
    // Publish domain events
    await this.Fire(EventCondition, serviceBusContext);
}

Step 2: Domain Business Logic

// Domain contains the business logic
public virtual Order AddOrder(AddOrderCommand cmd)
{
    // Business validation
    Guard.AgainstNull("Order command cannot be empty", cmd);
    
    // Data transformation
    this.Convert(cmd.Dto);
    
    // Business rules application
    this.CreatedBy = cmd.Dto.GetAppContext()?.UserId;
    this.LastModifiedBy = cmd.Dto.GetAppContext()?.UserId;
    this.SetAdded(cmd.Dto.GetGeneratedId());
    
    // Domain event publishing
    this.RaiseEvent(new OrderCreatedEvent { ... });
    
    return this;
}

Step 3: Infrastructure Handling

// Infrastructure handles data persistence
_repoFactory.GetRepo().InsertOrUpdate(_model);
int records = await _repoFactory.GetRepo().SaveAsync();

// Event publishing for side effects
await this.Fire(EventCondition, serviceBusContext);

🎯 DDD Best Practices Demonstrated

1. Separation of Concerns

  • Handler Layer: Orchestration, transaction management, event publishing

  • Domain Layer: Business logic, rules, invariants, domain events

  • Infrastructure Layer: Data persistence, external service integration

2. Dependency Inversion

  • High-level modules (Handlers) don't depend on low-level modules (Database)

  • Domain layer is independent of infrastructure

  • Abstractions define contracts between layers

3. Single Responsibility Principle

  • Handlers: Only orchestrate operations

  • Domain Models: Only contain business logic

  • Repositories: Only handle data access

4. Open/Closed Principle

  • Open for extension: New domain methods, handlers, events

  • Closed for modification: Existing domain logic doesn't change

  • Plugin architecture: Easy to add new business capabilities

5. Interface Segregation

  • Focused interfaces: Each interface serves specific purpose

  • Client-specific contracts: Handlers only depend on what they need

  • Loose coupling: Changes in one interface don't affect others


πŸš€ Advanced DDD Patterns

1. Aggregate Pattern

// Order is an Aggregate Root
public partial class Order : DomainModelBridge
{
    // Manages OrderItems as part of the aggregate
    public virtual ICollection<OrderItem> OrderItems { get; set; }
    
    // Business method that maintains aggregate consistency
    public virtual Order AddItemToOrder(AddItemToOrderCommand cmd)
    {
        // Business logic to add item
        // Maintains aggregate invariants
        // Publishes domain events
        return this;
    }
}

2. Domain Events Pattern

// Domain events for side effects
public class OrderCreatedEvent : IFlexEvent
{
    public Guid OrderId { get; set; }
    public string CustomerId { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime CreatedAt { get; set; }
}

// Event publishing in domain method
this.RaiseEvent(new OrderCreatedEvent
{
    OrderId = this.Id,
    CustomerId = this.CustomerId,
    TotalAmount = this.TotalAmount,
    CreatedAt = DateTime.UtcNow
});

3. Repository Pattern

// Repository abstraction for data access
_repoFactory.GetRepo().InsertOrUpdate(_model);
int records = await _repoFactory.GetRepo().SaveAsync();

// Domain doesn't know about database specifics
// Infrastructure handles the implementation details

4. Command Pattern

// Commands encapsulate business operations
public class AddOrderCommand : FlexCommandBridge<AddOrderDto, FlexAppContextBridge>
{
    public AddOrderDto Dto { get; set; }
    public FlexAppContextBridge Context { get; set; }
    public string CorrelationId { get; set; }
    public DateTime Timestamp { get; set; }
}

πŸ“Š DDD Benefits Achieved

1. Maintainability

  • Clear boundaries - Each layer has distinct responsibilities

  • Business logic isolation - Domain logic is separate from infrastructure

  • Easy testing - Each layer can be tested independently

  • Consistent patterns - Same structure across all modules

2. Scalability

  • Horizontal scaling - Stateless handlers can be scaled independently

  • Event-driven - Loose coupling through domain events

  • Microservices ready - Clear boundaries enable service extraction

3. Business Alignment

  • Ubiquitous language - Domain terms used consistently

  • Business logic centralization - All business rules in one place

  • Domain expert collaboration - Clear domain model for business discussions

4. Quality Assurance

  • Type safety - Compile-time validation throughout

  • Invariant enforcement - Business rules enforced at domain level

  • Error prevention - Framework prevents common mistakes

  • Consistent behavior - Same patterns across all operations


🎯 Key Takeaways

DDD Implementation Success

The YourApplication solution demonstrates enterprise-grade DDD implementation with:

  1. Clean Architecture - Clear separation between layers

  2. Rich Domain Models - Business logic properly encapsulated

  3. Event-Driven Design - Loose coupling through domain events

  4. Repository Pattern - Clean data access abstraction

  5. Command Pattern - Encapsulated business operations

Business Value Delivered

  • Maintainable Code - Clear structure and separation of concerns

  • Testable Architecture - Each layer can be tested independently

  • Scalable Design - Ready for horizontal scaling and microservices

  • Business Alignment - Domain model reflects business concepts

  • Quality Assurance - Consistent patterns and error prevention


This document showcases how the YourApplication solution implements Domain-Driven Design principles through its Handler-Domain-Domain Method architecture, delivering enterprise-grade maintainability, scalability, and business alignment.

Last updated