11. Стандартная библиотека
До сих пор мы использовали только базовый язык: module, surface, interface. Три базовых типа. Каждый пример был помеченной рамкой с операциями и стрелками.
Этого достаточно, чтобы смоделировать что угодно структурно, но не хватает двух вещей, которые нужны реальным проектам:
- Визуальное различие. База данных, сервис, пользователь и внешний поставщик должны выглядеть на диаграмме по-разному. Только с
moduleони так не выглядят. - Принудительные соглашения. Каждый сервис в этой организации имеет команду-владельца. Базовый тип
moduleничего не принуждает; валидатор не отличит сервис от внешнего клиента.
Стандартная библиотека решает обе задачи. Она поставляет пакеты типов — arch.extras, arch.c4, arch.backend, arch.diagrams, — которые вводят семантические подтипы базовых типов. Каждый каскадирует виджет по умолчанию и (как правило) требует несколько полей.
Правило. Стандартная библиотека — это необязательные батарейки, а не обязаловка. Это хороший, исчерпывающий набор по умолчанию, прикрученный к базовому языку: опирайтесь на него, чтобы стартовать, но вы вольны построить собственную библиотеку с нуля, и начало работы на типах стандартной библиотеки вас ни к чему не привязывает. Позже вы можете заменить тип из стандартной библиотеки своим или расширить его (добавить требования, поля, варианты связывания), а не переписывать.
Эта глава знакомит с тем, что есть в стандартной библиотеке и как подключить её к проекту.
Подключение стандартной библиотеки
Заголовок раздела «Подключение стандартной библиотеки»Объявите нужные типы в package.archspace, чтобы палитра была общей для пространства — каждый файл .arch в пакете может до неё дотянуться, а манифест заодно служит обозримым списком того, что в ходу:
package: my-project
// Относитесь к каждому пакету как к палитре — берите типы, которые реально используете.use service, database, message_broker, gateway from arch.backenduse rest_create, rest_read, rest_update, kafka, grpc_unary from arch.backenduse user, usergroup from arch.extrasuse table, column from arch.diagramsПравило. Никогда не делайте
use *для стандартной библиотеки. Относитесь к пакету стандартной библиотеки как к палитре, из которой выбирают, и импортируйте по имени ту горстку типов, которая вам нужна. Wildcard затаскивает всю поверхность пакета и привязывает вас ко всему ней. (use *оправдан только для небольшой внутренней библиотеки, которую вы написали сами, — никогда для стандартной библиотеки.) Держите эти строкиuseв манифестеpackage.archspace, а не переимпортируйте файл за файлом: один список на уровне пространства самодокументируем.
arch.backend — это прагматичный словарь архитектуры: ключевые backend-типы модулей (service, database, gateway, message_broker, …), общие типы system / frontend / component / external_system и типы интерфейсов на уровне протокола (http_*, grpc_*, kafka, amqp, db_read, db_write, …). arch.extras поставляет общие фигуры устройств и людей (user, usergroup, laptop, server, cloud, …). arch.diagrams добавляет table / column для ER-схем. Все пакеты автоматически разрешаются через встроенную в инструментарий стандартную библиотеку — запись в dependencies не нужна.
Предпочитаете формальную модель C4? arch.c4 — это полный, самодостаточный словарь C4: person, software_system, container + подтипы по форм-фактору, component, внешние/граничные варианты и узлы развёртывания. Импортируйте те типы C4, которыми вы декомпозируете, — use person, software_system, container, component from arch.c4 — и оставайтесь в фиксированном наборе абстракций C4. Такая библиотека — больше, чем удобство: C4 — это метамодель, нотация и дисциплина, которая формирует то, как вы декомпозируете и рассуждаете. Вы принимаете её ради того, что она делает с вашим мышлением, а не только ради рамок, которые она вам выдаёт. (В отличие от arch.extras, чьи фигуры user / group — чисто приятные дополнения, делающие диаграмму нагляднее.)
Теперь ваши файлы .arch могут использовать более выразительные типы:
service Payments { aspect team: "Payments" aspect { domain: "Payments" }
rest_create authorize kafka paymentEvents}Импортируемые типы — это подтипы module и interface. Все правила из глав 4 и 5 применимы — поверх просто добавляются значения по умолчанию и требования.
Backend-типы модулей (arch.backend)
Заголовок раздела «Backend-типы модулей (arch.backend)»Наиболее распространённые backend-типы модулей:
| Тип | Пакет | Обязательные поля | Значения по умолчанию | Виджет по умолчанию |
|---|---|---|---|---|
service | arch.backend | — | aspect team, aspect domain | arch-module |
database | arch.backend | — | aspect team, aspect data.classification | arch-backend-database |
message_broker | arch.backend | — | aspect team, aspect domain | arch-module |
Столбцы:
- Обязательные поля должны быть заполнены или сброшены в каждом экземпляре. Их отсутствие — ошибка разбора.
- Значения по умолчанию — предустановленные поля, которые наследует экземпляр; каскад распространяет их на вложенные модули.
- Виджет по умолчанию — тег пользовательского элемента, который монтирует средство рендеринга. У каждого типа своя визуальная идентичность.
Когда что использовать:
service— серверный сервис с поддерживающей командой.database— хранилище данных. Подтипы по семейству (relational,document,kv_store, …) и по движку (postgres,mongodb,redis, …).message_broker— развёрнутый брокер (кластер Kafka, RabbitMQ, NATS, …).
Используйте базовый тип module, когда ни один из этих не подходит — обычно редко. Если хочется «почти service, но ещё с тремя обязательными полями», определите подтип в рамках проекта (Глава 16).
Типы модели C4 (arch.c4)
Заголовок раздела «Типы модели C4 (arch.c4)»arch.c4 — это полный словарь модели C4: четыре уровня абстракции (Context, Containers, Components, Code) за вычетом Code, которым является сам исходный код. Цвета следуют канонической палитре C4, поэтому диаграммы читаются так же, как в официальной нотации.
| Тип | Уровень | Обязательные поля | Значения по умолчанию | Виджет по умолчанию |
|---|---|---|---|---|
person | Context | — | aspect team, aspect domain | arch-c4-person |
external_person | Context | — | — | arch-c4-external-person |
software_system | Context | — | aspect team, большая карточка | arch-module |
external_software_system | Context | required ext.vendor, required ext.contract.url | — | arch-module (пунктир, чип vendor) |
container | Container | — | aspect team, aspect technology | arch-module |
component | Component | — | aspect team | arch-module |
enterprise_boundary | Boundary | — | большая пунктирная карточка | arch-c4-boundary |
system_boundary | Boundary | — | большая пунктирная карточка | arch-c4-boundary |
container_boundary | Boundary | — | большая пунктирная карточка | arch-c4-boundary |
container через подтипы предустанавливает глиф заголовка для распространённых форм-факторов: web_application, single_page_app, mobile_app, api, data_store, message_bus, file_system, serverless_function. Каждый остаётся container для любого правила или шага процесса, фильтрующего по родительскому типу.
Когда что использовать:
person— человек-пользователь, роль или персона.external_personнаходится за пределами рассматриваемого предприятия (клиент, партнёр) и рендерится приглушённым + пунктирным.software_system— высший уровень абстракции; приносит ценность своим пользователям.external_software_system— система, которая вам не принадлежит;ext.vendor/ext.contract.urlобязательны, чтобы внешние зависимости всегда документировали, что они такое и где находится их контракт.container— отдельно разворачиваемая/запускаемая единица (веб-приложение, API, база данных, очередь). НЕ Docker-контейнер, хотя может им быть.aspect technologyфиксирует технологический стек так, как C4 печатает его под именем.component— группировка функциональности внутри контейнера за чётко определённым интерфейсом. Отдельно не разворачивается.- границы — пунктирные группирующие прямоугольники, размещающие подпространство дочерних элементов:
enterprise_boundary(люди + системы одной организации),system_boundary(контейнеры одной системы),container_boundary(компоненты одного контейнера).
Отношения («uses», «sends data to», …) не являются типами модулей — в ArchLang они вытекают из шагов process и соединений interface между этими узлами, как и в любом другом пакете.
Уровень развёртывания
Заголовок раздела «Уровень развёртывания»Дополнительная диаграмма развёртывания C4 отображает логические контейнеры на реальную инфраструктуру. arch.c4 поставляет и её, отрисовывая серо-сланцевым цветом, чтобы отделить физический слой от синих логических элементов:
| Тип | Обязательные поля | Значения по умолчанию | Виджет по умолчанию |
|---|---|---|---|
deployment_node | — | aspect team, aspect technology, большая карточка | arch-module |
infrastructure_node | — | aspect team, aspect technology | arch-module |
container_instance | — | (подтип container) чип aspect instances | arch-module |
deployment_node— где выполняется программное обеспечение. Свободно вкладывается (cloud → region → cluster → host) и размещает подпространство. Разновидности предустанавливают глиф:cloud_platform,region,cluster,host,execution_environment,device.infrastructure_node— вспомогательное сетевое оборудование, не являющееся контейнером:load_balancer,firewall,dns,cdn,gateway.container_instance— развёрнутая копияcontainer; задайтеaspect instancesдля количества реплик («x3»).aspect technology— это строка, которую C4 печатает под именем каждого узла.
arch.c4 самодостаточен — он покрывает всю модель C4 (Context, Container, Component, Boundaries, Deployment) самостоятельно. Используйте его, когда хотите оставаться в фиксированном словаре C4, а не в открытой вложенности и аспектах ArchLang.
Типы интерфейсов (arch.backend)
Заголовок раздела «Типы интерфейсов (arch.backend)»Типы интерфейсов на уровне протокола, сгруппированные по транспорту:
| Группа | Типы |
|---|---|
| HTTP | http_get, http_post, http_put, http_patch, http_delete, http_head, http_options, webhook, sse |
| REST | rest_list, rest_create, rest_read, rest_update, rest_delete (+ поверхность rest_crud) |
| gRPC | grpc_unary, grpc_server_stream, grpc_client_stream, grpc_bidi_stream |
| GraphQL | graphql_query, graphql_mutation, graphql_subscription |
| WebSocket | websocket |
| Messaging | kafka, amqp, nats, mqtt, redis_pubsub |
| Доступ к данным | db_read, db_write |
Соглашение по оформлению рёбер: синхронные request/response — сплошная линия; асинхронные / стримовые / pub-sub — пунктирная. Стримовые варианты (grpc_server_stream, webhook, sse, graphql_subscription) переопределяют свой сплошной родитель на пунктирный.
Асинхронные/событийные интерфейсы (любые пунктирные: kafka, amqp, nats, mqtt, redis_pubsub, webhook, sse, graphql_subscription, grpc_*_stream) — это то, чем вы моделируете события. Событие — это просто один из таких асинхронных интерфейсов, достигаемый обычным ребром процесса >; нет ни поля subscribes:, ни отдельной конструкции события. Именно пунктирный тип помечает вызов как асинхронный; ребро и есть подписка.
Базовый язык против стандартной библиотеки: одна и та же модель
Заголовок раздела «Базовый язык против стандартной библиотеки: одна и та же модель»Одна и та же архитектура, записанная двумя способами:
Базовая запись:
module Payments { aspect team: "Payments" interface authorize interface orderEvents}
module Shipping { aspect team: "Fulfillment" interface createShipment}
process Fulfilment { Shipping > Payments.orderEvents // ребро подписывает Shipping на событие}С использованием стандартной библиотеки:
service Payments { aspect team: "Payments" aspect { domain: "Payments" }
rest_create authorize kafka orderEvents}
service Shipping { aspect team: "Fulfillment" aspect { domain: "Fulfillment" }
rest_create createShipment}
process Fulfilment { Shipping > Payments.orderEvents // асинхронное ребро — тип kafka рисует его пунктиром}Структура идентична — два модуля, три интерфейса, одно ребро процесса, подписывающее Shipping на событие Payments. Версия со стандартной библиотекой добавляет:
- Виджеты
service(конкретная визуальная идентичность). - Типы интерфейсов
rest_create/kafka(сплошные sync против пунктирных async). - Аспект
domain(теперь обязательный, потому что его требует тип).
Базовая версия валидна; версия со стандартной библиотекой — то, что реально поставляют в проектах. Перевод механический.
Когда НЕ стоит использовать стандартную библиотеку
Заголовок раздела «Когда НЕ стоит использовать стандартную библиотеку»Несколько сценариев, где базовые типы — или ваша собственная библиотека — имеют смысл:
- Изучение языка. В главах 2–10 использовались базовые типы именно поэтому — меньше движущихся частей, которые нужно держать в голове.
- Крошечные черновые проекты без манифеста. Анонимные пакеты не могут ничего импортировать через
use, поэтому базовые типы — всё, что доступно. (Однофайловые черновики — полноправны, см. Глава 12.) - Создание собственной библиотеки. Библиотеки дёшево писать. Крупной организации часто нужна собственная — обычно не ради виджетов (виджеты стандартной библиотеки переиспользуемы), а ради специфичной для организации семантики: требований к владению/сопровождению, отношений между подразделениями, фирменной нотации. Постройте её с нуля или расширьте типы стандартной библиотеки, а не заменяйте их.
- Создание собственного инструментария. Если вы встраиваете ArchLang в систему, которая уже определяет собственную онтологию, может быть желательно полностью обойти словарь стандартной библиотеки.
Стандартная библиотека — удобное значение по умолчанию, а не требование: большинство проектов опираются на неё, заменяют части по мере перерастания и расширяют там, где этого требуют внутренние правила.
Что дальше
Заголовок раздела «Что дальше»Глава 12: Пакеты → — подробно о манифесте: зависимости, версия, экспорт типов.