Как DDD работает для меня

9317deff24f342887b3f360ed675645d.png

Привет! Меня зовут Станислав, я фронтенд-разработчик компании Тинькофф. Занимаюсь разработкой веб-приложений и написал десятки тысяч строк кода, массу велосипедов и костылей, пока не познакомился с разработкой, основанной на модели предметной области, или Domain-Driven Design.

DDD — это система знаний, приемов и методов, предназначенная для создания приложений высокой сложности. DDD обобщает лучшие практики коммерческой разработки программного обеспечения и постоянно совершенствуется, предоставляя разработчику надежную опору для принятия решений. Лучший способ узнать больше — это книга Эрика Эванса Domain-Driven Design: Tackling Complexity in the Heart of Software.

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

Бизнес-логика повсюду

Может показаться, что алгоритм решения предметной проблемы лучше и быстрее имплементировать прямо в месте применения: это может быть UI-компонент, часть инфраструктуры фреймворка, метод обращения к API другой системы.

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

Задачи делаем в разное время, в проекте заняты несколько бэкенд- и фронтенд-разработчиков. 

Если бизнес-правило будет решено в компонентах форм и отдельно в каждом методе бэкенда, мы получим четыре дубликата имплементации бизнес-правила о допустимых телефонных номерах.

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

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

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

b806f80e4134da2a502573fe635f0030.png

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

План такой:

  1. Разделить приложение на логические слои.

  2. Спроектировать слои так, чтобы каждый верхний слой мог зависеть только от нижележащих.

  3. Сосредоточьте весь код бизнес-логики в одном слое.

  4. Изолируйте слой бизнес-логики от остальных слоев.

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

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

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

Нет разделения на контексты

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

Модель, созданная для первого контакта с пользователем «Клиент», кроме телефонного номера, ФИО, адреса и даты создания оказалась очень удобной для агрегации и других данных для работы с этим пользователем. Разработчики снабдили ее списком рекомендаций, историей покупок, управлением бонусами и историей просмотров. 

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

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

a8fc46f763d2d50d90fa3b066d556b64.png

Предметно-ориентированное проектирование предлагает ряд методов для разделения сложной предметной области на поддомены.

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

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

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

Не поддерживается единый язык

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

Например, бизнес-аналитик обсуждает реализацию задачи с новым разработчиком:

— А здесь мы выводим список торговых точек.

— Но у нас нет таких данных.

— Посмотри Shops.

— Нет.

— Markets?

— Нет, вот только какие-то Opportunity Points.

— Да, это то, что нужно!

— ?!

121010950d94b0539ec8d94f6839f773.png

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

Единый язык требует осознанного поддержания участниками разработки, актуализации и рефакторинга. 

e4c7a82439fbc30146d233048a056b5c.png

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

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

Заключение

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

© Habrahabr.ru