- правило = номер + модальность (ДОЛЖЕН / СЛЕДУЕТ / ДОПУСКАЕТСЯ) плюс обязательный блок «Почему»; из OpenSpec взяты идентификаторы правил, но не SHALL и не GIVEN/WHEN/THEN - файловый статус отменён: обязательность живёт на правиле, а в шапке ещё не переведённых конвенций ключ остаётся меткой «это проза»
12 KiB
Язык конвенций
Как записываются правила в этом каноне. Документ описывает форму, а не содержание: что такое правило, чем оно отличается от прозы вокруг и как на него сослаться.
Форма подсмотрена у OpenSpec, но взято оттуда не всё — см. «Чего мы не берём».
Зачем формализовать
Не ради строгости. Три конкретные вещи, которые без адресуемых правил не работают:
- Механизация. Регион
механизированодолжен говорить «правило R4 проверяетarchrules», а не «AUTOINCREMENTв новых миграциях —archrules»: во втором случае читатель сам догадывается, к какому утверждению это относится, и догадывается по-разному. - Отступления. «У нас не так» бесполезно, пока не сказано, что именно «не так». Со ссылкой на правило отступления становятся счётными: видно, сколько правил конвенции репозиторий реально не соблюдает.
- Промоут находки. Путь «находка → конвенция → правило линтера → удаление прозы» требует ручки, за которую берут конкретное правило.
Общий знаменатель — идентификатор. Модальные слова и таблицы полезны, но вторичны.
Единица — правило
### R5. Разбор внешнего идентификатора на границе
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
к базе.
**Почему.** Разбор валидирует формат и нормализует регистр. Сравнение строк
в базе побайтовое, поэтому без нормализации запрос молча не находит
существующую запись — отладка такого случая стоит дороже, чем сам разбор.
Четыре обязательные части: номер, заголовок, модальность с нормой, почему. Норма — одна фраза; если в неё не влезает, это два правила.
Правило без «почему» не принимается
Это жёсткое требование к форме, а не пожелание. Причины:
- «Почему» — единственный способ понять, когда правило перестало действовать. Норма стареет молча; обоснование стареет заметно. Когда причина отпала, видно, что правило пора убрать, а не соблюдать по инерции.
- Правило без обоснования не переживает спор. Через год ни автор, ни агент не восстановят мотив, и правило будет либо отменено первым же возражением, либо соблюдено там, где вредит.
- Формулировка «почему» — проверка на то, что это вообще правило. Если причина не формулируется, перед нами привычка или вкусовщина; ей место в черновиках, а не в конвенции.
«Почему» отвечает на «что сломается, если сделать иначе», а не пересказывает норму другими словами. «Потому что так принято» — не обоснование.
Модальные слова
Пишутся капсом — это ключевые слова, а не обычный текст.
| Слово | Значение | Отступление |
|---|---|---|
| ДОЛЖЕН | нарушение считается ошибкой | только с записью в регион отступления |
| НЕ ДОЛЖЕН | запрет | то же |
| СЛЕДУЕТ | сильная рекомендация; новый код пишем так | допустимо, причину записываем |
| НЕ СЛЕДУЕТ | обратное к СЛЕДУЕТ | то же |
| ДОПУСКАЕТСЯ | явное разрешение | не требуется — правило ничего не запрещает |
ДОПУСКАЕТСЯ нужно не для симметрии: оно снимает вопрос «а так можно?» там, где соседнее правило звучит строго и его легко перечитать шире, чем задумано.
Модальность живёт на правиле, а не на файле. Прежний файловый статус
(status: рекомендуемая / обязательная в шапке) отменён: он неизбежно
врал, потому что один файл смешивает жёсткие требования с советами. В ещё
не переведённых конвенциях ключ остаётся как метка «этот файл — проза», без
нормативного значения, и исчезает при переводе.
Мы не используем SHALL и прочие английские ключевые слова. Они заняты спецификациями (OpenSpec), и общий словарь стирал бы границу «конвенция — не capability». Разный словарь эту границу держит бесплатно.
Идентификаторы
- Формат —
R<номер>, сквозная нумерация внутри файла, начиная сR1. - Строка таблицы, если на неё нужно ссылаться отдельно, —
R5.1,R5.2. - Номера стабильны и не переиспользуются. Удалённое правило оставляет дыру в нумерации; занимать её новым правилом нельзя — иначе ссылка из чужого репозитория начнёт указывать на другое утверждение.
- Глобальный адрес — путь файла плюс номер:
arch/db-identifiers.md R5. В пределах одного файла достаточноR5.
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это идентификатор, а не позиция.
Таблицы вместо сценариев
Часть правил классифицирует ситуации: какой уровень лога, какая категория директории, что делать с невалидным вводом в зависимости от его источника. Для них каноническая форма — таблица «ситуация → вердикт», строки которой при необходимости нумеруются.
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а неупомянутый случай в абзаце — нет.
Чего мы не берём из OpenSpec
GIVEN/WHEN/THEN. У спецификации субъект — система, и её поведение разворачивается во времени: состояние, событие, исход. У конвенции субъект — автор кода, и разворачивать нечего: есть ситуация выбора и вердикт. Это таблица, а не траектория.
SHALL. См. выше про словарь.
Сценарии как общая форма. Прозаический сценарий остаётся точечным инструментом — для стыка правил, когда два правила вместе дают неочевидный результат:
WHEN зависимость недоступна и ретраи вызова исчерпаны → ext-запись ERROR
AND тик фонового цикла упал по той же причине → доменная запись WARN
Такой блок ставится после обоих правил и ссылается на их номера. Если стыков нет — сценариев в файле нет.
Что правилом не является
Модальные слова в этих частях не употребляются — иначе перестанет быть понятно, что адресуемо, а что нет:
- Область действия — на что конвенция распространяется во времени («новые таблицы; существующие не переписываются»). Это рамка для всех правил файла, а не правило.
- Связано — ссылки на смежные конвенции, ADR, код.
- Локальные регионы — содержимое принадлежит репозиторию.
- Вводная проза, объясняющая предмет конвенции.
Как на правила ссылаются копии
В репозитории:
<!-- local:механизировано -->
R2, R4 — `internal/archrules` (проверяются в новых миграциях).
<!-- /local -->
<!-- local:отступления -->
R6 — не соблюдается в легаси-таблицах `show_history`, `queue`: составные
ключи там появились до конвенции, переписывание требует миграции данных.
<!-- /local -->
Отсюда видно и то, чего раньше не было видно: конвенция из восьми правил, из которых два механизированы и одно не соблюдается.
Что стоит проверять машиной
Сейчас не реализовано; список — на будущее для conv:
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило берёт следующий свободный, а не первый освободившийся);
- у каждого
### R<n>есть модальное слово и блок «Почему»; - ссылки вида
R<n>в локальных регионах копии указывают на правила, которые в каноне ещё существуют; - модальные слова не встречаются вне правил.
Порядок перевода
Конвенции переводятся на этот язык по мере касания, а не кампанией. Смешение форм в каноне допустимо: пока файл не тронут, он остаётся прозой со статусом в шапке.
Сейчас на формальном языке записаны arch/db-identifiers.md и
stack/ansible/app-directories.md.