Глава 14. Где проходят границы сервисов?

Главный вопрос: как модель данных определяет, какой сервис управляет каким знанием, и почему это разделение не является произвольным решением архитектора?

14.1. Разговор, который не состоялся

Представим совещание. Архитектор представляет проект новой PLM-системы. На экране — диаграмма сервисов. Product Service. Document Service. Workflow Service. User Service. Notification Service.

Кто-то спрашивает: «Почему именно так? Почему Product Service управляет и конструкцией, и технологией, и производством?»

Архитектор отвечает: «Потому что всё это относится к продукту».

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

Все трое работают с одним объектом. Но каждый из них заблокирован действиями другого. Потому что сервис один. И объект один. И изменение в одной области формально затрагивает все остальные.

Совещание, которое должно было состояться, не состоялось. Никто не задал главный вопрос: где проходят границы ответственности?

14.2. Как человек разделяет инженерную работу

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

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

Каждая область имеет собственные данные, собственные правила и собственную ответственность.

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

Один объект проходит через все эти области. Но знание об объекте в каждой области различно. Следовательно, возникает принцип:

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

14.3. Почему функциональное разделение не работает

Классический подход к проектированию сервисов основан на функциях. Документ-сервис управляет документами. Workflow-сервис управляет процессами согласования. User-сервис управляет пользователями.

Для простых бизнес-систем это работает. Заказ принадлежит системе заказов. Счёт принадлежит финансовой системе. Каждый объект имеет одного владельца. В инженерной системе ситуация иная.

Изделие одновременно имеет конструкторское описание, технологическое описание, производственное описание, эксплуатационные данные и множество других аспектов.

Если создать один Product Service и поместить туда всё, сервис становится владельцем всей информации об изделии.

Product Service
    |
    +-- design data
    +-- technology data
    +-- manufacturing data
    +-- service data

Теперь любое изменение проходит через один сервис. Любая область зависит от всех остальных. Сервис постепенно превращается в монолит, даже если технически он называется микросервисом.

Проблема не в размере кода. Проблема в модели ответственности.

14.4. Разделение должно проходить по знаниям

Вместо этого модель должна разделять разные описания объекта.

KProduct
    |
    +-- KDesignDefinition
    |
    +-- KTechnologyDefinition
    |
    +-- KManufacturingDefinition

Здесь изделие одно. Но его описания различны.

Конструкторское описание принадлежит области конструирования. Технологическое описание принадлежит области технологии. Производственное описание принадлежит области производства.

Это позволяет построить соответствующие границы сервисов:

                 KObject Registry
                       |
                  KProduct: 12345
                 /        |        \
                /         |         \
               ↓          ↓          ↓
       Design Service  Technology  Manufacturing
             |           Service       Service
             ↓             ↓             ↓
     KDesignDefinition  KTechnology   KManufacturing
                        Definition      Definition

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

Здесь важно сформулировать принцип точнее.

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

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

14.5. Почему объект не принадлежит сервису

Здесь необходимо провести важное различие.

В классической архитектуре сервис обычно является владельцем своего объекта. Product Service владеет Product. Document Service владеет Document. User Service владеет User. Для инженерной платформы этого недостаточно.

Изделие не принадлежит Design Service. Оно не принадлежит Technology Service. Оно не принадлежит Manufacturing Service. Оно существует независимо от всех этих областей.

Следовательно, нужен отдельный объектный слой — единый реестр объектов.

KObject Registry
       |
       +-- KObject: 12345
               |
               +-- Design Service
               |      KDesignDefinition
               |
               +-- Technology Service
               |      KTechnologyDefinition
               |
               +-- Manufacturing Service
                      KManufacturingDefinition

Реестр отвечает за существование объекта и его общий идентификатор. Специализированные сервисы хранят и управляют своими описаниями этого объекта. Это принципиально отличается от ситуации, когда Product Service является владельцем всей информации о продукте. Общая схема выглядит так:

Object Registry
       │
       ├── Design
       ├── Context
       ├── Relation
       └── ...

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

14.6. Почему нельзя просто разделить по таблицам

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

Но это не решает проблему.

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

Неправильно:

Product
    design_data     (таблица 1)
    technology_data (таблица 2)
    manufacturing_data (таблица 3)

Правильно:

KProduct
    |
    +-- KDesignDefinition
    |
    +-- KTechnologyDefinition
    |
    +-- KManufacturingDefinition

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

Разница фундаментальна.

14.7. Что происходит при изменении

Рассмотрим простое изменение.

Конструктор изменяет материал корпуса насоса. В модели, где всё находится внутри Product Service, система видит изменение Product.

Но что именно изменилось?

Изменилась конструкция? Технология? Производство? Эксплуатация? Ответ приходится восстанавливать из бизнес-правил.

В объектной модели изменение локализовано:

KProduct: Насос Н1
    KDesignDefinition:
        Revision A → Revision B
    KTechnologyDefinition:
        Revision A
    KManufacturingDefinition:
        Revision A

Система фиксирует: изменилось конструкторское описание. Технологическое описание не изменилось. Производственное описание не изменилось. Объект остался тем же.

Изменение имеет собственную границу и собственную ответственность.

14.8. Общий объект не означает общую ответственность

Здесь возникает важный архитектурный принцип.

Все сервисы работают с одним объектом, но это не означает, что они должны совместно владеть его данными.

Они используют один идентификатор объекта:

KObject: 12345

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

Design Service
    KObject 12345
        └── KDesignDefinition

Technology Service
    KObject 12345
        └── KTechnologyDefinition

Manufacturing Service
    KObject 12345
        └── KManufacturingDefinition

Поэтому сервисы не должны копировать сам объект как новую сущность. Они сохраняют у себя ссылку на зарегистрированный объект. Реестр создаёт объект и выдаёт его идентификатор. Специализированный сервис использует этот идентификатор при сохранении своего описания.

Получается разделение:

              Общий объектный слой
                      │
                 KObject 12345
                /       |       \
               /        |        \
              ↓         ↓         ↓
          Design    Technology  Manufacturing
          Service     Service      Service

Объект один. Владение знаниями разделено.

14.9. Почему это важно для микросервисов

Микросервисная архитектура предполагает независимость сервисов. Но независимость невозможна, если несколько сервисов являются владельцами одной и той же сущности.

Если Design Service должен изменять Product, Technology Service должен изменять тот же Product, а Manufacturing Service должен изменять тот же Product, то независимость становится формальной.

Сервисы начинают конкурировать за один объект. Любое изменение требует согласования. Любая транзакция пересекает границы сервисов. Любое изменение схемы одного сервиса затрагивает остальные.

Получается распределённый монолит.

В модели, где объект отделён от его описаний, ситуация иная. Реестр отвечает за общий объектный слой. Каждый специализированный сервис отвечает за собственную область знания.

Изменение внутри одного описания не требует изменения других описаний.

14.10. Взаимодействие между сервисами

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

Например, Design Service завершил новую ревизию конструкторского описания. Он публикует событие:

DesignDefinitionRevisionCreated
    objectId: 12345
    definitionId: 67890
    revision: B

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

Но решение принимает каждый сервис в своей области.

Design Service не изменяет технологическое описание напрямую. Technology Service не изменяет конструкторское описание. Производство не изменяет конструкцию.

Событие сообщает о факте. Ответственность остаётся внутри соответствующей области.

14.11. Почему это предотвращает ошибки

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

Конструктор не может изменить технологическое описание. Не потому, что интерфейс запрещает. А потому, что Technology Service не предоставляет такого API. Конструктор управляет KDesignDefinition. Технолог управляет KTechnologyDefinition. Граница заложена в модели.

Производство не может выпустить изделие без необходимого конструкторского описания. Не потому, что интерфейс показывает красное сообщение. А потому, что Manufacturing Service требует ссылку на соответствующее KDesignDefinition. Если описания нет, необходимое состояние не может быть сформировано.

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

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

Каждый работает в своей области.

14.12. Что говорят стандарты

Стандарт ANSI/EIA-649-D Configuration Management Standard устанавливает необходимость чётко определённых обязанностей и полномочий и связывает границы процессов с естественными разделениями инженерной деятельности.

NASA Systems Engineering Handbook также рассматривает распределение ответственности между инженерными дисциплинами как часть организации управления конфигурацией.

MIL-HDBK-61A аналогично разделяет функции и ответственность между различными областями управления конфигурацией.

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

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

В терминах Domain-Driven Design это соответствует принципу Bounded Context: каждый ограниченный контекст имеет свою модель, свой язык и свои правила. Конструкторское и технологическое описания — разные контексты. Попытка объединить их в один сервис приводит к семантическим конфликтам и потере автономии.

Международные стандарты PLM и продуктовых данных дают дополнительные подтверждения. ISO 10303-239 разделяет продукт и различные виды его определения и контекста. NATO Product Data Model также отделяет сам продукт от информации, описывающей его в различных аспектах.

ЕСКД использует тот же принцип на другом уровне: электронная модель изделия, электронная структура изделия, конструкторские и эксплуатационные документы являются различными сущностями, выполняющими разные функции в жизненном цикле изделия.

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

14.13. Граница: модель определяет границы, но не реализацию

Было бы неверно утверждать, что модель данных определяет всё.

Она определяет:

  • какие объекты существуют;
  • как они связаны;
  • кто за них отвечает;
  • где проходят границы ответственности.

Но она не определяет:

  • какой язык программирования использует сервис;
  • какую базу данных хранит внутри;
  • какой протокол взаимодействия;
  • какой механизм кэширования;
  • как реализован интерфейс.

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

Границы остаются теми же. Модель остаётся той же.

14.14. Связь с предыдущими главами

Глава 12 установила: связи между объектами являются самостоятельными сущностями. Глава 13 установила: модель данных определяет архитектуру системы. Единый реестр обеспечивает общий объектный слой. Событийная модель обеспечивает независимость сервисов. Глава 14 добавляет: граница ответственности сервиса должна следовать из различий в знаниях, правилах и жизненном цикле данных, которые он обслуживает.

Вместе эти главы формируют полную картину архитектуры.

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

Разделение по областям знания отражает реальную структуру инженерной деятельности.

14.15. Главный вывод

Границы сервисов не являются произвольным решением архитектора. Они следуют из модели данных.

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

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

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

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

Object Registry
       │
       ├── Design
       ├── Context
       ├── Relation
       └── ...

Функциональное разделение — Product Service, Document Service, Workflow Service, User Service — не решает проблему PLM, если оно приводит к тому, что один сервис становится владельцем всех аспектов изделия.

Разделение по областям знания — Design Service, Technology Service, Manufacturing Service — отражает реальную структуру инженерной деятельности. Это разделение не является усложнением. Оно является отражением того, как устроено предприятие.

Конструктор знает конструкцию. Технолог знает технологию. Производство знает производственный процесс. Каждый управляет своим знанием.

Модель данных фиксирует это разделение. Архитектура системы следует из него.

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

Примечания к главе 14

Источники:

  • ANSI/EIA-649-D, Configuration Management Standard, SAE International, 2019. §2.2.
  • NASA/SP-2016-610, Rev. 2, NASA Systems Engineering Handbook, NASA, 2016. §2.2.
  • MIL-HDBK-61A, Configuration Management Guidance, U.S. Department of Defense, 2001. §2.1.
  • ISO 10303-239, Industrial automation systems and integration — Product data representation and exchange — Part 239: Application protocol: Product life cycle support.
  • NATO CALS Office, NPDM Version 4.10 — NATO Product Data Model, STANAG 4613 / ALP-14.
  • ГОСТ 2.102-68. Единая система конструкторской документации. Виды и комплектность конструкторских документов.
  • ГОСТ 2.601-2019. Единая система конструкторской документации. Эксплуатационные документы.
  • ГОСТ Р 2.005-2023. Единая система конструкторской документации. Термины и определения.
  • ГОСТ Р 2.052-2024. Единая система конструкторской документации. Электронная модель изделия. Общие положения.
  • ГОСТ Р 2.053-2023. Единая система конструкторской документации. Электронная структура изделия. Общие положения.
  • ГОСТ Р 2.051-2023. Единая система конструкторской документации. Электронная конструкторская документация. Основные положения.
  • Evans, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley, 2003. Ch. 14 (Bounded Contexts).

Типы доказательств:

УтверждениеТипИсточник
Границы процессов отражают естественные разделения инженерной деятельностиПНУEIA-649-D §2.2
Обязанности CM назначаются по инженерным дисциплинамПНУNASA Systems Engineering Handbook §2.2
Функции CM не должны размывать дисциплинарные границыПНУMIL-HDBK-61A §2.1
product_definition связан с product_definition_contextПНУISO 10303-239
product представляет объект, а информация о нём вынесена отдельноПНУNPDM
Электронная модель изделия является самостоятельной сущностьюТОГОСТ Р 2.052-2024
Электронная структура изделия включает компоненты и связиТОГОСТ Р 2.053-2023
Разделение сервисов по областям знанияСССовокупность источников
Единый реестр является общим объектным слоемЛВААрхитектурный вывод книги
Сервис управляет отдельным описанием объектаЛВААрхитектурный вывод книги
Объект не принадлежит специализированному сервисуЛВААрхитектурный вывод книги
Границы ответственности сервисов должны следовать из различий в знаниях, правилах и жизненном цикле данныхЛВААрхитектурный принцип книги