Модельно-ориентированный на домен - давайте взглянем

Доменно-ориентированный дизайн - обширная тема, и иногда ее сложно осмыслить.

В этом посте я попытаюсь упростить ситуацию, перейдя от модели, управляемой к предметной области, и сосредоточусь на мотивации. Мне нравится думать, что сущность DDD - это свободная связь и деловой язык.

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

Начнем с модели-ориентированного и того, что мы под этим подразумеваем. Мы также обсудим, почему проекты становятся модельными.

Следует отметить важное различие: модели-ориентированные не следует путать с Low-Code. Платформы Low-Code основаны на моделях предметной области для автоматического создания кода и конечных точек. Хотя они тесно связаны, вы можете спроектировать систему с DDD, используя платформы Low-Code. Основное отличие состоит в том, используете ли вы модели в качестве инструментов или основы для архитектуры.

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

Итак, это те поля, которые нам потребуются;

  • Номер транспортного средства
  • VehicleCallSign
  • Тип транспортного средства: SmallCar, LargeCar, PeopleCarrier…
  • DriverName
  • Статус верности: наше, Конкуренция, неизвестно
  • ReadyForService: если автомобиль может обслуживать клиентов
  • MaxRange: максимальная дальность полета автомобиля или водителя, желающего ехать.
  • FuelPercent: процент топлива в баке.
  • LastLocation: последнее сообщенное местоположение.
  • LastConfirmedLocation: последнее подтвержденное местоположение.

В качестве следующего шага мы создадим нашу модель и напишем для нее код.

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

И довольно скоро приходит наше первое требование ...

Очевидно, в этом есть смысл. Первое, что приходит в голову, это то, что мы должны справиться с этим при обновлении имени драйвера. Это довольно просто. Но мы также должны учитывать это правило при просмотре или обновлении информации о готовности. Если драйвер не установлен, мы не сможем установить или увидеть готовность как True. Новая ситуация становится такой;

Нам пришлось изменить функции Driver и Readiness. Кроме того, поля DriverName и ReadyForService стали связаны с ними обоими.

Затем приходит второе требование ...

Опять же, в этом есть смысл. Не всегда возможно узнать имя водителя транспортного средства участника. Однако это не значит, что он не обслуживает клиентов.

Он похож на первый, и мы проделываем те же шаги.

Нам пришлось добавить дополнительные условия в функции Driver и Readiness. Кроме того, помимо полей DriverName и ReadyForService, нам также пришлось использовать поле AllegianceStatus.

На этом этапе что-то кажется неправильным, но прежде чем мы сможем об этом подумать, приходит третье требование.

Мы уже через это проходили и знаем, что делать. Рисуем линии…

В этот момент что-то определенно кажется неправильным.

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

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

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

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

Для расчета готовности нам не нужны все поля модели автомобиля. На самом деле, нам тоже не нужны сами ценности. Например, нам не нужно знать имя водителя, только если он назначен или нет. Нам не нужно знать Allegiance, только если автомобиль принадлежит нам.

В ходе этого анализа мы обнаружили кое-что новое. Мы ошибались в отношении ReadyForService. Мы думали, что это окончательное состояние, которое можно обновить как да или нет. На самом деле это было условие обертки. Это значило;

  • При соблюдении всех остальных требований автомобиль может служить.
  • Даже при соблюдении других требований машина не может служить.

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

Все требования и бизнес-логика теперь собраны в одном месте; Калькулятор готовности. Если появится другое требование, мы, вероятно, собираемся изменить только здесь.

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

А теперь давайте сделаем шаг назад и подумаем о том, что произошло в первую очередь. Мы начали с модели, и эта модель определяла нашу архитектуру. Все остальные решения, которые мы принимали, основывались на исходной модели. Так что, возможно, возникает вопрос, почему мы начали с этой модели?

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

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

Итак, когда мы разговариваем с представителями клиентов и спрашиваем их;

«Вы упомянули автомобили, что это такое?»

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

«В контексте конкурентоспособности, как вы собираетесь уведомлять водителей о возможных местах, которые могут быть полезны, и как вы собираетесь анализировать эффективность рекомендаций?»

Они не знают ... Выяснение этого - часть проекта. Это не работа разработчиков, но это часть проекта.

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

«Это все, что у нас есть на данный момент. По крайней мере, вы можете начать с моделирования БД. Мы должны показать что-то заказчику, чтобы мы могли попробовать что-то и поработать над остальными требованиями ».

И вот как это начинается ...

Все очень естественно. Итак, что мы можем с этим поделать? На данный момент DDD дает рекомендацию. Он просто рекомендует;

«Не спрашивайте, что такое Х. Спросите, что происходит. Спросите о событиях ».

В нашем примере мы могли бы спросить;

"Какие события влияют на работоспособность автомобиля?"

Ответы наверняка будут неполными или неточными. Но это нормально. Мы вместе разбираемся. В конце концов, это Agile :)

Но ответы помогли бы нам понять на более раннем этапе, что Готовность - это отдельная вещь. У него есть собственный ограниченный контекст. И события, а не модели, двигали нашей архитектурой.

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

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

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

Еще один очень полезный тест, который я могу порекомендовать, - это: Можете ли вы поэкспериментировать с этим?

Сравните первый дизайн и второй дизайн. Можете ли вы поэкспериментировать с первым? Попробовать, а потом забрать обратно? Не совсем. По мере того, как проект становится больше, он может стать в геометрической прогрессии сложнее. С другой стороны, второй дизайн дает нам много игрового пространства.

Если вы не можете экспериментировать с этим, вы не можете быть Agile.

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

Еще несколько моментов о модельно-ориентированном подходе.

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

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

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

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

Модельно-ориентированные проекты обычно начинаются очень быстро. Добавить код на более ранних этапах очень просто. Но по мере того, как проект становится больше и требования накапливаются, он останавливается.

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

Рефакторинг помогает, но становится ужасным.

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

Существует подход под названием Agile Model Driven Development (AMDD). Он пытается исправить проблемы, о которых мы упоминали, но я по-прежнему считаю, что моделирование - это не правильный ответ для настройки Agile.

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

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