← Назад к вопросам

Что такое DDD?

2.3 Middle🔥 161 комментариев
#Архитектура и микросервисы

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Domain-Driven Design (DDD)?

Domain-Driven Design (DDD) — это методология разработки программного обеспечения, которая фокусируется на сложных бизнес-доменах и их точном отображении в коде. Основная цель DDD — создание гибкой, поддерживаемой и эволюционирующей системы, которая тесно связана с бизнес-процессами и терминологией заказчика. Ключевая идея: язык домена (Ubiquitous Language) должен быть единым для всех участников проекта — от бизнес-аналитиков до разработчиков.

Ключевые концепции DDD

1. Ограниченный контекст (Bounded Context)

Это центральная организационная единица в DDD. Каждый ограниченный контекст определяет четкие границы, внутри которых действует конкретная модель домена со своим языком и правилами. Например, в системе электронной коммерции могут быть отдельные контексты: Управление заказами, Доставка и Оплата.

// Пример структуры проекта для ограниченного контекста "Ordering"
Ordering.Domain/
    ├── Entities/           // Сущности
    ├── ValueObjects/       // Объекты-значения
    ├── Aggregates/         // Агрегаты
    └── DomainServices/     // Доменные сервисы

Ordering.Application/
    ├── Commands/          // Команды
    ├── Queries/           // Запросы
    └── Services/          // Прикладные сервисы

2. Сущности (Entities) и Объекты-значения (Value Objects)

  • Сущности — это объекты с уникальной идентичностью, которая сохраняется на протяжении всего жизненного цикла. Например, Customer с CustomerId.
  • Объекты-значения — неизменяемые объекты без идентификатора, определяемые своими атрибутами. Например, Address или Money.
// Сущность
public class Customer : Entity<Guid>
{
    public string Name { get; private set; }
    public Email Email { get; private set; } // Value Object
    
    public Customer(Guid id, string name, Email email)
    {
        Id = id;
        Name = name;
        Email = email;
    }
}

// Объект-значение
public class Address : ValueObject
{
    public string Street { get; }
    public string City { get; }
    
    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Street;
        yield return City;
    }
}

3. Агрегаты (Aggregates)

Агрегат — это кластер связанных объектов (сущностей и значений), который рассматривается как единое целое. У каждого агрегата есть корень (Aggregate Root), через который происходит все взаимодействие. Это обеспечивает инкапсуляцию и целостность данных.

// Агрегат Order с корнем Order
public class Order : AggregateRoot<Guid>
{
    private readonly List<OrderItem> _items = new();
    
    public DateTime OrderDate { get; private set; }
    public Address ShippingAddress { get; private set; }
    public IReadOnlyCollection<OrderItem> Items => _items.AsReadOnly();
    
    public void AddItem(Product product, int quantity)
    {
        // Бизнес-правила внутри агрегата
        if (quantity <= 0)
            throw new DomainException("Quantity must be positive");
            
        _items.Add(new OrderItem(product.Id, product.Price, quantity));
    }
}

4. Доменные сервисы (Domain Services) и События домена (Domain Events)

  • Доменные сервисы содержат бизнес-логику, которая не принадлежит конкретной сущности или значению.
  • События домена — это неизменяемые объекты, которые фиксируют факты, произошедшие в домене.
// Доменное событие
public class OrderPlacedEvent : DomainEvent
{
    public Guid OrderId { get; }
    public decimal TotalAmount { get; }
    
    public OrderPlacedEvent(Guid orderId, decimal totalAmount)
    {
        OrderId = orderId;
        TotalAmount = totalAmount;
    }
}

// Доменный сервис
public class OrderService : IDomainService
{
    public bool CanPlaceOrder(Customer customer, Order order)
    {
        // Сложная бизнес-логика, затрагивающая несколько агрегатов
        return customer.IsActive && order.Items.Any();
    }
}

Паттерны и слои в DDD

Стратегическое проектирование

  • Картирование контекстов (Context Mapping)
  • Общий язык (Ubiquitous Language)
  • Разделение на поддомены (Core, Supporting, Generic)

Тактическое проектирование

  • Репозитории (Repositories) для доступа к агрегатам
  • Фабрики (Factories) для создания сложных объектов
  • Спецификации (Specifications) для инкапсуляции бизнес-правил

Преимущества DDD для C# Backend

  1. Глубокая связь с бизнесом — разработчики говорят на языке заказчика
  2. Гибкость и поддерживаемость — четкие границы контекстов упрощают изменения
  3. Тестируемость — доменная логика изолирована от инфраструктуры
  4. Эволюционная архитектура — система может развиваться с ростом бизнеса
  5. Качество кода — явное выражение бизнес-правил снижает количество ошибок

Когда применять DDD?

  • Сложные бизнес-домены с множеством правил и процессов
  • Долгосрочные проекты с ожидаемой эволюцией
  • Команды, готовые к тесному сотрудничеству с экспертами предметной области
  • Системы, где качество и гибкость критически важны

Пример реализации в C#

// Применение DDD в ASP.NET Core
public class OrdersController : ControllerBase
{
    private readonly IOrderRepository _orderRepository;
    private readonly IMediator _mediator;
    
    [HttpPost]
    public async Task<IActionResult> PlaceOrder([FromBody] PlaceOrderCommand command)
    {
        // Команда обрабатывается через медиатор
        var result = await _mediator.Send(command);
        
        if (result.IsSuccess)
            return Ok(new { OrderId = result.Value });
            
        return BadRequest(result.Error);
    }
}

// Команда и обработчик
public record PlaceOrderCommand(Guid CustomerId, AddressDto ShippingAddress, List<OrderItemDto> Items);

public class PlaceOrderHandler : IRequestHandler<PlaceOrderCommand, Result<Guid>>
{
    public async Task<Result<Guid>> Handle(PlaceOrderCommand request, CancellationToken ct)
    {
        // Восстановление агрегата
        var customer = await _customerRepository.GetByIdAsync(request.CustomerId);
        
        // Создание заказа через фабрику
        var order = OrderFactory.Create(customer, request.ShippingAddress, request.Items);
        
        // Применение бизнес-правил
        if (!_orderService.CanPlaceOrder(customer, order))
            return Result.Failure<Guid>("Cannot place order");
        
        // Сохранение и публикация событий
        await _orderRepository.AddAsync(order);
        await _unitOfWork.SaveChangesAsync(ct);
        
        return Result.Success(order.Id);
    }
}

DDD требует значительных усилий на начальном этапе, но окупается в долгосрочной перспективе для сложных систем. В экосистеме .NET он хорошо сочетается с CQRS, Event Sourcing и микросервисной архитектурой, позволяя создавать масштабируемые и адаптивные системы.

Что такое DDD? | PrepBro