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

Решение — подход DDD, Domain Driven Design, было предложено Эриком Эвансом в 2003. Но прежде, чем о нем говорить, необходимо немного углубиться в историю развития разработки софта как такового.

Долгое время основным способом проектирования софта был процедурный подход, включающий описание структур данных и алгоритмов обработки этих данных. Классическая книга — Николас Вирт «Алгоритмы + структуры данных = Программы» — была написана в 1976. Если мы сравним содержание книги Вирта со многими современными постановками, то увидим, что добавились лишь описания экранных форм. Однако, это не позволяло эффективно писать сложные системы, множество разрозненных процедур плохо поддавалось пониманию и управлению.

Решение дали объектные языки программирования, начиная с C++, который на рубеже 1980-х дал первую эффективную реализацию Объектно-ориентированного программирования, ООП. Уменьшение сложности достигается за счет инкапсуляции в объекты структур данных и связанных с ними алгоритмов обработки, с методами наследования и полиморфизма объектов, и это в целом структурирует системы: мы отдельно рассматриваем устройство каждого объекта и взаимодействие между разными объектами.

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

Итак, в начале нулевых основным способом, которым разработчики описывали устройство софта, был язык объектов, инкапсулирующих данные и бизнес-логику. Таким образом, получалось две модели: модель предметной области, обычно в виде бизнес-процессов, с которой работал бизнес-аналитик, и модель устройства системы через формализм объектов, которую создавал разработчик или системный аналитик, а сопряжение между ними были требования и модели интерфейсов. Подробнее это было рассмотрено в предыдущей статье «Какие нужны требования: развитие концепта».

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

DDD предложил так же, через объекты, описывать предметную область, а затем прозрачно отражать объекты предметной области в код. Это был следующий шаг по отношению к рекомендованному на этапе анализа составлению словаря предметной области: мы говорим, что у нас теперь будет не просто словарь понятий, а набор объектов со своими атрибутами и методами. И язык этих объектов будут понимать все участники проекта: заказчики, разработчики, аналитики, пользователи, менеджеры. Именно названия объектов и атрибутов из этого языка будут отражаться на интерфейсах системы. Этот язык, создаваемый для каждого проекта, DDD назвал ubiquitous language, в русском переводе — единым языком.

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

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

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

DDD сместил фокус от требований, описания системы как черного ящика, к описанию ее как прозрачного ящика в модели на едином языке

Еще одно важное изменение, которое принес DDD, — признание, что единую непротиворечивую модель предметной области построить невозможно, а значит и не стоит браться за эту задачу. Ведь это получается антипаттерн Big Object, когда всю логику пробуют реализовать в одном объекте. Вместо этого предложено предметную область делить на ограниченные контексты, в рамках каждого из которых строить свою модель, сопрягая их теми же способами, которыми в объектном подходе сопрягаются разные системы или фрагменты системы: через выделение общего ядра с наследованием, создание специальных прослоек-переводчиков или иным образом.

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

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

Правда, сейчас есть сложность с современной архитектурой, в которой системы реализуют активные сервисы, асинхронно взаимодействующие через очереди. Классические объекты с обработкой через вызовы методов плохо отражают такую архитектуру, ик требуются другие методы представления устройства софта, понятные бизнесу. Такой модели посвящена моя серия докладов «Акторная модель». Активные сервисы представляются гномиками, работающими и взаимодействующими для обработки запросов к системе. Для иллюстрации — схема интернет-магазина в таком представлении.

На этом я завершаю статью, посвященную моделям. Продолжение следует…

Комментарии (12)


  1. GraDea
    21.12.2022 12:49
    +5

    Макс, мне кажется, что такое описание ubiquitous language может сбить с толку.

    Единый язык создается не для проекта, а для контекста. И в каждом контексте слово «заказ» будет обозначать что-то свое.

    Если брать пример из активити диаграммы, там может быть пяток контекстов (магазин, разные менеджеры). При этом везде будет заказ, но со своими атрибутами, со своим бизнес-процессом. И уход от единой универсальной модели Заказа и есть избежание антипаттерна GodObject.


    1. MaximTsepkov Автор
      22.12.2022 10:38

      У Эванса в книге язык создавался для проекта. Правда, там язык появлялся сразу, а концепция контекстов - довольно далеко. Но, я с ним согласен, потому что есть тезис: все члены проекта общаются на одном едином языке, это важно. Если проект включает несколько контекстов - значит язык их должен как-то включать все вместе. И если речь везде идет о Заказе покупателя - то там один Заказ. А если у нас есть Заказ покупателя в интернет-магазин и Заказ на доставку в транспортную компанию, то слово Заказ становится запрещенным, надо пояснять. Причина, почему язык один в том, что люди с громадным трудом переключаются между языками в ходе одной коммуникации. Путаница будет, не будут выдерживать. А то, что в разных контекстах для заказа покупателя могут быть важны важны разные атрибуты - понятно.


      1. GraDea
        22.12.2022 14:12
        +1

        Сорри, за -1, мисклик(

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


  1. Ykkks
    21.12.2022 22:51

    Я так и не понял — что такое модель, и чем она отличается от требований...


    1. MaximTsepkov Автор
      22.12.2022 10:39

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


      1. Ykkks
        22.12.2022 14:24

        "Если для идентификации и аутентификации пользователя выбрано решение "пара логин/пароль", система должна предоставлять пользователю возможность восстановления забытого пароля" -- это описание системы как черного ящика, или устройства системы? Или её работы? Это требование или модель? Или это производное требование, появляющееся в результате выбора конструкции?

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


  1. F123456
    22.12.2022 10:39

    Вырезка из учебника по алгебре.

    Алгебраической системой <A;WF;WR> называется объект, состоящий из трёх множеств: непустого множества A, множества алгебраических операций WF, определёных на A, и множества отношений WR, определёных на A. Множество A называется носителем алгебраической системы. Если алгебраическая система не содержит операций, она называется моделью, если не содержит отношений, то – алгеброй.


    1. MaximTsepkov Автор
      22.12.2022 10:42

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


  1. olegkusov
    22.12.2022 10:42

    Кажется что тема не раскрыта совсем. Не до конца понятно зачем нужны ограниченные контексты и как общий язык меняется в этих контекстах. Упомянул модель акторов:

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

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


    1. MaximTsepkov Автор
      22.12.2022 10:56

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

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

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

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


      1. olegkusov
        22.12.2022 15:07

        Спасибо за развернутый ответ


  1. beskov
    24.12.2022 11:49

    «Таким образом, получалось две модели: модель предметной области, обычно в виде бизнес-процессов, с которой работал бизнес-аналитик»

    Модель предметной области всегда была прежде всего онтологической моделью, сначала — ER-диаграммой (смотри методологию SADT 70-х годов и моду на ERWin в 90-х), потом — UML Class (см RUP и OOA).

    Модель предметной области обычно фиксирует общее устройство реальности в отрасли (статическая модель отношений явлений и бизнес-объектов), а не в конкретной компании — в этом её сила для повторного использования (см Analysis Patterns Фаулера) и в этом же её слабость (см неуспех той же книжки).

    Модель процессов обычно описывает устройство процессов в конкретной компании, а не в отрасли, т.к. считается, что они сильно изменчивы от компании к компании, хотя и есть инициативы типы APQC Reference Model, но они видимо известны только бизнес-архитекторам (https://www.apqc.org/resource-library/resource-listing/apqc-process-classification-framework-pcf-cross-industry-excel-10)

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

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

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

    И в целом побеждали и победили смешанные неформальные модели деятельности с объектами swimlane flowchart, откуда вылез и закрепился успех BPMN (а теперь глядишь и Event Storming).