Какие понятия входят в DDD: value object, entity, aggregate
Что проверяют
Различаете ли вы три понятия по поведению, а не по определению из книги, и умеете ли выразить их в коде на C#. Следом обычно спрашивают, как провести границу агрегата и как сохранить всё это через EF Core.
Как отвечать
- Value Object: определяется значениями, а не идентичностью. Два
Money(100, "RUB")равны,Idу них нет. Неизменяем: вместо изменения создаётся новый объект. В C# его удобно описать черезrecordилиreadonly record struct, равенство по значению даёт компилятор, а проверка в конструкторе не позволит создать невалидный объект; - Entity: имеет идентичность, которая сохраняется при изменении атрибутов.
Customerс новым email остаётся тем же клиентом, поэтому равенство сравниваетId, а не поля; - Aggregate: группа сущностей и объектов-значений с одним корнем, который охраняет инварианты. Снаружи изменения идут только через методы корня:
order.AddLine(product, qty), а неorder.Lines.Add(...).
Про агрегат стоит проговорить главное: это граница согласованности и транзакции. Одна транзакция меняет один агрегат, на другие агрегаты ссылаются по идентификатору (CustomerId), а не объектной ссылкой, а согласованность между ними достигается доменными событиями. Репозиторий заводится на корень агрегата, а не на каждую таблицу.
В EF Core объекты-значения мапятся через OwnsOne/OwnsMany или через ComplexProperty (появился в EF Core 8), коллекция внутри агрегата открыта наружу как IReadOnlyCollection<OrderLine> поверх приватного поля, сеттеры закрыты. Агрегат лучше держать небольшим: большой агрегат означает тяжёлую загрузку и частые конфликты оптимистичной блокировки.
Где спотыкаются
Делают сущности анемичными: публичные сеттеры, вся логика в сервисах. Тогда агрегат ничего не охраняет и остаётся просто набором таблиц.
Строят один огромный агрегат «клиент со всеми заказами и платежами». Загрузка тянет половину базы, а параллельные изменения постоянно конфликтуют.
Объявляют сущность через record и получают сравнение по всем полям. Две версии одного клиента перестают быть равными, и в коллекциях появляются дубли.