Привязки к исходному коду
Повторяющееся возражение против модели архитектуры — справедливое: откуда я знаю, что она всё ещё истинна? Диаграмма молча расходится с кодом, и к тому моменту, когда это кто-то замечает, ей уже никто не доверяет настолько, чтобы чинить.
Ответ ArchLang — не генерировать модель из кода: Глава 30 объясняет, почему выведенная архитектура это картинка ваших импортов, а не вашего замысла. Ответ это ссылка на свидетельство. Модуль называет диапазоны файлов, которые о нём свидетельствуют, а хост, у которого есть репозиторий, может проверить, что эта ссылка всё ещё верна.
Модель утверждает. Репозиторий свидетельствует. Из кода не выводится ничего.
sources: это обычное поле
Заголовок раздела «sources: это обычное поле»module Checkout { sources: "src/checkout/index.ts:12-88", "src/checkout/tax.ts:5-40"}Никакой новой конструкции здесь нет, и это намеренно. sources это общеизвестное поле (Глава 9), как latency: обычные структурированные данные, которые интерпретирует конкретный инструмент. Поэтому всё, что вы уже знаете о полях, работает без изменений:
- уточнение и
overrideна уровне типа или экземпляра (Глава 19), - распространение
cascade/append(Глава 18), - слияние по блокам-расширениям
in <Module> { … }, - и поле уходит по проводу — JSON-экспорт, просмотрщик, дифф — без изменений сериализатора.
Запись имеет одну из трёх форм, относительно корня репозитория:
| Форма | Значит |
|---|---|
"src/tax.ts" | весь файл |
"src/tax.ts:40" | одна строка |
"src/tax.ts:12-88" | диапазон строк, нумерация с 1, границы включительно |
Закрепление задаётся на уровне пакета
Заголовок раздела «Закрепление задаётся на уровне пакета»Путь сам по себе свидетельствует, что файл когда-то существовал. Чтобы засвидетельствовать, что модель истинна относительно ревизии, репозиторий и коммит закрепляются в package.archspace — рядом с version: и widgets: (Глава 12):
package: acme.shopversion: "1.4.0"
repo: "https://github.com/acme/shop"commit: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"commit: обязателен всегда, когда задан repo:. Закрепление на уровне пакета — вместо того чтобы писать репозиторий рядом с каждой привязкой — это то, что оставляет голый путь однозначным при любом числе зависимостей у пакета.
commit:, называющий ветку или тег, всё равно проверяется, но вызывает предупреждение: ветка движется, поэтому «подтверждено» было бы утверждением о том, куда она указывает сегодня, а не о фиксированной ревизии.
Вердикты трёхзначны
Заголовок раздела «Вердикты трёхзначны»| Вердикт | Значит |
|---|---|
verified | путь это blob на закреплённом коммите, и диапазон помещается внутрь него |
broken | ссылка больше не верна — файла нет, диапазон выходит за конец файла, или запись не разбирается |
unverified | проверить было нечем — нет репозитория, нет закрепления, или репозиторий не тот |
unverified никогда не считается успехом. Непроверенная ссылка никогда не показывается как проверенная, и доска вообще не рисует для неё бейдж: узел, который просмотрщик не смог проверить, обязан выглядеть ровно как узел, который ни на что не ссылается. Инспектор в обоих случаях перечисляет ссылки, поэтому читатель отличает «свидетельств нет» от «свидетельства есть, но не проверены».
Ссылка, которая не разбирается, считается broken, а не просто непроверенной. Нечитаемый диапазон иначе проходил бы любую проверку границ вхолостую, а это единственный способ для ссылки заявить больше, чем она доказывает.
То, что проверяет хост, механично: путь это blob на закреплённом коммите, диапазон помещается внутрь этого blob, а origin рабочей копии совпадает с заявленным репозиторием. Действительно ли код в этих строках и есть этот модуль — суждение ревьюера, и вердикт это вход для такого суждения, а не его замена.
Проверка — archlang evidence
Заголовок раздела «Проверка — archlang evidence»archlang evidence ./architecture --repo=../shophttps://github.com/acme/shop @ a1b2c3d ✓ Checkout src/checkout/index.ts:12-88 ✗ Checkout src/checkout/tax.ts:5-40 · Ledger src/ledger.ts
warning: 'Checkout' ссылается на 'src/checkout/tax.ts' до строки 40, но на закреплённом коммите длина файла — 22 строк.
1 verified, 1 broken, 1 unverifiedНенулевой код возврата бывает только при broken. Привязка, которую вообще не удалось проверить — нет репозитория, нет закрепления, не тот репозиторий — сообщается как unverified и не проваливает запуск. Асимметрия намеренна: сломанная привязка это дефект, который автор может починить, а непроверяемая обычно означает, что у машины, где идёт проверка, просто нет репозитория. При этом unverified по-прежнему никогда не считается успехом, и ничто не показывает его как успех.
Свидетельства также одна из фаз объединённого gate, поэтому CI не нужен отдельный шаг:
archlang check ./architecture # validate + policy-check + format --check + evidenceВсе семь диагностик имеют серьёзность warning, и три репозиторного уровня подавляют пошаговый шум, который иначе бы возник:
| Код | Срабатывает, когда |
|---|---|
EVIDENCE_MALFORMED | запись не имеет вида path / path:line / path:start-end |
EVIDENCE_PIN_MISSING | привязки есть, но нет repo: или commit: |
EVIDENCE_PIN_NOT_A_COMMIT | commit: называет ветку или тег |
EVIDENCE_UNVERIFIED | закреплённый коммит не удалось прочитать |
EVIDENCE_ORIGIN_MISMATCH | origin рабочей копии не совпадает с заявленным репозиторием |
EVIDENCE_PATH_MISSING | указанного пути нет в репозитории на этом коммите |
EVIDENCE_RANGE_OUT_OF_FILE | диапазон выходит за конец файла |
Вердикту нужен хост, умеющий читать репозиторий
Заголовок раздела «Вердикту нужен хост, умеющий читать репозиторий»Движок не знает про git. Он проверяет снапшот, который ему передаёт хост, и ничего не выводит из содержимого этого снапшота:
archlang evidenceиarchlang checkдают снапшот для локальной рабочей копии (Глава 21).- Studio даёт его для репозитория, который читатель никогда не клонировал, потому что репозиторием уже владеет.
- Обычный просмотрщик не даёт ничего, поэтому ничего и не проверяется — и, по правилу выше, ничего не помечается бейджем.
Там, где вердикты есть, модуль помечается угловым бейджем. Он рисуется из одного составленного дерева сцены, поэтому живая доска и экспортированные SVG или PNG несут его одинаково, а ссылки в инспекторе ведут на закреплённый коммит.
Как писать ссылки, которые остаются верными
Заголовок раздела «Как писать ссылки, которые остаются верными»- Ссылайтесь на несущий диапазон, а не на каталог.
"src/checkout/"это не утверждение, которое можно осмысленно проверить;"src/checkout/index.ts:12-88"— можно. - Целый файл лучше протухшего диапазона. Диапазон, уезжающий на четыре строки, становится
brokenкаждую неделю. Если модуль и есть файл, ссылайтесь на файл. - Двигайте закрепление вместе с моделью. Именно
commit:делает ссылку утверждением о ревизии; протухшее закрепление проверяется по истории и незаметно перестаёт что-либо сообщать. - Ссылка читается и без репозитория. По одной строке ⌘F на ссылку, поэтому на вопрос «какой модуль претендует на этот файл?» можно ответить из одной только модели — в том числе имея на руках лишь
.arch-файлы.