11. Стандартная библиотека
До сих пор мы использовали только базовый язык: module, facet, interface. Три ключевых слова. Каждый пример был помеченной рамкой с операциями и стрелками.
Этого достаточно, чтобы смоделировать что угодно структурно, но не хватает двух вещей, которые нужны реальным проектам:
- Визуальное различие. База данных, микросервис, пользователь и внешний поставщик должны выглядеть на диаграмме по-разному. Только с
moduleони так не выглядят. - Принудительные соглашения. Каждый микросервис в этой организации имеет команду-владельца. Базовый вид
moduleничего не принуждает; валидатор не отличит сервис от внешнего клиента.
Стандартная библиотека решает обе задачи. Она поставляет два пакета видов — arch.modules и arch.kinds, — которые вводят семантические подтипы базовых видов. Каждый каскадирует виджет по умолчанию и (как правило) требует несколько полей.
Эта глава знакомит с тем, что есть в стандартной библиотеке и как подключить её к проекту.
Подключение стандартной библиотеки
Добавьте две строки в package.archspace:
name: my-project
use * from arch.modulesuse * from arch.kindsarch.modules добавляет подтипы модулей (service, database, actor, …). arch.kinds добавляет подтипы интерфейсов (command, query, event, …). Оба пакета автоматически разрешаются через встроенную в инструментарий стандартную библиотеку — запись в dependencies не нужна.
Теперь ваши файлы .arch могут использовать более выразительные виды:
service Payments { team: Payments labels { domain: Payments }
command Authorize event PaymentEvents}Импортируемые виды — это подтипы module и interface. Все правила из глав 4 и 5 применимы — поверх просто добавляются значения по умолчанию и требования.
Виды модулей (arch.modules)
Из коробки поставляется семь видов.
| Вид | Обязательные поля | Значения по умолчанию | Виджет по умолчанию |
|---|---|---|---|
service | required cascade team, required labels.domain | — | arch-service |
frontend | required cascade team, required labels.domain | — | arch-frontend |
database | required cascade team, required labels.data.classification | — | arch-database |
component | — | cascade team (по умолчанию пусто) | arch-component |
system | — | cascade team | arch-system |
external_system | required ext.vendor, required ext.contract.url | — | arch-external-system |
actor | — | — | arch-actor |
Столбцы:
- Обязательные поля должны быть заполнены или сброшены в каждом экземпляре. Их отсутствие — ошибка разбора.
- Значения по умолчанию — предустановленные поля, которые наследует экземпляр; каскад распространяет их на вложенные модули.
- Виджет по умолчанию — тег пользовательского элемента, который монтирует средство рендеринга. У каждого вида своя визуальная идентичность.
use * from arch.modules сразу даёт рабочую визуализацию; собственный скрипт виджетов не требуется. (Глава 20 посвящена настройке виджетов.)
Когда что использовать:
service— серверный сервис с поддерживающей командой.frontend— приложение для пользователя (веб, мобильное).database— хранилище данных.component— более мелкая часть внутри другого модуля. Часто вложенная.system— контейнер, группирующий другие модули (подсистема или продуктовая область).external_system— поставщик или партнёр, который вам не принадлежит.ext.vendorиext.contract.urlобязательны, чтобы внешние зависимости всегда документировали, что они такое и где их контракт.actor— человек или внешний клиент, инициирующий вызовы. Акторы не предоставляют операций; они их вызывают.
Используйте базовый вид module, когда ни один из этих не подходит — обычно редко. Если хочется «почти service, но ещё с тремя обязательными полями», определите подтип в рамках проекта (Глава 16).
Виды интерфейсов (arch.kinds)
Поставляется шесть видов.
| Вид | Родитель | Семантика |
|---|---|---|
sync | interface | Универсальный синхронный интерфейс |
async | interface | Универсальный асинхронный интерфейс |
command | sync | Операция, изменяющая состояние |
query | sync | Операция только для чтения |
event | async | Pub/sub-вещание |
stream | async | Долгоживущий поток данных |
Два родительских вида (sync, async) задают оформление рёбер: синхронные сплошные, асинхронные пунктирные. Четыре дочерних вида (command, query, event, stream) наследуют это оформление и передают конкретную семантику.
Только event и stream (или что-либо, наследующее их) — осмысленные цели для связи через subscribes:. Валидатор отклоняет subscribes: someCommand.
Базовый язык против стандартной библиотеки: одна и та же модель
Одна и та же архитектура, записанная двумя способами:
Базовая запись:
module Payments { team: Payments interface Authorize interface OrderEvents}
module Shipping { team: Fulfillment interface CreateShipment { subscribes: Payments.OrderEvents }}С использованием стандартной библиотеки:
service Payments { team: Payments labels { domain: Payments }
command Authorize event OrderEvents}
service Shipping { team: Fulfillment labels { domain: Fulfillment }
command CreateShipment { subscribes: Payments.OrderEvents }}Структура идентична — два модуля, три интерфейса, одна связь подписки. Версия со стандартной библиотекой добавляет:
- Виджеты
service(конкретная визуальная идентичность). - Виды интерфейсов
command/event(оформление рёбер sync против async). - Метку
domain(теперь обязательную, потому что её требует тип).
Базовая версия валидна; версия со стандартной библиотекой — то, что реально поставляют в проектах. Перевод механический.
Когда НЕ стоит использовать стандартную библиотеку
Несколько сценариев, где базовые виды имеют смысл:
- Изучение языка. В главах 2–10 использовались базовые виды именно поэтому — меньше движущихся частей.
- Маленькие черновые проекты без манифеста. Анонимные пакеты не могут ничего импортировать через
use, поэтому базовые виды — всё, что доступно. - Создание собственного инструментария. Если вы встраиваете Archlang в систему, которая уже определяет собственную онтологию, может быть желательно полностью обойти словарь стандартной библиотеки.
Большинство проектов используют стандартную библиотеку.
Что дальше
Глава 12: Пакеты → — подробно о манифесте: зависимости, версия, экспорт типов.