Доменно-ориентированное проектирование Эрик Эванс

Когда я занял свою нынешнюю должность в Betsys в качестве разработчика Node.js, я был очень рад начать работать в совершенно новой области, как с точки зрения программирования, поскольку до этого я был разработчиком FE, так и с точки зрения бизнеса, поскольку раньше я работал в программном агентстве, а теперь работаю над продуктом. Было много вещей, которые мне предстояло изучить, например, фреймворк Nest.js, Angular для помощи в разработке FE приложения, шестиугольная архитектура и DDD — Domain-Driven Design.

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

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

Вездесущий язык

Поклонники Филипа К. Дика должны быть заинтригованы, увидев слово ubiquitous или сокращенно Ubik. Но в случае с DDD это не спрей, который обращает вспять регрессию времени и пространства. Вездесущий язык на самом деле является основой DDD. Если все, что вы вынесли из DDD — это вездесущий язык, то вы уже усвоили важный урок.

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

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

Так, в программном проекте разные команды говорят на своем языке, но у них общая цель. Они хотят разработать часть программного обеспечения, и им нужно говорить об этом по разным причинам. Мы также должны понимать, что общение имеет решающее значение. Разработка программного обеспечения — это командная работа (в основном), а основной концепцией командной работы является общение. Ключевым моментом для достижения гладкой и эффективной коммуникации является минимизация двусмысленности и максимизация ясности. Мы все должны быть на одной волне. Поэтому нам нужен общий язык для разговора, письма, документации, моделирования, планирования… нашего проекта.

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

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

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

Практические советы по повсеместному использованию языка

  • поддерживайте актуальный словарь. Это легкая в ведении документация проекта, которая может оказать огромную помощь в принятии новых членов команды.
  • Обсуждайте и тщательно анализируйте язык как можно чаще — так вы не только придете к консенсусу, но и заставите всех дважды подумать, как они назовут свою следующую переменную, функцию и т.д.

Изолирование области

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

Понятно, что DDD должен сосредоточиться на домене. Это одно. Но при разработке приложения нам приходится иметь дело не только с доменом. Нам нужно что-то показать пользователю, нужно где-то хранить данные и т.д. Довольно часто в ООП-программах домен распределен по всему проекту. Есть часть в пользовательском интерфейсе, часть в контроллере и часть прямо в том месте, где мы запрашиваем нашу базу данных. В масштабе это приносит много проблем. Становится трудно отследить трассировку, и мы можем легко изменить бизнес-логику при исправлении некоторых проблем пользовательского интерфейса. Подобно тому, как если мы хотим достать что-то из ящика, все в нем неизбежно и неконтролируемо перемещается.

Решение, предлагаемое DDD, и необходимое условие для применения принципов DDD — это разделение проблем. Самое главное — изолировать область от остальной части приложения. Разделение проблем может быть довольно сложным, но обычно это делается путем создания слоев. DDD требует практически всего двух слоев — слой домена и слой всего остального, но это было бы не совсем правильно. Поэтому вместо такого упрощенного решения DDD поощряет как минимум 4-слойную структуру. Этими слоями являются: слой пользовательского интерфейса, слой приложений, слой домена, слой инфраструктуры.

Слой Описание
Пользовательский интерфейс (или презентационный слой) Отвечает за отображение информации для пользователя и интерпретацию его команд. Иногда внешним действующим лицом может быть не пользователь, а другая компьютерная система.
Прикладной уровень Определяет задачи, которые должно выполнять программное обеспечение, и направляет выразительные объекты домена на решение проблем. Задачи, за которые отвечает этот уровень, важны для бизнеса или необходимы для взаимодействия с прикладными уровнями других систем. Этот слой является тонким. Он не содержит бизнес-правил или знаний, а только координирует задачи и делегирует работу совместной работе доменных объектов на следующем уровне вниз. Он не имеет состояния, отражающего бизнес-ситуацию, но может иметь состояние, отражающее ход выполнения задачи для пользователя или программы.
Слой домена (или слой модели) Отвечает за представление концепций бизнеса, информации о бизнес-ситуации и бизнес-правил. Состояние, отражающее бизнес-ситуацию, контролируется и используется здесь, хотя технические детали его хранения передаются инфраструктуре. Этот уровень является сердцем программного обеспечения для бизнеса.
Инфраструктурный уровень Предоставляет общие технические возможности, которые поддерживают более высокие уровни: отправка сообщений для приложения, сохранение данных для домена, рисование виджетов для пользовательского интерфейса и так далее. Инфраструктурный уровень может также поддерживать модель взаимодействия между четырьмя уровнями через архитектурную структуру.

Эванс, Э. (2004) Проектирование, управляемое доменом. стр. 70

DDD действительно требует только одного изолированного слоя, которым является слой домена.

Доменный слой» — это проявление модели домена и всех непосредственно связанных с ней элементов проектирования.

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

Выражение доменной модели в программном обеспечении

Сущность

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

Уникальность сущности не должна зависеть только от ее атрибутов. В одном здании могут жить два клиента с одинаковыми именами. Существуют тысячи автомобилей Toyota Corollas, но они не одинаковы. У каждой из них есть какой-то идентификатор, позволяющий отличить их друг от друга. Возможно, это VIN-номер. Аналогично этому, сущности имеют идентификатор (или другой уникальный атрибут, отпечаток пальца).

Чтобы система не допускала ошибок, нам нужно сопоставлять сущности преимущественно по этим отпечаткам пальцев. Создание таких идентификаторов, сохраняющихся во времени и даже в распределенных или смешанных системах, — дело тонкое. Тем не менее, задачей DDD является идентификация уникальных сущностей.

Ценностный объект

Многие объекты не имеют концептуальной идентичности. Эти объекты описывают некоторую характеристику вещи. У них не просто отсутствует идентичность, у них есть значение, которое может быть использовано независимо от его применения. Например, цифра 7 не нуждается в идентификации, потому что она не уникальна. Вы можете использовать ее в «17» или «57», и нам все равно, какой экземпляр цифры 7 вы использовали.

Другой пример — ребенок рисует картину мелками. Если ребенок хочет использовать желтый карандаш, чтобы нарисовать солнце, а на столе лежат 3 желтых карандаша, ребенку все равно, какой из них он использует. Его идентичность не имеет значения. Но если карандаш является предметом хранения в магазине художественных принадлежностей, мы можем захотеть каким-то образом идентифицировать его.

Является ли объект VO или сущностью — это предмет для обсуждения и зависит от контекста. Когда мы разрабатываем модель, мы должны спросить себя, нужно ли нам, чтобы этот объект отличался от других? Если ответ «Да», то это сущность, и наоборот.

Сущность может состоять из VO. VO могут быть, поскольку они не являются уникальными, повторно используемыми или общими для сущностей. Например, если у двух людей одинаковые имена, нам не нужно создавать второго «Джона», мы можем повторно использовать первого. Но для обеспечения безопасности VO должны быть неизменяемыми. Поэтому для изменения значения нужно использовать другой VO, а не изменять значение исходного. Если Джон изменит свое имя на Кларенс, мы не должны менять содержимое VO «Джон», мы должны использовать VO «Кларенс».

Объект значения может давать информацию о сущности. Он должен быть концептуально цельным.

Сервисы

В ООП разработчики подгоняют все из домена под объекты — атрибуты и функциональные возможности. Те же разработчики часто натыкаются на функциональность, которую они не могут правильно приписать к объекту, потому что она может подходить к нескольким объектам или вообще не подходить. Такие функциональные возможности в DDD называются сервисами. Они не зависят от сущностей и виртуальных объектов. Мы держим сервисы отдельно, чтобы не искажать концептуальность сущностей и VO, и они не хранят состояния.

Сервисы также называются операциями. Каждая операция должна выполнять одну функциональность, ее название должно происходить из языка Ubiquitous. Параметры и результаты операции должны быть объектами домена.


Если вы не являетесь поклонником ООП, вы можете сделать шаг вперед и отделить всю функциональность от доменных объектов. Имейте в виду, что эта статья посвящена книге Эрика Эванса, но DDD не является исключительной частью ООП, как может показаться в этой книге. На самом деле DDD хорошо сочетается с функциональным программированием и его композиционным принципом. Вы можете узнать больше об этом из видео Скотта Влашина. И не стесняйтесь выбирать между этими двумя парадигмами, на самом деле в нашей компании мы смешиваем концепции из обеих парадигм, и в результате получаем отличный опыт разработчиков.


Заключение

Эта книга может предложить еще много интересного: как проводить рефакторинг для более глубокого понимания домена, практические примеры, использование DDD в крупномасштабных приложениях… Я лишь хотел предложить вам краткое изложение основных концепций, но я настоятельно рекомендую вам изучить книгу самостоятельно.

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