DDD и авторизационно-зависимые объекты как совокупные корни?
Интересно, должен ли я моделировать зависимые объекты как совокупные корни. Допустим, у меня есть TaskList
и этот список имеет Task
s. Task
не может существовать без TaskList
но это можно просматривать и редактировать отдельно. Там нет особых условий, что TaskList
мог бы проверить, когда Задача изменена или добавлена - что, я думаю, было бы основной причиной совокупного корня. Единственное условие, что TaskList
и его задачи могут быть отредактированы только владельцем. Было бы легко обеспечить это условие, если TaskList
был владелец, и задачи можно редактировать только через TaskList. В противном случае мне необходимо было бы определить владельца или добавить поле владельца к задачам.
Так что здесь уместно?
- Task и TaskList как совокупные корни и каждый с полем владельца
- Только TaskList в качестве совокупного корня и Tasks в качестве зависимых объектов
Я что-то упустил?
2 ответа
- Если нет никаких инвариантов, управляющих обоими, проектируйте их как отдельные агрегаты.
- Список задач - это фабрика задач, что позволяет ему определить, кто является владельцем задачи. Любое последующее поведение задачи теперь может проверить, что оно выполнено надлежащим владельцем (то есть задача должна помнить, что список сообщил владельцу). Тем не менее, это выглядит как плохой дизайн с точки зрения UX. Зачем включать кнопку редактирования (или показывать детали как редактируемые) для задач, владельцем которых не является пользователь? Да, человек в середине атаки возможен. Но сколько времени / денег вы готовы потратить на это (насколько это важно)?
- Что касается авторизации, задайте вопрос, сколько это является частью вашей модели. Не говорить, что это не так или есть, просто о чем подумать.
- Подробнее о совокупном дизайне можно узнать здесь: Эффективный совокупный дизайн и повышение производительности и масштабируемости с помощью DDD
Я бы сделал это так:
class TaskList{
User Owner;
Task[] Tasks;
}
class Task{
TaskList List; string Description;
void ChangeDescription(description){
if(List.Owner!=CurrentUser)
throw exception or whatever;
else
Description=description;
}
}
// http post
class TaskController{
ActionResult ChangeDescription(int id, string description){
_tasks.Find(id).ChangeDescription(description);
}
}