Ubiquitous Language и Bounded Context в DDD


    Domain-Driven Design: Tackling Complexity in the Heart of Software Эванса — лучшая книга о проектировании действительно больших enterprise-приложений, что я читал. Видимо это мнение разделяют многие другие разработчики и проектировщики, потому что Entity и ValueObject, Repository и Specification встречаются почти в каждой большой кодовой базе. Но вот незадача, Ubiquitous Language (единый язык) и Bounded Context (контекст предметной области) в чужом коде я не видел ни разу. И здесь зарыта очень большая собака.

    Зачем нужен единый язык?


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

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

    Единый язык on
    var ticket = cashdesk.Sale(seat, count); // Это может понять даже не технический специалист
    

    Единый язык off
    ticket.State = TicketState.Sold; // А это нет
    ticketRepository.Update(ticket);
    

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

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

    Заметили как сложно воспринимается предыдущий абзац?

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

    Зачем нужны контексты?


    Проблема №1


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

    Проблема №2


    «Единый язык» на самом деле не является «единым» для всего приложения и живет только в рамках контекста. И Эванс прямо об этом пишет. К сожалению, в книге сей факт формируется мягко, скорее как рекомендация, а не правило. Я бы набрал параграф красным КАПСОМ и поместил в рамку. Попытка создания единой модели предметной области обречена на провал. Один и тот же термин может значить разные вещи в разных контекстах. Я могу сходу назвать несколько примеров из разных предметных областей, но все они требуют специального объяснения, поэтому ограничусь синтетическим примером: салат рекурсивный — помидоры, огурцы, салат. Ну вы поняли…

    Проблема №3


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

    В качестве бонуса


    Bounded Context — это реализация принципа слабой связанности на более высоком уровне — на уровне подсистемы (модуля). Такая сегментация позволит вам более гибко управлять разработкой, вплоть до исключения или переписывания с нуля целых модулей, возможно, что даже с полной заменой команды и/или технологического стека модуля. Если вы игнорируете Bounded Context и расширяете и расширяете вашу модель домена, рано или поздно это закончится тем, что стоимость (как по времени, так и по деньгам) любого изменения системы будет стремиться к бесконечности.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 40
    • +3
      Эванс написал хорошую книжку с хорошими идеями. Но этим идеям не хватает методологической основы. Опытным разработчикам/архитекторам понятно, что надо быть как можно ближе к предметной области заказчика, что с заказчиком надо разговаривать и т.п. Но не понятно как оценить проект на соответствие Ubiquitous Language и реального языка заказчика? Как понять, что вы выбрали верный Bounded Context? Как вообще опредилить используется DDD в проекте или нет? При анализе унаследованного кода, как мы узнаем, что концепции DDD реализованы верно? Было бы отлично, например, сделать соответствие практик рефакторинга и процесса перевода проекта на рельсы DDD.

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

      Могу рекомендовать более свежую книжку www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577
      В ней уже больше практики и приближения к повседневным задачам. Всё это активно обсуждалось в сообществе dddcommunity.org/

      Автору спасибо за статью, тема DDD должна активно обсуждаться и развиваться.
      • +1
        >>тема DDD должна активно обсуждаться и развиваться.
        Александр, а вы почему не принимаете в этом участие на хабре? :-)
      • 0
        как оценить проект на соответствие Ubiquitous Language и реального языка заказчика?
        Интервьюируя представителя клиента в таком стиле: «в программе заложена такая-то логика. Это верно? Вы делаете так?». Обычный ответ: «конечно нет!»)

        Как понять, что вы выбрали верный Bounded Context?
        Обычно тоже в ходе беседы: с представителями разных отделов.обычно где-то обнаруживается четкий водораздел. Здесь есть смежный вопрос: «в какой части системы нам нужен DDD, а где можно использовать методологию хуяк-хуяк и в продакшн», но это тема следующей статьи)

        Как вообще опредилить используется DDD в проекте или нет?
        Приемочные/интеграционные тесты. Не всегда применимо, но если есть какой-то вменяемый API, то должно получиться.
        • 0
          Ок, если мы говорим, что интервью дает нам ответы. Тогда следующий вопрос: Из каких вопросов должно состоять интервью? Есть ли некий чек-лист, пройдя который, мы понимаем: Да, здесь есть DDD (или наоборот).

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

          Я нисколько не пытаюсь принизить DDD, только хочу выяснить на сколько в данный момент выстроена методологическая база.
          • 0
            Чек-листа нет. К сожалению, тут надо включать голову. на эту тему понравился доклад Грега Янга: www.youtube.com/watch?v=KXqrBySgX-s.
            — Поднимите руки те, кто проектирует по DDD (он поднимает руку и еще какое-то количество людей в зале)
            — А теперь те, кто создает объекты, моделирующие предметную область и рассовывает логику по helper'ам и manager'ам и думает, что это DDD
            По залу идет смешок. Я вижу один четкий критерий — является ли ваша модель предметной области поведенческой моделью? Если да, то это DDD. Если нет, то это симулирование DDD.
            • +1
              Максим, мы с вами возможно понимаем это правильно и даже, возможно, понимаем одинаково. Но где гарантия, что все вокруг поняли эти идеи?

              Совет включить голову можно давать на любую проблему. «У меня плохой код», — говорит джуниор — «всё постоянно ломается». Какие варианты помощи? Можно сказать ему «Включи голову», а можно дать книжку по рефакторингу.
              • 0
                На тему получения знаний от носителя есть наука и практика «когитология».
      • +1
        В русскоязычной предметной области проблема общего языка, кстати, удваивается: нужно сначала выбрать общий язык предметной области (на русском), а затем выбрать единый (и желательно адекватный) перевод всего этого языка на английский.

        Иначе получаются монстры, у которых в одном контексте одновременно существует Leaser и Renter.
      • 0
        Надо будет перевести новую статью (или это просто префэйс к новой книге, точно не помню) Дино Эспозито, где он говорит, что подавляющая часть проектов основанных на DDD были за последнюю декаду провалены. Основная причина в том, что DDD — крайне сложный подход, используя который все находятся в перманентной фрустрации по той причине, что ни один принцип DDD удовлетворить не могут, ну и просто потому, что DDD — это сложно. Эспозито говорит, что CQRS более общий подход, который более прост и может подходить для более широкого спектра приложений. И стоит ожидать рост количества проектов, которые строятся на идеях CQRS.

        Что касается Bounded Context. Недавно смотрел курс Pluralsight по DDD и там чёрным по белому было сказано, что такого уровня сегрегации контекстов, особенно, когда они почти идентичны, но не совсем почти ни в каких проектах не встречается — ну не готов никто ради разницы в паре свойств плодить классы.
        • 0
          А можете дать ссылку на курс? Не встречается — не показатель того, что все хорошо. Раздувание модели приводит к тому, что у вас в солюшне 120 проектов и собрать по отдельности ничего нельзя. Bounded Context помогает командам работать независимо. Очень хорошо работает принцип команда UI — заказчик для команды бекенда. Этот вопрос находится на стыке архитектуры и управления проектными командами и именно по этому чаще всего не решается должным образом. Необходимо, чтобы архитектор и пи-эм были на одной волне и обладали смежными знаниями: менеджер был технарем в прошлом, а у архитектора был опыт управления людьми или хотя бы желание понять пи-эма.
          Кроме этого, если у вас есть контексты, ничего не мешает в рамках контекста вообще выкинуть DDD. Мы удачно применили этот принцип на одном из проектов в модуле отчетов. Ну не нужен там DDD. Инфраструктура загрузки модуля у нас общая, а внутри модуля отчетов RDLC и ReportViewer, потому что это решение отлично подходит и не нужен никакой DDD. Вообще фанатизм «все в проекте должно быть одинаково» — очень вредная штука.
        • +1
          Противопоставление DDD и CQRS, скажем так, удивляет. Во-первых, CQRS не подходит для широкого круга приложений (это написано и в майкрософтовской книжке по этому поводу, и у самого Янга), а во-вторых, CQRS как раз лучше всего живет в сочетании с DDD, потому что очень удобно оперировать агрегатами и операциями на них.
        • 0
          Если что, вот новая книга Эспозито, м.б., кого-то заинтересует. Я предложил издательству «Питер» её перевести, но не знаю захотят ли они.
          • 0
            Ну не знаю, первое издание меня совершенно не впечатлило.
            • 0
              Второе издание значительно переработано, так сказал Эспозито, вроде бы.
              • +1
                Так говорил Заратустра Эспозито:)
                • 0
                  Просто я не могу подтвердить, к сожалению))) Ещё само издание не выпущено, как я понял)))
          • –1
            Переводим на русский:

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

            Даже сами определения содержат противоречия, не находите? При этом о проектировании ни слова.

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

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

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

            В таких системах рулит дизайн основанный на "языке области решения" задачи. Утрированный пример — если надо выкопать яму, то НЕ надо делать сущности «земля», «лопата», «рабочий», а потом писать так:
            var лопата = new Лопата(рабочий);
            земля.Копайся(лопата);
            
            Решение такой задачи надо начинать с проектирования экскаватора.

            В итоге «единый язык предметной области» и «ограниченные контексты» — хороший инструмент для анализа, но плохой для проектирования приложений.
            • 0
              Противоречия как такого нет. Вы, видимо, не внимательно читали статью. Я явно указываю на то, что «единым» язык будет только в «ограниченном контексте», а попытки сделать его «общим» для всего приложения приводят к Ахтунгу. А по поводу лопаты у вас явно должно быть иначе:

              class Землекоп: Рабочий
              {
                //...
              }
              var рабочий = new Землекоп(лопата);
              рабочий.Копать(земля);
              


              Иначе
              • –1
                В противном случае «земля» будет нарушать SRP и ISP.
                • –1
                  Довольно странное утверждение, учитывая что вы не знаете интерфейса класса «земля».
                • –1
                  Без разницы, все равно экскаватор не получается.

                  Более реальный пример: вы делаете учетную систему — бухгалтер вам начинает сыпать терминами — баланс, остаток, оборот, «шахматка».
                  Вот вам единый язык, даже контексты не нужны, за пределы бухгалтерии не выходим. Как будет спроектирована такая система? Если понасоздавать сущностей по этому «единому языку», то получится говно. Надо сделать таблицу проводок, тогда все эти балансы, обороты и шахматки станут просто запросами.

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

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

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

                          Эванс говорит как раз о том, что программисты должны не только слова повторять, а понимать суть. Аналитики в этом случае не сильно нужны.
                          • 0
                            А как аналитик узнает что нужно реализовывать, а что нет?

                            Из беседы с представителями заказчика.

                            Если у него нет опыта проектирования, то он сможет только нарисовать эти самые «сущности» в виде схемы и правила по которым они работают.

                            Это как раз и нужно.

                            А потом программисты не включая голову запрограммируют эти сущности в виде классов.

                            Ну так голову-то надо включать. И между аналитиком и программистами еще есть архитектор/тимлид.

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

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

                  Единый язык — это фиксированный словарь предметной области, не содержащий лексической избыточности и/или неоднозначностей. Например, сторона, заключающая договор, всегда называется контрагентом, а не «контрагент, клиент, заказчик, пользователь». Само по себе это не влияет на дизайн (любого уровня) приложения, это просто позволяет всегда точно знать, что именно аналитик, разработчик и тестировщик имеют в виду.

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

                  Иными словами, можно написать полностью процедурное bottom-up приложение из 150 строк, которое ничего не знает не только про DDD, но даже про ООП, и при этом оно будет опираться на единый язык и ограниченный контекст.
                  • 0
                    Чушь полнейшая. Уж простите, вы хоть с реальным бизнесом разговаривали хоть раз? Из недавнего — простая система внутреннего документооборота, есть такая сущность как «стандартный договор». Есть описанный процесс в терминах «стандартного» и «нестандартного» договора. На проверку оказалось что у юристов, бухгалтеров, финансистов и руководства совершенно разное понимание стандартности. Хотя все говорят об одном и том же «стандартном договоре» и все прекрасно, на уровне бизнеса, понимают что это такое.

                    Вот пример bounded context. А одинаковые названия для разных сущностей — это, простите, детский сад, даже выдумывание названия для такой ситуации тратит больше времени, чем её устранение. У Фаулера есть подробное описание — martinfowler.com/bliki/BoundedContext.html

                    На практике же такие вещи встречаются очень часто: возьмем интернет-магазин и «товар». Для покупателя с товаром можно сделать: положить в корзину, посмотреть каталог, сравнить с другим, посмотреть похожие. Для администратора сайта — создать, изменить описание и картинки, назначить скидку. Для менеджера — оприходовать, отгрузить. Это все разное поведение, для этого поведения нужны разные данные, хотя товар один и тот же. Как на основе такого языка предметной области проектировать программу? Никак, вы начнете ввожить сущности «каталог», «управление товарами», «управление заказами», которых нет в предметной области и получите не язык предметной области, а язык решения задачи.
                    • 0
                      Уж простите, вы хоть с реальным бизнесом разговаривали хоть раз?

                      Да.

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

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

                        Бизнесу это объясните, для них товар это одна сущность. Да и в СУБД товар будет в одной таблице. Предметная область такая.

                        Поэтому и существует понятие bounded context, когда сущность одна, а «поведение» — разное.
                        Само это противоречие говорит нам о том, что для проектирования применять «язык предметной области» нельзя. Не получится в программе разные классы или функции назвать одним именем.
                        • 0
                          Бизнесу это объясните, для них товар это одна сущность.

                          Понадобится — объясню.

                          Да и в СУБД товар будет в одной таблице.

                          Тоже не факт.

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

                          Пространства имен уже отменили? У меня одна и та же сущность предметной области имеет в коде сильно больше одного выражения.
                          • 0
                            Ну-ну, объясните человеку, который далек от ИТ, что «товар» и «товар» это не одно и то же.

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

                            Пространства имен создадут разные классы и, например, присвоить один другому нельзя. Будет путаница.

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

                            Поймите простую вещь — сущности предметной области поведением обладают только если у вас задача моделирования. В автоматизации поведением обладают не сущности предметной области, а люди и процессы. Проектировать в этом случае с другой стороны.
                            • 0
                              Вы упускаете тот факт, что я написал "может быть опасным их смешивать". Если это «может» сработало, значит, есть причины.

                              Ну-ну, объясните человеку, который далек от ИТ, что «товар» и «товар» это не одно и то же.

                              На примерах обычно объясняется весьма легко.

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

                              … или наоборот, перестану мучаться с тем, что изменение логики работы склада влияет на БД, с которой работает сайт.

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

                              Это же и прекрасно.

                              Заметьте, вы еще ни строчки не написали, а уже усложнили потенциальный код совершенно без необходимости

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

                              просто пытаясь следовать тому, что написал Эванс.

                              … и Эванс тут совсем не при чем, я просто анализирую предметную область.

                              Поймите простую вещь — сущности предметной области поведением обладают только если у вас задача моделирования.

                              Это зависит от того, что вы понимаете под поведением сущности. Если то, что сущность делает сама — это одно. А если то, что с сущностью можно сделать — это другое.
                          • –2
                            Нет, не будет. Будет Product и OrderedProduct. Потому что иначе у вас «поплывут» цены в архиве заказов при изменении в каталоге, а еще вы не сможете удалять товары, потому что foreign key на заказы.
                            • 0
                              И как связаны Product и OrderedProduct? Обычно есть OrderLine, которая ссылается на Product, а Product он один. Хоть его смотрит покупатель, хоть его отгружает менеджер.
                        • 0
                          Как раз для вас я и описал в статье какую проблему создал «язык решения задачи» в одном из реальных проектов.

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