Глава 15. Может ли система запрещать ошибки?

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

15.1. От проверки к невозможности

Обычная информационная система работает следующим образом.

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

Пользователь создаёт изделие без описания. Система отвечает: «Ошибка: необходимо указать описание».

Пользователь создаёт Revision непосредственно для изделия. Система отвечает: «Ошибка: операция недопустима».

Пользователь создаёт связь между несовместимыми типами объектов. Система отвечает: «Ошибка: такие объекты нельзя связать».

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

Это различие между проверкой и моделью. Проверка говорит: «Так делать нельзя». Модель говорит: «Такого состояния не существует».

Для инженерной системы это принципиально разные подходы.

15.2. Почему проверки недостаточно

Представим систему, которая запрещает создать Revision без указания KDefinition.

Через пользовательский интерфейс это действительно запрещено.

Но система имеет API. Есть импорт данных. Есть интеграция с ERP. Есть миграции. Есть административные инструменты. Есть другие сервисы.

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

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

15.3. Инвариант

Для этого в модели существуют инварианты.

Инвариант — это формальное условие, которое должно сохраняться для всех допустимых состояний модели.

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

Например:

KObject
    |
    +-- KContext
    |
    +-- KDefinition
            |
            +-- Revision

Эта структура означает больше, чем набор таблиц. Она означает:

  • KContext относится к KObject;
  • KDefinition относится к KObject;
  • Revision относится к KDefinition;
  • Revision не является версией KObject.

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

15.4. Инвариант первый: объект первичен

KObject существует
        ↓
всё остальное относится к нему

Но не наоборот.

KContext относится к KObject. KAttribute относится к KObject. KDefinition относится к KObject. KRelation соединяет KObject с KObject.

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

Что это предотвращает?

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

15.5. Инвариант второй: идентичность не имеет свойств

KObject
    id: 12345

Не более.

KObject не содержит имени. Не содержит владельца. Не содержит статуса. Не содержит описания. Это не бедность модели. Это её сила.

Идентичность объекта должна оставаться неизменной, пока объект остаётся тем же объектом. Имя может измениться. Владелец может измениться. Статус может измениться. Описание может измениться. Но изменение этих характеристик не должно создавать новый объект.

Что это предотвращает?

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

15.6. Инвариант третий: Revision принадлежит описанию

KProduct
    |
    +-- KDesignDefinition
            |
            +-- Revision A
            +-- Revision B

Revision не принадлежит KProduct.

Revision принадлежит KDefinition.

Невозможно создать Revision для самого объекта как такового. Revision относится к определённому описанию объекта. Это означает, что Revision A и Revision B описывают изменения именно этого определения. Не изменение объекта. Не изменение контекста. Не изменение экземпляра. Не изменение производственного состояния.

Изменение конструкторского описания.

Что это предотвращает?

Ситуацию, в которой пользователь создаёт «Revision изделия», не определив, что именно изменилось. Ситуацию, в которой изменение описания и изменение самого объекта записываются одинаково. Ситуацию, в которой через несколько лет невозможно восстановить смысл записи.

15.7. Инвариант четвёртый: изменение объекта создаёт новый объект

KProduct A
        ↓
KProduct B

Здесь необходимо вернуться к Главе 4.

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

Revision существует внутри KDefinition. KDefinition существует внутри KProduct.

Но KProduct не имеет Revision.

Следовательно, изменение, которое означает появление нового объекта, не должно записываться как Revision. Оно должно приводить к созданию нового KProduct.

Что это предотвращает?

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

15.8. Инвариант пятый: контекст не может существовать без объекта

KObject: 12345
    |
    +-- KContext
            owner: Иванов
            project: Проект А

Но не:

KContext
    owner: Иванов
    project: Проект А
    object: ???

Контекст всегда относится к объекту. Невозможно создать контекст, который не связан с конкретным объектом. Это следствие Главы 22. Контекст отвечает на вопрос: в каких условиях существует объект? Если объекта нет, контекст не имеет предмета, существование которого он описывает.

Что это предотвращает?

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

15.9. Инвариант шестой: атрибут имеет время

KAttribute
    object: 12345
    type: material
    value: 09Г2С
    valid_from: 01.06.2031
    source: конструктор Петров
    basis: извещение №45

Атрибут не является простым значением.

Он является утверждением о состоянии объекта в определённый момент времени. Поэтому атрибут имеет:

  • объект;
  • значение;
  • время действия;
  • источник.

Невозможно создать атрибут без связи с объектом. Невозможно создать атрибут без времени. Невозможно создать атрибут без источника.

Что это предотвращает?

Ситуацию, в которой система хранит только последнее значение:

material = 09Г2С

и через десять лет невозможно определить:

  • когда оно появилось;
  • когда изменилось;
  • кто его указал.

Модель сохраняет не только значение. Она сохраняет утверждение вместе с его происхождением.

15.10. Инвариант седьмой: связь имеет смысл

KRelation
    from: KObject 12345
    to: KObject 67890
    type: contains
    position: 10
    quantity: 4

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

KProduct ──contains──> KProduct
KDocument ──describes──> KDefinition

Но:

KDocument ──contains──> KProduct

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

Что это предотвращает?

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

15.11. Инвариант восьмой: исполнение является объектом

KPExecutionGroup
    |
    +-- KProduct (исполнение 1)
    +-- KProduct (исполнение 2)
    +-- KProduct (исполнение 3)

Исполнение является KProduct.

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

KProduct.

Это следует из вывода Главы 7: если исполнение является самостоятельным изделием, оно должно быть самостоятельным объектом инженерного учёта.

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

Что это предотвращает?

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

Производство не должно получать задание изготовить:

конфигурация 047

не имея в системе самостоятельного объекта, который эта конфигурация представляет.

15.12. Почему инварианты сильнее правил

Традиционная система проверяет правильность действий пользователя.

Пользователь нажимает кнопку. Система проверяет: допустимо ли действие? Если нет — показывает ошибку. Но такая проверка является внешней. Её можно обойти:

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

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

Это различие принципиально.

Правило говорит: «Не делай этого».

Инвариант говорит: «Это состояние невозможно».

15.13. Аналогия со строгой типизацией

В программировании есть похожий принцип.

Без строгой типизации:

x = "hello" + 42

Технически можно попытаться определить, что должно произойти.

Со строгой типизацией:

x: Integer = "hello" + 42

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

То же самое происходит в модели данных. Строгая модель не делает систему менее гибкой. Она ограничивает множество состояний, которые не имеют смысла в предметной области. Пользователь не может случайно создать изделие без необходимого определения. Revision нельзя создать как свойство самого объекта. Контекст нельзя отделить от объекта. Связь нельзя создать без её типа и допустимых участников. Исполнение нельзя представить только набором параметров.

15.14. Валидация и инвариант — не одно и то же

Здесь важно провести границу.

Валидация отвечает на вопрос: «Корректны ли данные?»

Инвариант отвечает на вопрос: «Может ли такое состояние существовать в модели?»

Например, значение:

diameter = 150 mm

может быть структурно корректным. Но оно может быть инженерно неправильным. Модель не знает, должен ли конкретный насос иметь диаметр 150 или 160 мм, если это не выражено отдельным правилом предметной области.

Поэтому модель не может предотвратить все ошибки.

15.15. Что модель может запретить, а что нет

Здесь важно зафиксировать принципиальную границу.

Не всякая ошибка может быть предотвращена моделью. Модель может запрещать структурно невозможные состояния. Она не может определить, правильно ли инженер выбрал материал или верно ли выполнил расчёт.

Модель может запретить:

  • создать изделие без необходимого определения;
  • создать Revision непосредственно для объекта;
  • создать Revision без определения;
  • создать исполнение только как набор параметров;
  • создать связь без допустимого типа;
  • создать контекст без объекта;
  • представить изменение объекта как изменение его описания, если модель различает эти два случая.

Модель не может сама по себе запретить:

  • ввести неверный размер в чертеже;
  • указать неправильную дату;
  • выбрать неподходящий материал;
  • ошибиться в расчёте;
  • принять неверное инженерное решение.

Первые ошибки нарушают структуру предметной области. Вторые нарушают инженерный смысл конкретных данных.

Для вторых существуют другие механизмы:

  • экспертиза;
  • согласование;
  • верификация;
  • расчёт;
  • испытания;
  • аудит.

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

15.16. Практический пример

Рассмотрим конкретную ситуацию.

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

В традиционной модели: Пользователь создаёт Revision C для Part «Насос Н1». Система позволяет. Запись существует. Формально всё корректно. Но по смыслу это ошибка: под одним обозначением оказались два разных объекта.

Через пять лет эксплуатационная служба спрашивает: «Можно ли заменить насос Revision A на Revision C?» Система не может дать однозначный ответ. Потому что модель не различает изменение описания и изменение самого объекта.

В модели с разделением: Пользователь пытается создать Revision C. Инженер определяет, что изменение затрагивает присоединительные размеры и нарушает взаимозаменяемость. Следовательно, это не новая Revision того же объекта. Создаётся новый KProduct:

KProduct: Насос Н1
        |
        +-- KDesignDefinition
                +-- Revision A
                +-- Revision B

KProduct: Насос Н2
        |
        +-- KDesignDefinition
                +-- Revision A

Между объектами может быть зафиксирована связь преемственности. Через пять лет система уже может ответить: «Насос Н2 — другой объект. Он не является взаимозаменяемой Revision насоса Н1».

Модель содержит различие.

15.17. Что это даёт через десять лет

PLM-система живёт десятилетиями.

Люди, которые создавали записи, уходят. Остаются данные.

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

Revision B означает изменение определённого описания. KProduct B означает другой объект. KContext означает условия существования. KAttribute означает утверждение о свойстве. KRelation означает типизированную связь. Каждое понятие имеет собственный смысл.

Это не удобство. Это требование долговечности.

15.18. Как инварианты связаны с архитектурой

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

Инвариант:

Revision принадлежит Definition.

означает, что создание и изменение Revision относится к сервису, управляющему соответствующим Definition.

Инвариант:

KContext не существует без KObject.

означает, что Context Service работает с контекстом конкретного зарегистрированного объекта.

Инвариант:

KRelation имеет определённый тип и допустимых участников.

означает, что Relation Service отвечает за правила создания соответствующих связей.

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

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

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

Вместе эти главы формируют следующую последовательность. Модель определяет объекты. Объекты определяют области ответственности. Области ответственности определяют границы сервисов.

Инварианты определяют, какие состояния допустимы внутри этих границ. Так модель данных превращается из схемы хранения в механизм сохранения смысла.

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

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

Не всех ошибок.

Содержательные ошибки — неверный размер, неправильный материал, ошибочный расчёт — остаются ответственностью инженера.

Но онтологические ошибки — создание несуществующего объекта, смешение объекта и его описания, подмена нового изделия новой Revision, создание исполнения как набора параметров — могут быть предотвращены структурой модели.

Это не ограничение свободы. Это отражение инженерной реальности. Модель не должна спрашивать пользователя каждый раз: «Ты уверен, что хочешь сделать это?»

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

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

В следующей главе: почему современные PLM-системы начали смешивать управление конфигурацией и управление вариантами, и к каким последствиям это приводит.

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

Источники:

  • ISO 10007:2017, Quality management — Guidelines for configuration management.
  • ГОСТ Р ИСО 10007-2019. Менеджмент качества. Руководящие указания по менеджменту конфигурации.
  • ANSI/EIA-649-D, Configuration Management Standard, SAE International, 2019.
  • NASA/SP-2016-610, Rev. 2, NASA Systems Engineering Handbook, NASA, 2016.
  • ГОСТ Р 2.101-2023. Единая система конструкторской документации. Виды изделий.
  • ГОСТ Р 2.052-2024. Единая система конструкторской документации. Электронная модель изделия. Общие положения.
  • ГОСТ Р 2.053-2023. Единая система конструкторской документации. Электронная структура изделия. Общие положения.
  • ГОСТ Р 2.005-2023. Единая система конструкторской документации. Термины и определения.
  • ГОСТ 2.113-75. Единая система конструкторской документации. Групповые и базовые конструкторские документы.

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

УтверждениеТип
Модель данных может ограничивать допустимые состоянияЛВА (архитектурный вывод)
Инварианты являются формальным выражением модели предметной областиЛВА
KContext не существует без KObjectЛВА (архитектурный принцип Constructum)
Revision относится к Definition, а не непосредственно к KProductЛВА (архитектурный принцип Constructum)
Изменение, нарушающее взаимозаменяемость, требует нового объектаЛВА + вывод из Главы 4
Атрибут хранит время, источник и основаниеЛВА (модель Constructum)
Исполнение является самостоятельным объектомСС + ЛВА; см. Главу 7 и ГОСТ 2.113-75
Модель не предотвращает содержательные инженерные ошибкиЛВА
Инварианты определяют границы ответственности сервисовЛВА
Разделение объекта и описания позволяет сохранить смысл данныхСС (совокупность выводов книги)