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

Глубокие системы

Модель данных во многом определяет архитектуру приложения. С простыми CRUD-приложениями вы часто можете принять разговорное предположение «получить объект и отправить». В этом случае будет достаточно любой модели данных, сервисного уровня, управляющего этими данными, и интерфейса API.

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

Модель анемичных данных была определена в 2003 году Мартином Фаулером как антипаттерн. Он подчеркивает, что это не совместимо с объектно-ориентированным программированием, а скорее с процедурным программированием.

«Модель анемичной предметной области на самом деле представляет собой просто дизайн процедурного стиля…»

Но что же это за анемичная штука…?

Примитивная модель

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

Поэтому следует помнить, что нет худших или лучших баз данных, они лучше или хуже используются в том или ином случае.

public class Order {
    private Long orderId;
    private LocalDate orderDate;
    private LocalDate orderShippedDate;
    private String orderStatusCode;
    private int orderTotal;
    private Long customerId;
    private String shipToName;
    private Long shipToAddressId;
    private String shipToPhoneNumber;
    private Long shippingOptionId;
    private Long paymentOptionId;
    // getters and setters
}

Это пример реального кода, используемого в приложении. Есть ли здесь что-то хорошее? Не…

Начнем с основ.

Если вы звоните двум сеттерам подряд, вы упускаете концепцию (Оливер Гирке)

Изучая язык программирования, мы всегда говорим об инкапсуляции. Мы хотим предотвратить изменение данных. Однако, если вы не определяете поведение класса, как вы хотите изменить его состояние? Конечно забыл, у нас есть сеттеры. Зачем они нам, ведь мы можем использовать публичные поля, это ничем не отличается, и нет никакой инкапсуляции в обоих случаях :( Класс может делать что угодно и каждый может манипулировать class (здесь нет инкапсуляции или ограниченной ответственности).

Другая проблема. Чрезмерное обобщение и отсутствие контекста, в котором работает данная область модели.

Поймите, как работает бизнес.

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

ИЗБЕГАЙТЕ обслуживания юридических лиц, сосредоточившись на возможностях

Итак, каковы эффекты анемичной модели?

  • проблема с сопровождением/разработкой приложения, нечеткая логика выходит за пределы предметной области, много зависимостей — большая связанность
  • худшая производительность из-за работы по так называемому золотому классу
  • сложная логика, часто работающая со многими логическими значениями или перечислениями
  • чрезмерное обобщение отсутствие контекста, в котором работает данная область модели
  • класс может делать что угодно и каждый может манипулировать классом
  • нарушение правила Лискова — извлечение объекта с помощью .get().get()
  • Намерение SET неизвестно:

Какое деловое действие здесь происходит — мы не знаем, потому что не назвали его?

И когда я захочу использовать такой метод? Я ничего не путаю?

Узнаю ли я через два месяца, что здесь происходит?

Что, если я забуду установить дополнительные значения?

Сущностью управляет кто-то другой, говорит ей, как жить и что делать, обычно какой-нибудь SuperUtilService, MyFancyExecutionManagerService — такая недееспособность :)

Богатая модель

  • метод выражает свои намерения
  • деловой язык переходит в код
  • объект неизменяем, нет наборов, просто общедоступный метод, который делает все, что должен
  • методы на объектах можно использовать повторно, не опасаясь, что мы дополнительно что-то забыли
  • сущность управляет собой, только она может изменить свое состояние, проверить его и отреагировать — она зрелая и независимая

Философия Domain Driven Design идеально вписывается в концепцию богатого домена. Ниже я хотел бы представить проект на основе DDD:

Проект библиотеки с использованием Domain Driven Design — GitHub

Компоненты богатой модели, такие как:

  • высокая сплоченность
  • ценные объекты
  • ограниченные контексты
  • Мероприятия
  • шестиугольная архитектура
  • пример использования
  • и конечно прагматичный подход

Будет представлено в следующих рассказах. Просто обход анемичной модели позволит вам значительно улучшить качество вашей работы. Оставайтесь рядом с Domain Driven Design.