ЧАСТЬ III. Как модель становится системой?
Глава 13. Почему модель данных определяет архитектуру?
13.1. Разговор, который обычно начинают не с того места
Представим начало нового проекта PLM-системы.
Архитекторы обсуждают сервисы. Кто-то предлагает Product Service. Кто-то — Document Service. Отдельно Workflow Service, User Service, Notification Service. На доске появляются десятки блоков и стрелок. Обсуждают хранилища. API. Брокер сообщений. Контейнеры.
И только потом возникает вопрос: А что именно каждый из этих сервисов должен знать об объекте? Это кажется техническим вопросом. Но на самом деле он относится к модели данных.
Если один объект имеет несколько независимых описаний, значит, эти описания не обязаны находиться в одном месте. Если конструкция изделия, технология изготовления и производственное состояние являются разными областями знания, значит, система должна иметь возможность разделить ответственность за это знание.
Архитектура не должна сначала придумать границы, а потом искать для них смысл. Границы должны следовать из модели.
13.2. Один объект — много областей знания
Вернёмся к насосу Н1.
Это один инженерный объект. Но о нём существует несколько разных видов знания.
Конструктор знает:
KProduct
конструктивное описание
геометрия
материалы
размеры
состав
Revision
Технолог знает:
KProduct
технологическое описание
операции
оборудование
маршрут
технологические требования
Производство знает:
KProduct
производственное состояние
производственный процесс
фактический выпуск
ограничения производства
Эксплуатационная служба знает:
KProduct
эксплуатационное описание
условия применения
обслуживание
ограничения
Объект один. Знание о нём — разное.
Это различие было установлено в предыдущих главах. Один объект может иметь несколько независимых описаний. Теперь необходимо сделать следующий шаг: если описания независимы по смыслу, они должны быть независимы и по ответственности.
13.3. Что происходит, если всё положить в один сервис
Представим систему, в которой существует один Product Service.
Он хранит всё:
Product Service
│
└── Product
├── Construction
├── Technology
├── Manufacturing
├── Operation
├── Documents
├── Workflow
└── ...
На первом этапе это выглядит удобно. Один сервис знает всё о продукте. Но затем начинается реальная работа. Конструктор изменяет материал. Технологу необходимо проверить, влияет ли изменение материала на технологический процесс. Производству необходимо понять, можно ли продолжать выпуск. Эксплуатационной службе нужно проверить новые ограничения.
Изменение одной части объекта начинает затрагивать весь сервис. Появляется сильная связанность. Изменяется конструкция — меняется Product. Меняется Product — должны реагировать технология, производство, эксплуатация.
Каждое изменение становится изменением одного большого объекта. Система начинает отражать не разделение инженерного знания, а техническое решение хранить всё вместе.
13.4. Проблема не в сервисах
Можно попытаться решить проблему противоположным способом. Разделить систему на сервисы:
Product Service
Document Service
Workflow Service
Technology Service
Manufacturing Service
Но это ещё ничего не решает. Если все сервисы продолжают считать, что существует один объект, которым каждый должен управлять целиком, проблема остаётся. Например:
Product Service
владеет Product
Technology Service
тоже изменяет Product
Manufacturing Service
тоже изменяет Product
Возникает вопрос: кто имеет право изменять Product?
Если ответ — все, границы сервисов фиктивны. Если ответ — один, остальные сервисы начинают зависеть от него. Получается распределённая система, в которой каждый сервис зависит от одного центрального владельца объекта.
Сервисы появились. Независимости не появилось.
13.5. Модель данных должна разделять ответственность
Предыдущие главы дали для этого необходимую основу.
Мы уже различаем:
KProduct
│
├── KDesignDefinition
│ └── Revision
│
├── KTechnologyDefinition
│ └── Revision
│
├── KManufacturingDefinition
│ └── Revision
│
└── KOperationalDefinition
└── Revision
Это не просто удобная структура хранения. Каждое описание отвечает на свой вопрос.
Конструкторское описание отвечает: как устроено изделие? Технологическое: как его изготовить? Производственное: как организовано его производство? Эксплуатационное: как его использовать и обслуживать?
Эти вопросы различны. Значит, различна и ответственность за ответы.
13.6. Объект не принадлежит сервису
Здесь возникает важный принцип.
Если несколько сервисов работают с разными описаниями одного объекта, нельзя говорить, что сам объект принадлежит одному из этих сервисов. KProduct не принадлежит Design Service. Не принадлежит Technology Service. Не принадлежит Manufacturing Service. Он является общим объектом системы. Профильные сервисы управляют своими описаниями объекта.
Это принципиальное отличие.
KObject / Product
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
Construction Technology Manufacturing
Definition Definition Definition
│ │ │
▼ ▼ ▼
Design Service Technology Manufacturing
Service Service
Объект является общим. Знание о нём разделено. Именно это позволяет нескольким сервисам работать с одним объектом, не становясь владельцами друг друга.
13.7. Единый реестр объектов
Но возникает другая проблема.
Если каждый сервис хранит свои данные самостоятельно, кто гарантирует, что речь идёт об одном и том же объекте? Представим:
Design Service
Product ID = 12345
Technology Service
Product ID = 12345
Manufacturing Service
Product ID = 12345
Откуда взялся 12345?
Если каждый сервис генерирует идентификаторы самостоятельно, единого объекта больше нет. Получаются три локальных объекта, которые система должна каким-то образом считать одним.
Поэтому необходим фундаментальный механизм — единый реестр объектов. Он отвечает не за конструкцию изделия. Не за технологию. Не за производство. Его задача значительно проще и фундаментальнее: зарегистрировать объект и выдать ему общий идентификатор.
После этого профильный сервис сохраняет собственное представление объекта под выданным идентификатором.
Упрощённо:
Object Registry
│
register()
│
▼
KObject ID=12345
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
Design Technology Manufacturing
Service Service Service
│ │ │
└────── ID=12345 ───────┘
Это не означает, что реестр хранит всю информацию об объекте. Он хранит фундаментальный факт существования объекта и его общий идентификатор. Профильный сервис хранит данные своей области.
Именно поэтому один и тот же объект может быть представлен в нескольких сервисах, оставаясь одним объектом системы.
13.8. Почему идентификатор должен быть общим
Представим изменение конструкции.
Design Service сообщает:
Product 12345
Design Revision B created
Technology Service получает событие:
Product 12345
Design changed
Он не создаёт собственный объект. Он знает: 12345 — тот же объект, который существует и в его области.
Technology Service анализирует изменение и, если необходимо, создаёт новую технологическую Revision. Manufacturing Service получает то же событие и решает, влияет ли изменение конструкции на производство. Никто не передаёт другому сервису весь объект. Передаётся ссылка на один и тот же объект и информация о произошедшем изменении.
Это делает взаимодействие между сервисами значительно слабее.
13.9. Событие вместо прямого управления
Из разделения знания следует ещё один архитектурный принцип.
Если Design Service изменил своё описание, ему не нужно напрямую изменять данные Technology Service. Он фиксирует изменение. Система публикует событие. Например:
ProductDesignChanged
objectId: 12345
revision: B
Technology Service получает событие и принимает собственное решение. Manufacturing Service также получает событие и принимает собственное решение.
Это важно.
Событие сообщает: что произошло. Оно не говорит: что другой сервис обязан сделать внутри себя.
Поэтому каждый сервис сохраняет автономию.
13.10. Почему это возможно только при правильной модели
Если Product представляет собой один огромный объект со всеми областями знания, событие ProductChanged практически бесполезно.
Что именно изменилось? Конструкция? Технология? Производство? Эксплуатация?
Если всё является частью одного объекта, изменение объекта не говорит ничего о том, какая область должна реагировать. Но если модель различает описания:
KProduct
│
├── DesignDefinition
├── TechnologyDefinition
├── ManufacturingDefinition
└── OperationalDefinition
событие становится семантически точным:
DesignDefinitionChanged
или:
TechnologyDefinitionChanged
Получатель понимает, относится ли событие к его области знания. Архитектура становится следствием модели.
13.11. Что происходит с базой данных
Отсюда следует ещё один важный вывод. Единый объект не означает единую базу данных.
Напротив. Каждый сервис может хранить собственные данные:
Design Service
└── Design DB
Technology Service
└── Technology DB
Manufacturing Service
└── Manufacturing DB
Но все они используют общий идентификатор объекта.
KObject ID = 12345
Это позволяет разделить владение данными, не разделяя сам объект. В распределённой системе информация об одном инженерном объекте поэтому физически может находиться в нескольких местах.
Это не дублирование смысла. Это распределённое хранение разных аспектов одного объекта.
13.12. Что означает «один объект в нескольких базах»
Здесь легко допустить ошибку в терминологии.
Если Design Service хранит:
product_id = 12345
geometry = ...
material = ...
а Technology Service:
product_id = 12345
operations = ...
route = ...
это не означает, что каждый сервис имеет собственную копию всего Product. У каждого сервиса находится только тот аспект знания, которым он управляет. Общий идентификатор связывает эти представления.
Object 12345
│
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
Design DB Tech DB Mfg DB
│ │ │
geometry route process
material operations status
Объект один. Представлений его аспектов — несколько.
13.13. Архитектура появляется из модели
Теперь можно вернуться к исходному вопросу. Почему модель данных определяет архитектуру?
Потому что модель уже отвечает на вопросы:
- какие сущности существуют;
- какие из них являются самостоятельными;
- какие описания независимы;
- какие связи имеют собственный смысл;
- кто должен управлять каждым видом знания;
- какие изменения относятся к какой области.
Архитектор не должен придумывать эти границы с нуля. Он должен увидеть их в модели. Если конструкция и технология представлены одной сущностью, архитектура будет стремиться объединить их. Если они представлены разными сущностями, возникает естественная граница ответственности.
В терминах Domain-Driven Design это соответствует принципу Bounded Context: каждый ограниченный контекст имеет свою модель, свой язык и свои правила. Конструкторское и технологическое описания — разные контексты. Попытка объединить их в одну модель приводит к семантическим конфликтам.
Модель не диктует название сервиса. Но она определяет, где есть смысл проводить границу.
13.14. Почему это важнее выбора технологий
Технологические решения часто становятся отправной точкой проектирования. Но архитектура системы — это не сумма выбранных технологий. Можно построить сто сервисов вокруг неправильной модели. Получится сто маленьких сервисов, которые вместе реализуют одну большую ошибку.
И наоборот.
Правильная модель может быть реализована разными технологическими способами.
Модель данных первична. Архитектурный стиль вторичен.
13.15. Почему модель должна появиться раньше сервисов
На практике часто происходит наоборот. Команда начинает с архитектуры:
API Gateway
↓
Product Service
↓
Document Service
↓
Workflow Service
Затем проектирует таблицы. Затем обнаруживает, что один объект используется всеми сервисами. Затем появляются общие таблицы. Затем прямые вызовы между сервисами. Затем распределённые транзакции. Затем согласование данных.
Архитектура начинает бороться сама с собой. Причина появилась намного раньше. Команда начала проектировать систему до того, как определила модель. Правильная последовательность выглядит иначе:
Реальный мир
↓
Модель объектов
↓
Модель описаний и связей
↓
Границы ответственности
↓
Архитектура сервисов
↓
API и события
↓
Хранилища
↓
Технологии
Каждый следующий уровень реализует решение, принятое на предыдущем.
Не наоборот.
Если модель говорит, что конструкция и технология являются разными областями знания, архитектура должна позволять разделить их. Если модель говорит, что объект является общим для нескольких областей, архитектура должна позволять нескольким сервисам работать с одним объектом. Если модель говорит, что связь является самостоятельной сущностью, архитектура должна уметь управлять этой связью независимо от связанных объектов.
Эта последовательность выражается в простой формуле:
Модель
↓
объекты
↓
отношения
↓
границы ответственности
↓
архитектура
Архитектура системы не должна создавать модель мира заново. Она должна реализовать уже определённые моделью границы.
13.16. Граница: модель определяет границы, но не реализацию
Однако здесь важно провести границу.
Из того, что модель определяет архитектурные границы, не следует, что она определяет всю реализацию. Модель определяет:
- какие объекты существуют;
- как они связаны;
- кто за них отвечает;
- где проходят границы ответственности.
Но она не определяет:
- какой язык программирования использовать;
- какую базу данных выбрать;
- какой протокол взаимодействия использовать;
- какой брокер сообщений использовать;
- какой механизм кэширования применять;
- как реализовать интерфейс.
Эти решения вторичны. Границы останутся теми же. Модель останется той же.
Предприятие может заменить базу данных. Может заменить язык программирования. Может перейти с монолита на микросервисы. Может заменить брокер сообщений. Но насос Н1 останется насосом Н1. Его конструкция останется конструкцией. Его технологическое описание останется технологическим описанием. Его отношения с другими объектами останутся теми же по смыслу.
Поэтому модель должна переживать технологии. Через пять лет предприятие может заменить инфраструктуру. Через десять лет — архитектурный стиль. Через двадцать лет — целые поколения программного обеспечения. Но данные должны сохранять смысл. Именно модель данных отвечает за этот смысл.
Хорошая модель данных может быть реализована на разных технологиях.
Плохая модель данных не исправляется никакой технологией.
13.17. Почему это не просто «хорошая практика»
Может показаться, что это очевидно. Любой архитектор скажет: «Конечно, модель данных важна».
Но на практике модель данных часто определяется в последнюю очередь. Сначала выбираются технологии. Потом проектируются сервисы. Потом API. Потом таблицы. И только после этого кто-то спрашивает: А какие объекты мы вообще моделируем?
К этому моменту модель уже существует. Неявно. Она записана в таблицах. В API. В DTO. В правилах сервисов. В событиях. В ограничениях базы данных. Но она появилась не из инженерной реальности. Она появилась из технических решений. И именно поэтому изменить её потом чрезвычайно трудно. Правильная последовательность требует дисциплины.
Сначала модель. Потом всё остальное. Это не удобно. Это не быстро. Но именно такая последовательность позволяет строить платформы, которые могут жить десятилетиями.
13.18. Связь с предыдущими главами
Глава 10 установила, что объект существует независимо от документа.
Глава 11 показала, что один и тот же объект может иметь изменяющееся описание.
Глава 12 показала, что отношения между объектами также могут иметь собственный смысл.
Глава 13 делает следующий шаг.
Если объект, описание и отношение являются разными сущностями, то система не может корректно управлять ими как одной неделимой структурой. Границы модели становятся границами ответственности. Границы ответственности становятся архитектурными границами. Поэтому архитектура не является отдельным слоем, придуманным после модели.
Она является её продолжением.
13.19. Главный вывод
Модель данных не является внутренним устройством системы. Она определяет, что система считает существующим, какие сущности она различает и где проходят границы ответственности.
Архитектура должна следовать этим границам. Объект изделия может быть общим для нескольких областей знания. Поэтому сам объект не должен становиться собственностью одного профильного сервиса.
Конструкторское, технологическое, производственное и другие описания могут управляться независимо, потому что они являются разными областями знания об одном объекте.
Единый реестр обеспечивает общий идентификатор объекта. Профильные сервисы хранят свои данные под этим идентификатором. Изменения распространяются между ними через события, а не через передачу владения объектом.
Поэтому правильная последовательность построения системы выглядит так:
Реальный мир
↓
Модель данных
↓
Границы ответственности
↓
Архитектура
↓
API и события
↓
Хранилища
↓
Технологии
Если начать с технологий, модель будет подстраиваться под них. Если начать с модели, технологии станут инструментом её реализации.
Технология определяет, как построить систему. Модель данных определяет, какую систему вообще нужно строить. Архитектура системы не должна создавать модель мира заново. Она должна реализовать уже определённые моделью границы.
В следующей главе: где проходят границы сервисов? Как модель данных определяет, какой сервис управляет каким знанием, и почему это разделение не является произвольным решением архитектора?
Примечания к главе 13
Источники:
- ANSI/EIA-649-D, Configuration Management Standard, SAE International, 2019. §2.1.
- NASA/SP-2016-610, Rev. 2, NASA Systems Engineering Handbook, NASA, 2016. §2.1.
- ГОСТ Р 2.101-2023. Единая система конструкторской документации. Виды изделий.
- ГОСТ 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).
Типы доказательств:
| Утверждение | Тип | Источник |
|---|---|---|
| CM включает процессы с собственными обязанностями | ПНУ | ANSI/EIA-649-D |
| Функции CM распределяются между организационными элементами | ПНУ | NASA Systems Engineering Handbook |
| Изделие и его конструкторские/эксплуатационные документы различаются | ПНУ | ГОСТ Р 2.101-2023, ГОСТ 2.102-68, ГОСТ 2.601-2019 |
| Электронная модель изделия является самостоятельным представлением изделия | ПНУ | ГОСТ Р 2.052-2024 |
| Электронная структура изделия представляет компоненты и связи | ПНУ | ГОСТ Р 2.053-2023 |
| Разделение областей знания влияет на архитектурные границы | СС | Совокупность источников |
| Единый реестр объектов с общим идентификатором | ЛВА | Архитектурное решение |
| Профильные сервисы хранят собственные аспекты одного объекта | ЛВА | Архитектурное решение |
| События позволяют передавать факт изменения без передачи владения объектом | ЛВА | Архитектурное решение |
| Модель данных определяет архитектурные границы | СС + ЛВА | Авторский вывод на основе модели и источников |
| Архитектура должна реализовать уже определённые моделью границы | ЛВА | Архитектурный принцип книги |