Pull to refresh

Comments 27

В рамках одной транзакции в ограниченном контексте должно происходить изменение только одного агрегата.

Вот это, на мой взгляд, довольно спорное утверждение. Правильнее было бы сказать, что изменение агрегата должно обязательно происходить в транзакции.

Я тоже так подумал, но в книге «Реализация методов предметно-ориентированного проектирования» на этом акцентировалось внимание несколько раз, поэтому добавил это.
А можно подробнее раскрыть тему агрегатов?
Правильно ли я понимаю, что область применения этого шаблона, в рамках концепции DDD — только всякого рода отчёты? Как они соотносятся с сущностями?
агрегат — это граф сущностей, используемых в одном контексте. Например Order (Заказ) и OrderLines (Строки Заказа). OrderLines в отрыве от заказа неуместны, поэтому они используются только в составе агрегата Order, который состоит из корня агрегата/сущности Order и связанных с ним сущностей OrderLines.

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

Изменения данных должны быть в рамках одной транзакции, главное чтобы всегда соблюдались инварианты.
Это просто шаблон который состоит из нескольких объектов, доступ к которым можно получить только через корень
Это просто составной объект, он рассматривается как одно целое с точки зрения изменения данных. Главное чтобы всегда выполнялись все инварианты
Если какое-то понятие предметной области является уникальным и отличным от всех других объектов в системе, то для его моделирования используется сущность.

До какой степени выделять?
Допустим товар может иметь такие свойства: цвет и объем памяти.
Но выделять все свойства в отдельную сущность — вряд ли правильно при большом числе свойств. :)

На счет генерирования ИД можно поговорить и в отдельной статье. :)

Цвет и объем памяти, если уж на то пошло, надо выделять в объект-значение.


Сущность — это то, что имеет идентичность, которая не выражается через его данные (сложно сказано).


То есть, если есть сущность клиент, то может быть два Ивана Петрова мужчина холост 65 года рождения, которые, тем не менее, разные.


Объект-значение, напротив, имеет идентичность, выражаемую через его данные. Например, объем памяти 128МВ имеет два атрибута — объем — 128 и единицы измерения (мегабайты). И два значения являются одинаковыми, если у них совпадает объем и единицы измерения.

Выделять нужно не по степени, а по конкретному ограниченному контексту. Один объект или понятие предметной области может в одном контексте являться сущностью, в другом — объектом-значением, в третьем — вообще игнорироваться. Если в одном контексте интересен только суммарный объём установленных модулей памяти, без уточнения сколько и каких там модулей, то модуль нет смысла делать сущностью, но в системе учёта гарантий каждый модуль является отдельной сущностью со своим идентификатором.
Сущность — не сущность — это такое.

Больше интересует даже другой вопрос:
Хранить ли справочник «память» и «цвет» в одной таблице или в разных. :)
Это не вопрос моделирования :) Вы можете моделировать цвет отдельной сущностью с кучей методов типа «повеселее», а хранить простой строкой в таблице основной сущности.
Ну так весь вопрос как такие сущности-полусущности хранить в одной таблице свойств товаров…
С учетом того, что что-то будет отдельной сущностью (зачем?), а что-то нет. :)
В одной таблице с сущностью легко можно хранить ValueObject, который может занимать несколько столбцов типа memory_amount и memory_unit, которые будут маппиться на entity.memory.amount и entity.memory.unit, а может храниться в одном столбце типа memory в сериализованном виде типа {«amount»: 512, «unit»: «MB»}. С сущностями можно тоже так поизвращаться, но обычно смысла нет.
Это все общий текст.
Покажите пример реализации :)

Хранить сериализировано — тот еще адок. :)
В mysql json только недавно добавили. То есть на старших версиях фильтрация и сортировка работать не будут.
Ну и индексов на это не навесить :)
doctrine embeddables — пример реализации первого варианта
В Doctrine есть оба. Фильтрация, сортировка, связность реализуются на уровне приложения.

Если значение для сущности не набор, а одна еденица и нужно ей добавить функции или ограничить набор допустимых значений, как в случае ENUM, то можно создать свой тип для маппинга в Doctrine.


Вообще DDD в php лучше реализовывать через Doctrine.

Модуль в понятиях DDD может ли содержать в себе сервисы из инфраструктурного или слоя приложения?
Условно говоря — модуль «оформления заказа» имеет в себе, помимо доменных моделей, ещё и инфраструктурные шлюзы оплаты или что-либо в таком духе.
модуль имеет внутри себя все, что нужно для его работы, то есть да, он должен иметь все слои. Нюанс: оплата может стать неплохим пластом кода, поэтому, возможно, следует вынести в отдельный модуль, а в первом оставить лишь интерфейс сервиса оплаты.
Модули внутри модели являются именованными контейнерами для некоторой группы объектов предметной области

For a large and complex application, the model tends to grow bigger and bigger. The model reaches a point where it is hard to talk about as a whole, and understanding the relationships and interactions between different parts becomes difficult. For that reason, it is necessary to organize the model into modules.

Здесь, в статье, и в DDD Quickly везде написано что «Модуль» включается в себя разбитую на куски «Модель» когда она слишком разрастается.
Это не доменная модель? Что это за модель тогда? «Модель» = «модель всей предметной области» = «всё моё приложение»? Если так, то да — всё приложение целиком включает в себя любые необходимые слои. Но если имеется ввиду разбиение именно доменной модели, то тут не могут быть никакие другие слои, кроме непосредственно доменного.
да, имеется в виду доменная модель, как ядро модуля, вокруг которого он строится. Но это не значит, что модуль состоит только из слоя домена.
Но какой же может быть cohesion внутри модуля между слоями?

DDD Quickly:
While cohesion starts at the class and method level, it can be applied at module level. It is recommended to group highly related classes into modules to provide maximum cohesion possible.


Но тут опять же ничего не сказано про другие слои. Я могу интерпретировать эту фразу как: связывай доменные модели, но не делай связи между слоями внутри модуля.
обычный cohesion.
Надо отметить, что в DDD quickly, указан повод для выделения домена в модуль, но не говорится, что в модуле должен быть только домен, поскольку модуль — это не ddd-понятие, а общий термин программирования.
вот например реализация приложения из классической книги Эванса https://github.com/codeliner/php-ddd-cargo-sample/tree/master/CargoBackend/src
как видим в модуле присутствуют все 4 слоя.
Я стараюсь выносить шлюзы и прочую инфраструктуру вовне модулей домена. Доменные модели и сервисы используют интерфейсы/абстрактные классы, а нужные реализации подтягиваются в рантайме через DIC/SL/etc. Условно — модуль «оформления заказа» содержит абстрактный класс «платежная система» с которым модуль и работает, а экземпляр конкретного класса создаётся на уровне приложения перед тем как обратиться к модулю.
Самая приятная и полезная статья из всех, что я читал. Автору большое спасибо!
Sign up to leave a comment.

Articles