2. Ваша первая архитектура
Эта глава ведёт через построение полной (маленькой) архитектуры из пустого каталога. К концу у вас будет три модуля, один процесс, связывающий их, диаграмма и ощущение формы языка.
Мы будем использовать только базовый язык — базовые типы module, surface, interface плюс конструкции верхнего уровня process и view — без стандартной библиотеки. Дальнейшие главы вводят более богатые типы (service, command, event); Глава 11 подробно их разбирает. Старт с базовым языком держит фокус на том, что делает сам язык, отдельно от соглашений.
Смоделируем платёжный домен: клиент платит, платёжный сервис авторизует, реестр записывает. И больше ничего.
Каждый проект начинается с манифеста. Создайте package.archspace:
package: shopОдна строка. Поле package: называет корень пакета; стандартную библиотеку пока не импортируем, потому что используем только базовые типы. (Имена пакетов — в нижнем регистре, через точку; для одного проекта голого shop достаточно.)
Глава 12 подробно разбирает манифест. Пока хватит этого.
Три модуля
Заголовок раздела «Три модуля»Добавьте payments.arch в тот же каталог:
module Payments { aspect team: "Platform" "Authorizes and captures card payments."
interface authorize interface capture interface refund}
module Ledger { aspect team: "Finance" "Immutable financial record of every transaction."
interface record}
module Customer { "The person initiating the payment."}Вы объявили три модуля базовым типом module. У каждого есть:
- Тип (
module) — базовый тип языка. - Имя (
Payments,Ledger,Customer) — как остальная часть модели на него ссылается. Имена модулей — вUpperCamelCase. - Аспект team — кто им владеет (необязательно; аспекты каскадируют на всё вложенное, с возможностью переопределения).
- Описание — голый строковый литерал. Обычный markdown плюс два расширения, с которыми вы познакомитесь в Главе 10.
- Ноль или больше интерфейсов —
interface authorizeи т. д. Это то, что другие модули могут попросить этот сделать. Имена интерфейсов — вlowerCamelCaseи читаются как реальная операция: глагол для RPC-вызова (authorize), действие-плюс-ресурс для REST (подробнее в Главе 5).
У Customer интерфейсов нет. Это нормально — не каждый модуль выставляет операции наружу. (Типы стандартной библиотеки добавляют семантические различия вроде user для сущностей, которые только инициируют вызовы; пока всё — просто module.)
Мы не садились и не спрашивали «что с чем соединяется». Мы описали каждый модуль сам по себе — чем он является, что он умеет — и остановились. Соединения приходят позже, и они выпадают из процесса, а не рисуются. Эта привычка в два прохода (описать состав, затем рассказать историю) — основа авторской работы в ArchLang.
Попробуйте вживую — отредактируйте исходник выше, диаграмма обновится ниже. Наводитесь на идентификаторы, жмите F2 для переименования, Ctrl/⌘ Space для автодополнения:
Сохраните файл и запустите:
archlang validate .Ошибок быть не должно. Откройте каталог в редакторе (с установленным расширением ArchLang) и вызовите панель встроенного предпросмотра — появятся три коробки, пока ни с чем не связанные. Это ожидаемо — мы не сказали, как они взаимодействуют.
Диаграмма выглядит просто, потому что у базового типа module нет специализированного отображения. Коробки подписаны именами; один общий виджет для всех трёх. Стандартная библиотека вводит виджеты под каждый тип (Глава 11); в этой главе суть в простых коробках — они делают лежащую под ними структуру очевидной.
Процесс
Заголовок раздела «Процесс»Добавьте checkout.arch:
process Checkout { Customer > Payments.authorize Payments > Ledger.record Customer > Payments.capture Payments > Ledger.record}Процесс — последовательность шагов. Каждый шаг имеет форму Caller > Callee.Interface:
- Вызывающий (слева от
>) — модуль, делающий вызов. - Принимающий (справа от
>) — интерфейс, конкретная вызываемая операция.
Сохраните — предпросмотр обновится. У диаграммы теперь есть стрелки. Их не рисовали — они выведены из процесса. Это первый принцип из предисловия в действии: поведение — источник структуры.
Сдвиг мышления. В большинстве инструментов диаграмм вы рисуете стрелку, потому что два сервиса общаются. В ArchLang вы объявляете шаг процесса; стрелка появляется, потому что что-то объявило, что общается. Удалите шаг — стрелка исчезнет. Добавьте ещё шаг — появится новая стрелка. Граф зависимостей — всегда функция поведения.
Изменение
Заголовок раздела «Изменение»Откройте payments.arch и добавьте четвёртый интерфейс:
module Payments { aspect team: "Platform" "Authorizes and captures card payments."
interface authorize interface capture interface refund interface void // new}Сохраните. Предпросмотр обновится. void появляется в узле Payments; стрелок к нему нет, потому что ни один процесс пока его не вызывает.
Теперь откройте checkout.arch и добавьте шаг:
process Checkout { Customer > Payments.authorize Payments > Ledger.record Customer > Payments.capture Payments > Ledger.record Customer > Payments.void // new — customer cancels mid-checkout}Сохраните. Предпросмотр снова обновится. К void теперь идёт стрелка.
Вы добавили интерфейс и шаг процесса в две правки, и диаграмма последовала за вами. Не надо переделывать схему, не надо двигать коробки.
Что вы построили
Заголовок раздела «Что вы построили»shop/├── package.archspace├── payments.arch└── checkout.archТри файла, три модуля, один процесс. Полная (хоть и минимальная) архитектура, написанная на чистом базовом языке. Каждая диаграмма, каждая стрелка зависимости, каждый анализ влияния, который ArchLang может для вас сделать, выводится из этих файлов.
- Рабочее пространство начинается с манифеста
package.archspace, называющего пакет. - Базовых типов
moduleиinterfaceхватает для моделирования структуры и выставленных наружу операций. - Процессы — последовательности шагов
Caller > Callee.Interface. Стрелки в диаграммах выводятся из процессов — они не рисуются напрямую. - Предпросмотр редактора перерендеривается на сохранение. Цикл разработки: править файл → видеть диаграмму.
Что дальше
Заголовок раздела «Что дальше»Глава 3: Чтение диффа → — внести изменение в архитектуру и посмотреть, как ArchLang показывает, что изменилось.