Перейти к содержимому

Привязки к исходному коду

Повторяющееся возражение против модели архитектуры — справедливое: откуда я знаю, что она всё ещё истинна? Диаграмма молча расходится с кодом, и к тому моменту, когда это кто-то замечает, ей уже никто не доверяет настолько, чтобы чинить.

Ответ ArchLang — не генерировать модель из кода: Глава 30 объясняет, почему выведенная архитектура это картинка ваших импортов, а не вашего замысла. Ответ это ссылка на свидетельство. Модуль называет диапазоны файлов, которые о нём свидетельствуют, а хост, у которого есть репозиторий, может проверить, что эта ссылка всё ещё верна.

Модель утверждает. Репозиторий свидетельствует. Из кода не выводится ничего.

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.shop
version: "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 ./architecture --repo=../shop
https://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_COMMITcommit: называет ветку или тег
EVIDENCE_UNVERIFIEDзакреплённый коммит не удалось прочитать
EVIDENCE_ORIGIN_MISMATCHorigin рабочей копии не совпадает с заявленным репозиторием
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-файлы.