Посмотрел и понял что не могу быть они разной длинны. Иначе сразу нету однозначного решения. Только нижняя в принципе может быть короче. Но тогда мы сразу знаем что она нижняя =)
Давайте =) Нижняя всегда должа быть пересечена всеми 3-мя. Её найти просто. Все последующие ищем по такому алгоритму: палка должна быть пересечена количеством на 1 меньше чем предыдущая + должна пересекать предыдущую. Вот и все)
Они на счет границ ничего не говорят. Говорят только, что в некоторых случаях лучше избегать применения CQRS, чтобы не усложнить систему. У Udi даже пост есть «When to avoid CQRS»
Самый простой вариант добавить LastName и FirstName, а в коде уже обрабатывать ситуацию когда они не заданы. Но тут тема, конечно, для отдельной статьи. Раньше мы писали патчи, которые проходились по всему event store и меняли устаревшие события на новый формат. Однако, я сейчас склоняюсь к тому, что это не правильных подход.
Границ применимости я не вижу, честно говоря, и не думаю что они есть. А ограничений у данного подхода не больше чем у ORM, при том что возможности намного шире.
Постараюсь в следующих статьях это продемонстрировать. Спасибо за ваши комментарии.
Ну не получилось например потому, что вы не учли некоторые детали при проектировани и они добавились позже, когда уже нету возможности заново проектировать домен. Это конечно плохо, но всякое случается. В случае с CQRS концептуально неправильно получать данные из write модели. Единственное что вам может вернуть агрегат — это исключение. Конечно вы можете это правило игнорировать, но тогда могут возникнуть проблемы с масштабируемостью. Так же команда должна относить только к одному агрегату, поэтому поднимать какой-либо другой тоже концептуально не правильно, не говоря уже о том чтобы открыть доступ извне к его состоянию.
Если у вас все-таки не получилось спроектировать систему так, что любое бизнес правило может быть проверено в рамках одного агрегата, то это проблема, но проблема решаемая.
Я могу вам предложить 3 способа. 1. Самый простой способ — это проверять бизнес правило по данным read модели перед отправкой команды. Но так как в этом случае данные read модели могут быть не консистентны, способ стоит применять только если ваша бизнес модель допускает вероятность ошибки при проверке этого правила, так как на время отправки команды в read модели могут находится не актуальные данные. Вероятность конечно очень мала но она есть. Мы часто используем этот подход так как он самый простой и не накладывает дополнительных ограничений. 2. Вы можете в Command Handler'e восстановить два агрегата, сначала попытаться изменить состояние одного, в котором проверяется бизнес правило. Если не возникло исключительной ситуации, изменить состояние второго агрегата. Но это накладывает ограничение на масштабируемость так как теперь вы не можете разделить эти два агрегата. 3. Самый концептуально правильный подход — это организовать месседжинг между агрегатами. Т.е. вы сначала отправляете команду в один агрегат, там проверяется ваше бизнес правило, инициируется событие, в обработчике этого события в отправляете команду в другой агрегат, которая уже содержит информацию о том что бизнес правило выполнилось.
Так как у вас корее всего будет событие OrderItemAdded, вам достаточно будет написать так
public class OrderState
{
public ICollection Items { get; private set; }
public decimal Total { get; private set; }
public void On(OrderItemAdded e)
{
var item = new Item(e.Price, e.Quantity);
Items.Add(item);
Total += e.Price + e.Quantity;
}
}
В read моделе вы тоже можете обработать это событие подобным образом.
Если вам надо просто показать «Итого», то тут нету никаких проблем. Вы можете хранить в read модели данные как вам захочется. Можете хранить где-то список позиций для пользователя и каждый раз считать итоговую сумму, или вообще хранить сразу готовую итоговую сумму и обновлять её когда приходит события добавления новой позиции.
Проблемы начнутся когда у вас появится бизнес правило которое зависит от итоговой суммы. Но это задача тоже решается, просто надо правильно спроектировать агрегат, чтобы при добавлении юзером новой позиции у агрегата был доступ к итоговой сумме.
Постараюсь в следующих статьях это продемонстрировать. Спасибо за ваши комментарии.
Я могу вам предложить 3 способа.
1. Самый простой способ — это проверять бизнес правило по данным read модели перед отправкой команды. Но так как в этом случае данные read модели могут быть не консистентны, способ стоит применять только если ваша бизнес модель допускает вероятность ошибки при проверке этого правила, так как на время отправки команды в read модели могут находится не актуальные данные. Вероятность конечно очень мала но она есть. Мы часто используем этот подход так как он самый простой и не накладывает дополнительных ограничений.
2. Вы можете в Command Handler'e восстановить два агрегата, сначала попытаться изменить состояние одного, в котором проверяется бизнес правило. Если не возникло исключительной ситуации, изменить состояние второго агрегата. Но это накладывает ограничение на масштабируемость так как теперь вы не можете разделить эти два агрегата.
3. Самый концептуально правильный подход — это организовать месседжинг между агрегатами. Т.е. вы сначала отправляете команду в один агрегат, там проверяется ваше бизнес правило, инициируется событие, в обработчике этого события в отправляете команду в другой агрегат, которая уже содержит информацию о том что бизнес правило выполнилось.
В read моделе вы тоже можете обработать это событие подобным образом.
Проблемы начнутся когда у вас появится бизнес правило которое зависит от итоговой суммы. Но это задача тоже решается, просто надо правильно спроектировать агрегат, чтобы при добавлении юзером новой позиции у агрегата был доступ к итоговой сумме.