Перейти к содержанию

Архитектурные границы компонентов

Требования применяются к внутренней структуре запускаемых и публикуемых компонентов, разделяющих ответственность между проектными модулями и адаптерами. Они не предписывают число слоёв или именованный архитектурный паттерн. Уровни обязательности определены в корневом README.md.

В этом документе:

  • проектный модуль — именованная единица исходного кода с определяемыми статическими зависимостями;
  • прикладное правило — независимое от технологии входа решение о допустимости, результате, состоянии или обязательном эффекте операции;
  • прикладная граница — принадлежащий проекту контракт вызова прикладного правила;
  • адаптер — код, преобразующий контракт транспорта, хранилища, framework или внешнего provider в контракт прикладной границы либо обратно.

ARC-PAT-001. Обоснованная архитектурная абстракция

Уровень: SHOULD

Применяется к: добавлению проектного интерфейса, слоя или модуля, не заданного внешним контрактом

Новой архитектурной абстракции следует изолировать хотя бы одно фактически существующее различие:

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

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

Обоснование

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

Проверка

  • сопоставление абстракции с одним из перечисленных различий;
  • поиск фактического потребителя и реализации;
  • сравнение с прямой реализацией без дополнительной границы;
  • architecture test направления зависимости, если граница его устанавливает.

Исключения

Extension point, обязательный для framework, и сгенерированный контракт MAY иметь одну реализацию, если их происхождение определяется dependency metadata или входом генератора.

ARC-PAT-002. Направление зависимости прикладной границы

Уровень: SHOULD

Применяется к: компоненту с прикладным правилом и адаптером транспорта, хранилища, framework или внешнего provider

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

Адаптеру следует зависеть от прикладной границы и преобразовывать внешний контракт до её вызова и после получения результата. Прикладному правилу не следует зависеть от реализации адаптера.

Обоснование

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

Проверка

  • статическая проверка import graph между прикладным правилом и адаптерами;
  • unit-тест правила без инициализации framework, сети или хранилища;
  • contract-тест преобразования входов, результатов и ошибок адаптера.

Исключения

Тип MAY быть сгенерирован из версионируемого проектного или публичного контракта, если он не требует lifecycle context, соединения или сессии конкретного адаптера и его совместимость проверяется автоматически.

Компонент, который только проверяет и передаёт внешний контракт без прикладного правила, находится вне области требования.

ARC-PAT-003. Единый путь применения прикладного правила

Уровень: MUST

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

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

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

Обоснование

Дублирование правила между HTTP handler, consumer, job или UI создаёт пути, которые по-разному защищают доступ и целостность данных.

Проверка

  • перечисление поддерживаемых точек входа и трассировка вызова общей прикладной границы;
  • статический запрет прямого доступа входного адаптера к реализации эффекта;
  • негативный тест каждой точки входа: отклонённое правило не создаёт эффект.

Исключения

Миграционная или repair-операция MAY использовать отдельное правило только по ADR, определяющему её назначение, доступ, входные данные, аудит и срок удаления. Read-only техническая операция без перечисленного эффекта находится вне области требования.

ARC-PAT-004. Ациклические зависимости проектных модулей

Уровень: SHOULD

Применяется к: компоненту с двумя и более проектными модулями и статическими зависимостями между ними

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

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

Обоснование

Цикл скрывает владельца контракта, связывает независимые изменения и мешает проверять направление зависимостей.

Проверка

  • автоматическое построение import или module dependency graph;
  • architecture test, отклоняющий добавление цикла;
  • сборка модулей в топологическом порядке, если toolchain поддерживает отдельную сборку.

Исключения

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

ARC-PAT-005. Закрытая поверхность проектного модуля

Уровень: MUST

Применяется к: компоненту с двумя и более проектными модулями, разделяющими прикладные ответственности

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

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

Обоснование

Общая process- и release-граница не защищает модуль от скрытого обхода его инвариантов и последующего неуправляемого разделения ответственности.

Проверка

  • автоматическая проверка import graph и разрешённых направлений зависимостей;
  • поиск обращений к внутренним namespace или package другого модуля;
  • contract-тест публичных входов, результатов и ошибок модуля.

Исключения

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

ARC-PAT-006. Владение состоянием проектного модуля

Уровень: MUST

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

Для каждого такого состояния должен быть определён один проектный модуль-владелец и единственный поддерживаемый путь изменения. Другой модуль не должен изменять состояние через внутренний repository, таблицу, файл, bucket, cache keyspace или адаптер хранения владельца.

Чтение другим модулем должно проходить через публичную прикладную границу владельца либо через явно принадлежащее consumer производное read-only представление. Для производного представления должны быть определены источник, допустимая свежесть и способ полного пересоздания. Общее физическое хранилище MAY использоваться, если граница записи и запрещённые зависимости проверяются автоматически.

Обоснование

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

Проверка

  • сопоставление устойчивого состояния, модуля-владельца и write path;
  • статический запрет доступа другого модуля к write adapter владельца;
  • негативный тест обходной записи;
  • тест свежести и полного пересоздания производного представления.

Исключения

Временный путь записи для миграции или repair-операции MAY существовать только по принятому ADR с порядком переключения, защитой от конкурирующей записи, восстановлением и сроком удаления.