2. Ваша первая архитектура
Эта глава ведёт через построение полной (маленькой) архитектуры из пустого каталога. К концу у вас будет три модуля, один процесс, связывающий их, диаграмма и ощущение формы языка.
Мы будем использовать только базовый язык — базовые виды module, facet, interface плюс конструкции верхнего уровня process и view — без стандартной библиотеки. Дальнейшие главы вводят более богатые виды (service, command, event); Глава 11 подробно их разбирает. Старт с базовым языком держит фокус на том, что делает сам язык, отдельно от соглашений.
Смоделируем платёжный домен: клиент платит, платёжный сервис авторизует, реестр записывает. И больше ничего.
Пакет
Каждый проект начинается с манифеста. Создайте package.archspace:
name: shopОдна строка. Имя идентифицирует пакет; стандартную библиотеку пока не импортируем, потому что используем только базовые виды.
Глава 12 подробно разбирает манифест. Пока хватит этого.
Три модуля
Добавьте payments.arch в тот же каталог:
module Payments { team: Platform "Авторизует и проводит карточные платежи."
interface Authorize interface Capture interface Refund}
module Ledger { team: Finance "Неизменяемая финансовая запись каждой транзакции."
interface Record}
module Customer { "Человек, инициирующий платёж."}Вы объявили три модуля базовым видом module. У каждого есть:
- Вид (
module) — базовый вид языка. - Имя (
Payments,Ledger,Customer) — как остальная часть модели на него ссылается. - Поле team — кто им владеет (необязательно; базовый вид не требует).
- Описание — простой строковый литерал. Обычный markdown плюс два расширения, с которыми вы познакомитесь в Главе 10.
- Ноль или больше интерфейсов —
interface Authorizeи т. д. Это то, что другие модули могут попросить этот сделать.
У Customer интерфейсов нет. Это нормально — не каждый модуль выставляет операции наружу. (Виды стандартной библиотеки добавляют семантические различия вроде actor для сущностей, которые только инициируют вызовы; пока всё — просто module.)
Попробуйте вживую — отредактируйте исходник выше, диаграмма обновится ниже. Наводитесь на идентификаторы, жмите F2 для переименования, Ctrl/⌘ Space для автодополнения:
Сохраните файл и запустите:
archlang validate .Ошибок быть не должно. Откройте каталог в редакторе (с установленным расширением Archlang) и вызовите панель встроенного предпросмотра — появятся три коробки, пока ни с чем не связанные. Это ожидаемо — мы не сказали, как они взаимодействуют.
Диаграмма выглядит просто, потому что у базового вида module нет специализированного отображения. Коробки подписаны именами; один общий виджет для всех трёх. Стандартная библиотека вводит виджеты под каждый вид (Глава 11); в этой главе суть в простых коробках — они делают лежащую под ними структуру очевидной.
Процесс
Добавьте checkout.arch:
process Checkout { Customer > Payments.Authorize Payments > Ledger.Record Customer > Payments.Capture Payments > Ledger.Record}Процесс — последовательность шагов. Каждый шаг имеет форму Вызывающий > Принимающий.Интерфейс:
- Вызывающий (слева от
>) — модуль, делающий вызов. - Принимающий (справа от
>) — интерфейс, конкретная вызываемая операция.
Сохраните — предпросмотр обновится. У диаграммы теперь есть стрелки. Их не рисовали — они выведены из процесса. Это первый принцип из предисловия в действии: поведение — источник структуры.
Сдвиг мышления. В большинстве инструментов диаграмм вы рисуете стрелку, потому что два сервиса общаются. В Archlang вы объявляете шаг процесса; стрелка появляется, потому что что-то объявило, что общается. Удалите шаг — стрелка исчезнет. Добавьте ещё шаг — появится новая стрелка. Граф зависимостей — всегда функция поведения.
Изменение
Откройте payments.arch и добавьте четвёртый интерфейс:
module Payments { team: Platform "Авторизует и проводит карточные платежи."
interface Authorize interface Capture interface Refund interface Void // новый}Сохраните. Предпросмотр обновится. Void появляется в узле Payments; стрелок к нему нет, потому что ни один процесс пока его не вызывает.
Теперь откройте checkout.arch и добавьте шаг:
process Checkout { Customer > Payments.Authorize Payments > Ledger.Record Customer > Payments.Capture Payments > Ledger.Record Customer > Payments.Void // новый — клиент отменяет посреди оплаты}Сохраните. Предпросмотр снова обновится. К Void теперь идёт стрелка.
Вы добавили интерфейс и шаг процесса в две правки, и диаграмма последовала за вами. Не надо переделывать схему, не надо двигать коробки.
Что вы построили
shop/├── package.archspace├── payments.arch└── checkout.archТри файла, три модуля, один процесс. Полная (хоть и минимальная) архитектура, написанная на чистом базовом языке. Каждая диаграмма, каждая стрелка зависимости, каждый анализ влияния, который Archlang может для вас сделать, выводится из этих файлов.
Сводка
- Рабочее пространство начинается с манифеста
package.archspace, называющего пакет. - Базовых видов
moduleиinterfaceхватает для моделирования структуры и выставленных наружу операций. - Процессы — последовательности шагов
Вызывающий > Принимающий.Интерфейс. Стрелки в диаграммах выводятся из процессов — они не рисуются напрямую. - Предпросмотр редактора перерендеривается на сохранение. Цикл разработки: править файл → видеть диаграмму.
Что дальше
Глава 3: Чтение диффа → — внести изменение в архитектуру и посмотреть, как Archlang показывает, что изменилось.