Как разделить сущность доктрины на более доменные сущности в разных ограниченных контекстах?
Я пробую свои первые шаги в DDD (домен-управляемая конструкция поле). Мне нравится мудрое правило, что вы должны разделить свои сущности на множество меньших, контекстно-специфичных сущностей (например User
сущность имеет тенденцию перерастать почти в каждом не-ddd или плохо разработанном приложении). Но каковы общие варианты того, как это сделать (эффективно) в php с использованием доктрины?
предположим, у меня есть два ограниченных контекста:Store
и Invoicing
каждый из них имеет двух сущностей предметной области :
для магазина BC это FirstTimeCustomer
и RecurrentCustomer
для выставления счета BC это VatCustomer
и NonVatCustomer
теперь, на моем уровне инфраструктуры, я хочу, чтобы все они были сохранены в одной (по крайней мере, базовой) таблице, чтобы иметь возможность ссылаться на них general UserId
(Uuid). Проблема для меня в том, как это сделать, чтобы я мог использовать преимущество doctrine automapping в своих реализациях репозитория.
Я читал о наследовании одной таблицы или Наследование Таблицы Классов что может быть решением, но:
мне нужно иметь возможность работать с User
того же Uuid, что и другой тип в каждом контексте.
мне нужно иметь возможность вернуть некоторые AbstractStoreCustomer
ака FirstTimeCustomer
или RecurrentCustomer
on $storeCustomerRepository->find(1);
в магазине BC.
и вернуть AbstractInvoicingCustomer
ака VatCustomer
или NonVatCustomer
on $invoicingCustomerRepository->find(1);
в выставлении счетов BC.
но, похоже, я вынужден здесь выбрать то, к чему я хочу привязать конкретную идентичность сущности. Так что это не имеет смысла в контекст DDD для меня вообще.
Я также читал о Сопоставлены Суперклассов, это тоже похоже на вариант, но:
это означает, что ассоциации "один ко многим" невозможны на сопоставленном вообще суперкласс.
а мне нужно Customer
чтобы иметь отношение к заказам, которые должны быть доступны в обеих сущностях (также, возможно, не хотите, чтобы он был доступен, это какой-то новый тип User
сущность в новом BC).
I пришел к выводу, что я должен подозревать, что я что-то упускаю, не так ли? Как я должен достичь разбиения сущности Бога на более мелкие контекстно-специфические?
1 ответов
я начну с некоторых общих правил. Думая о DDD, вы должны отбросить любые мысли о постоянстве (таблицы и первичные ключи и тому подобное). Вы должны создавать свои агрегатные корни и сущности так, как если бы вы хранили их в файле. Когда вы разрабатываете модели, Если вам приходит в голову мысль о таблицах или ORM, вы не можете сделать DDD; сделайте шаг назад и перезапустите.
как я вижу, вы начали нормально, разделив свои модели на ограниченные контексты. Если вы не разделите их на BCs в конечном итоге вы получаете гигантские модели, которые пытаются охватить все поведение, а затем постоянство повлияет на производительность, потому что в DDD агрегаты сохраняются в одной транзакции. Еще одно, старайтесь избегать наследования и использовать композицию.
это, как говорится, давайте поговорим о вашем бизнесе.
В Authentication
BC, есть Users
который может аутентифицироваться с некоторыми учетными данными. В Store
до н. э. Есть Customers
что покупать вещи. В Invoice
до н. э., Есть также Customers
но другую модель (другой класс, если хотите). В Shipping
BC есть также Customers
но, опять же, разные модели. Эти Customer
модели разделяют некоторые свойства вдоль BCs, как name
и id
. Итак, вы используете id
чтобы идентифицировать человека из реальной жизни, но использовать различные модели для инкапсуляции их поведения в зависимости от контекста.
я думаю, что у вас не должно быть AbstractStoreCustomer
, вы должны иметь только Customer
и попытаться изолировать то, что дифференцируйте их в абстрактном классе / интерфейсе, например BuyingHistoryProfile
С 2 реализация FirstTimeCustomer
и RecurrentCustomer
. Этот класс должен содержать только поведение относительно профиля покупки, и на него должен ссылаться каждыйCustomer
на Store
до нашей эры. Аналогично, попробуйте извлечь класс в Invoicing
BC для расчета цены.
теперь, когда мы создали модели, мы можем думать о сохраняемости. Для каждого ограниченного контекста создайте Customer
таблица, содержащая общие свойства (name
и id
) и специфические свойства (buyingHistoryProfile
на Store
BC,priceCalculationStrategy
на Invoicing
до н. э. и т. д.).
если вам интересно, что есть степень дублирования данных, то вы правы, но это нормально, необходимо отделить модели. Эти повторяющиеся данные синхронизируются, когда User
на Authentication
BC изменить свое имя: вы обновляете все другие модели прямо тогда. С этой точки зрения, Invoice
и Store
BC вниз-потоки, они используют данные от Authentication
BC; это зависит от вашего бизнеса, когда обновление инициируется.
будучи поклонником событийных архитектур, я рекомендую вам взглянуть на CQRS (и даже на источники событий). Я думаю, что эти архитектуры хорошо вписываются в это приложение. CQRS может сделать ваши модели в 10 раз чище, я говорю вам по своему опыту. С Event Sourcing очень вероятно, что вам даже не придется использовать ORM
. Вы могли бы использовать ORM
на стороне чтения, если вам действительно нравится они или ты!--48-->не могу оставить их. Я лично не люблю (и не использую) ORM
s.