Совокупность конфликтов корней в логике и производительности

Вопрос:

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

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

class Account{
Budget Budget;
List<Campaign> Campaigns;
// Account stuff
}

class Campaign{
Budget Budget;
List<Mission> Missions;
// Campaign stuff
}

class Mission{
Budget Budget;
double Value;
// Mission stuff
}

Что имеет смысл для логики домена, но у меня возникают проблемы, позволяющие пользователям работать непосредственно с миссиями, поскольку они не заботятся о кампании или учетной записи. Есть также несколько учетных записей, и я должен предоставить пользователю все задачи, которые они могут выполнить. Загрузка всех этих объектов становится тяжелой и сложной, поэтому я подумал о возврате всего и сделать миссию следующим образом:

class Mission{
Budget AccountBudget;
Budget CampaignBudget
Budget MissionBudget
Double Value;
// All mixed stuff that i need
}

Таким образом, у меня будет только репозиторий миссий, и вам будет легче работать со всеми миссиями и пользователями, но когда миссия будет выполнена, мне нужно обновить бюджет аккаунта и кампании для всех миссий. Эта структура также имеет меньшее значение для меня в отношении логики домена. Итак, если я пойду с первым решением, как избежать проблем с производительностью и заставить его работать для пользователя, чтобы получить все доступные миссии? И если я пойду со вторым решением, это имеет смысл?

Лучший ответ:

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

На практике это не кажется особенно хорошим эвристическим; вырезание домена в агрегаты — это больше о поведении, чем о структуре. Вам нужно знать детали учетной записи, чтобы изменить миссию? Вам нужно знать детали миссии, чтобы изменить учетную запись?

У меня возникли проблемы, позволяющие пользователям работать непосредственно с миссиями, так как они не заботятся о кампании или учетной записи.

Это большой намек на то, что миссии, возможно, представляют собой отдельный агрегат; это особенно важно, если вы ожидаете, что многие пользователи будут манипулировать своими миссиями одновременно, не наступая друг на друга.

когда миссия выполняется, мне нужно обновить счет и бюджет кампании для всех миссий.

Да, но нужно ли это немедленно или сразу?

Вероятно, вам следует обсудить Грег Янг на складских системах. Основная идея заключалась в том, что модель домена не пыталась помешать пользователям делать что-то; вместо этого основное внимание было уделено созданию «отчетов об исключениях», если у модели есть подозрения, что может возникнуть проблема.

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

Другой взгляд на одну и ту же основную идею — это эссе Udi Dahan Race Conditions Do not Exist

Микросекундная разница в сроках не должна влиять на основные бизнес-модели поведения.

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

Я предполагаю, что в конечном итоге вы окажетесь в структуре Mission

class Mission{
    AccountId accountId;
    CampaignId campaignId;
    MissionId missionId;

    Budget Budget;
    // Mission stuff
}

Есть ли у вас какие-либо предложения по дизайну, позволяющие пользователям взаимодействовать на общем ресурсе или в некоторых источниках для поиска?

Я не чувствую, что там много. Возможно, вы сможете получить некоторые идеи от разговоров Грега Янга в отношении периодически подключаемых систем.

Существует альтернатива рассматривать сообщения из внешнего мира как команды; вы можете считать их событиями: UserDecided, UserSubmittedForm…. Таким образом, внешний мир — это книга записи, и ваш агрегат действует как процессор обработки событий

Alice said X
Bob said !X (contradicting Alice)
... and therefore (other consequences)

где другие последствия могут быть эскалацией для человека или что два решения отменяют друг друга или…

Вы все еще обновляете свою книгу записей, поэтому она все еще является «командой» в смысле CQS handle(Event) слова handle(Event), но вы можете отделить «захват события» от «действия на событие»,

Оцените статью
TechArks.Ru
Добавить комментарий