DDD Выбор агрегированных корней

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

Основные основные сущности - это клиент, проект, сотрудник, назначение проекта, отдел, расписание. У клиента есть один или несколько проектов, у проекта есть один или несколько сотрудников, назначенных ему (через ProjectAssignment), сотрудник принадлежит отделу, а расписание связывает проект и сотрудника вместе.

Клиент кажется очевидным совокупным корнем.

Client -> Project -> ProjectAssignment -> Employee

Что касается других агрегатов, я не уверен, что лучше всего сделать ...

Я думал...

Department -> Employee -> Person

Или сделайте «Сотрудник» и «Отдел» целиком как отдельные агрегаты. Сотрудники могут быть только в одном отделе и только в одном отделе. Однако для создания иерархии отделов используется самостоятельная ссылка на отдел.

Как вы справляетесь с объектами, совместно используемыми между совокупными корнями?


person greyfox    schedule 09.03.2017    source источник


Ответы (4)


DDD - это не структура данных или взаимосвязь между этими структурами, а изменения, которые происходят с этими данными и границами вокруг этих изменений. DDD очень плохо объясняется во многих местах, включая курсы или конференции Pluralsight, где люди создают простое приложение, ориентированное на одного пользователя, и изо всех сил стараются навязать как можно больше принципов DDD.

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

Начало проектирования со структуры данных - это причина номер один, по которой люди терпят неудачу в DDD. Из того, что вы предоставили, мне кажется, что ваш агрегат скорее ProjectAssignment и, возможно, Timesheet, потому что здесь, вероятно, будет лежать основная бизнес-логика. Все остальное - это лишь объекты-значения (или сущности, если вы должны использовать ORM), которые можно создать с помощью простого подхода в стиле CRUD. Существует множество дискуссий и сообщений в блогах о различиях между сущностями и объектами-значениями. Люди склонны придавать какое-то значение «объектам», которые они имеют в своей области, но для экспертов в области эти драгоценные объекты, на создание которых мы тратим так много времени, являются просто ценностями, не более того. Так что не продвигайте Client или Department как совокупный корень - это просто ценности.

Не бойтесь использовать CRUD. Многие вещи, с которыми вы сталкиваетесь при разработке своего домена, будут просто объектами ценности для экспорта домена. Они просто используют их для выполнения операций с настоящими бизнес-объектами. Их не волнует, как создается Client, как создается Department или как создается Department иерархия. Они просто создают их, а затем редактируют или удаляют. Таким образом, слова, используемые для описания Client или Department, будут просто создавать, обновлять или удалять - и эти слова очень плохие кандидаты для повсеместного языка (язык предметной области). Вездесущий язык - это очень недооцененный образец в DDD. При правильном использовании вы сэкономите массу времени, которое вы тратите на проектирование вещей, которые просто не имеют значения для бизнеса. Каждый раз, когда вы думаете, что вам нужно что-то создать или обновить - используйте CRUD! Не утруждайте себя принципами DDD, потому что они просто неприменимы, когда речь идет о таких словах, как создание или обновление.

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

person berhalak    schedule 13.03.2017
comment
Очень хороший ответ! Будет ли DDD применяться в длинном механизме бизнес-обработки (несколько сложных алгоритмов, которые работают в течение минут / часов), где взаимодействие с пользователем - это всего лишь несколько входов? Это пример проблемы домена без сотрудничества? - person Narayana; 03.02.2018
comment
Короткий ответ: нет. DDD - это инструмент для разработки программного обеспечения, а не для его реализации. Конечно, вы всегда можете использовать все артефакты или шаблоны, которые он приносит (поскольку они имеют отдельную ценность). Когда вы реализуете алгоритмы, лучше использовать здравый смысл: процедурный образ мышления или умственный подход с некоторыми шаблонами проектирования, потому что люди, которые будут взаимодействовать с вашим кодом (то есть: читать его позже или исправлять), будут разработчиками, а не бизнесменами. Подводя итог: DDD - это инструмент проектирования для создания кода, который легко читать людям, говорящим на деловом языке. - person berhalak; 11.12.2019
comment
Во-первых, отличный ответ. Для смеха, потому что вы прокомментировали, что этому так плохо преподают - я думаю, это потому, что язык настолько чувствителен в технических областях, я просто хотел указать на типы утверждений, из-за которых этот предмет так сложно преподавать. Затем создайте единый объект, который выполняет это изменяет и объединяет его с любыми другими необходимыми сущностями (объектами значений) в агрегате. ... - person Sinaesthetic; 12.05.2021
comment
... Хотя я знаю, что вы на самом деле говорили (совокупность - это концептуальная граница, а не физическая граница), после прочтения этой строки я сразу же подумал о создании класса, который физически обернул / содержал совокупный корень, что совершенно неверно . Во всяком случае, мне это показалось забавным. - person Sinaesthetic; 12.05.2021

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

ProjectAssignment должен быть объектом значения в Project AR, который содержит список идентификаторов занятости и другие данные, такие как дата назначения.

Timesheet может быть объектом значения внутри Employee, содержащим список Projects IDs и другие данные, такие как дата начала и дата окончания.

Employee AR может содержать ссылку на свой Department ID инвариант, согласно которому сотрудник принадлежит только к одному отделу.

person Constantin Galbenu    schedule 09.03.2017

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

Давайте посмотрим на сотрудников и отдел. Проверьте свои варианты использования: можно ли использовать возможную согласованность для изменений отдела / сотрудников (согласятся ли пользователи иногда видеть устаревшую организационную структуру?)

Если да, относитесь к отделу и сотруднику как к отдельным агрегатам. Сделайте справочник сотрудника отделом через его id.

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

Дополнительную информацию по этой теме можно найти в книге IDDD Вона Вернона: https://rads.stackoverflow.com/amzn/click/com/0321834577

person Andrey Koshelev    schedule 20.03.2017

«Агрегат» - это кластер связанных объектов, который мы рассматриваем как единое целое с целью изменения данных ». Эванс. 126

Совокупный корень - это основная сущность, которая содержит ссылки на другие. Это единственный объект в группе, который используется для прямого поиска.

person Ali Borjian    schedule 04.04.2020