- META-20: норму можно исполнить, имея один файл; на чужую тему смотрят только «Почему», «Связано» и разграничение области — подписка это произвольное подмножество, графа зависимостей нет по построению - META-21: ссылка ведёт на имя темы или идентификатор правила; путь файла канона умирает при сборке, потому что слои темы становятся секциями
16 KiB
Язык конвенций
Как записываются правила в этом каноне. Документ описывает форму, а не содержание: что такое правило, чем оно отличается от прозы вокруг и как на него сослаться.
Форма подсмотрена у OpenSpec, но взято оттуда не всё — см. «Чего мы не берём».
Зачем формализовать
Не ради строгости. Три конкретные вещи, которые без адресуемых правил не работают:
- Механизация. Регион
механизированодолжен говорить «правилоMIGR-4проверяетarchrules», а не «AUTOINCREMENTв новых миграциях —archrules»: во втором случае читатель сам догадывается, к какому утверждению это относится, и догадывается по-разному. - Отступления. «У нас не так» бесполезно, пока не сказано, что именно «не так». Со ссылкой на правило отступления становятся счётными: видно, сколько правил конвенции репозиторий реально не соблюдает.
- Промоут находки. Путь «находка → конвенция → правило линтера → удаление прозы» требует ручки, за которую берут конкретное правило.
Общий знаменатель — идентификатор. Модальные слова и таблицы полезны, но вторичны.
Единица — правило
### KEYS-5. Разбор внешнего идентификатора на границе
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
к базе.
**Почему.** Разбор валидирует формат и нормализует регистр. Сравнение строк
в базе побайтовое, поэтому без нормализации запрос молча не находит
существующую запись — отладка такого случая стоит дороже, чем сам разбор.
Четыре обязательные части: идентификатор, заголовок, модальность с нормой, почему. Норма — одна фраза; если в неё не влезает, это два правила.
Правило без «почему» не принимается
Это жёсткое требование к форме, а не пожелание. Причины:
- «Почему» — единственный способ понять, когда правило перестало действовать. Норма стареет молча; обоснование стареет заметно. Когда причина отпала, видно, что правило пора убрать, а не соблюдать по инерции.
- Правило без обоснования не переживает спор. Через год ни автор, ни агент не восстановят мотив, и правило будет либо отменено первым же возражением, либо соблюдено там, где вредит.
- Формулировка «почему» — проверка на то, что это вообще правило. Если причина не формулируется, перед нами привычка или вкусовщина; ей место в черновиках, а не в конвенции.
«Почему» отвечает на «что сломается, если сделать иначе», а не пересказывает норму другими словами. «Потому что так принято» — не обоснование.
Модальные слова
Пишутся капсом — это ключевые слова, а не обычный текст.
| Слово | Значение | Отступление |
|---|---|---|
| ДОЛЖЕН | нарушение считается ошибкой | только с записью в регион отступления |
| НЕ ДОЛЖЕН | запрет | то же |
| СЛЕДУЕТ | сильная рекомендация; новый код пишем так | допустимо, причину записываем |
| НЕ СЛЕДУЕТ | обратное к СЛЕДУЕТ | то же |
| ДОПУСКАЕТСЯ | явное разрешение | не требуется — правило ничего не запрещает |
ДОПУСКАЕТСЯ нужно не для симметрии: оно снимает вопрос «а так можно?» там, где соседнее правило звучит строго и его легко перечитать шире, чем задумано.
Модальность живёт на правиле, а не на файле. Прежний файловый статус
(status: рекомендуемая / обязательная в шапке) отменён: он неизбежно
врал, потому что один файл смешивает жёсткие требования с советами. В шапке
остаются только prefix, extends и служебные ключи копии.
Мы не используем SHALL и прочие английские ключевые слова. Они заняты спецификациями (OpenSpec), и общий словарь стирал бы границу «конвенция — не capability». Разный словарь эту границу держит бесплатно.
Идентификаторы
- Формат —
<ПРЕФИКС>-<номер>:KEYS-5,SLOG-27. Префикс принадлежит файлу, нумерация внутри файла сквозная и начинается с единицы. - Строка таблицы, если на неё нужно ссылаться отдельно, —
KEYS-5.1,KEYS-5.2. - Идентификатор глобален. Префикс уникален по всему канону, поэтому
путь файла в ссылке не нужен:
KEYS-5адресует правило одинаково изнутри файла, из соседней конвенции и из чужого репозитория. В собранной копии слои разных осей лежат в одном документе, так что ссылка на базовый слой из языкового вообще никуда не ведёт — правило рядом. - Идентификаторы стабильны и не переиспользуются. Удалённое правило
оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из
чужого репозитория начнёт указывать на другое утверждение. То же
относится к префиксам: выбывшие хранит
prefixes.toml. - Префикс выбирается под файл, а не выводится по формуле: он нужен, чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок привязал бы идентификатор к таксономии, которую канон перестраивает, и упёрся бы в потолок из числа букв алфавита.
- Перенос правила в другой файл — смысловое изменение, а не переименование: новый файл означает новый префикс и новую нумерацию. Переезд самого файла между осями идентификаторы не трогает.
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это идентификатор, а не позиция.
Правило, чья норма уехала в линтер
Когда правило механизировано у всех потребителей, его норма из канона удаляется, а обоснование — нет. Остаётся правило без модальности, и чтобы оно не выглядело недописанным, место нормы занимает отметка:
### MIGR-6. Дефолтов времени в схеме БД нет
**МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера; формулировка
удалена, потому что дублировала работающую проверку.
**Почему.** Дефолт превращает забытую вставку в тихо работающий код…
- Идентификатор и заголовок сохраняются: ссылки из репозиториев продолжают указывать на то же утверждение.
- «Почему» остаётся навсегда — линтер сообщает, что нарушено, но не сообщает, зачем правило существует, и без обоснования нельзя понять, когда проверку пора отменять.
- МЕХАНИЗИРОВАНО — не шестое модальное слово: оно не задаёт обязательность, а сообщает, что обязательность теперь обеспечена машиной. В остальном такое правило равно ДОЛЖЕН.
Факт «механизировано у всех» устанавливается вручную: канон по построению не знает списка подписчиков, и обойти репозитории перед удалением нормы — часть работы, а не то, что можно проверить автоматически.
Таблицы вместо сценариев
Часть правил классифицирует ситуации: какой уровень лога, какая категория директории, что делать с невалидным вводом в зависимости от его источника. Для них каноническая форма — таблица «ситуация → вердикт», строки которой при необходимости нумеруются.
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а неупомянутый случай в абзаце — нет.
Чего мы не берём из OpenSpec
GIVEN/WHEN/THEN. У спецификации субъект — система, и её поведение разворачивается во времени: состояние, событие, исход. У конвенции субъект — автор кода, и разворачивать нечего: есть ситуация выбора и вердикт. Это таблица, а не траектория.
SHALL. См. выше про словарь.
Сценарии как общая форма. Прозаический сценарий остаётся точечным инструментом — для стыка правил, когда два правила вместе дают неочевидный результат:
WHEN зависимость недоступна и ретраи вызова исчерпаны → ext-запись ERROR
AND тик фонового цикла упал по той же причине → доменная запись WARN
Такой блок ставится после обоих правил и ссылается на их номера. Если стыков нет — сценариев в файле нет.
Что правилом не является
Модальные слова в этих частях не употребляются — иначе перестанет быть понятно, что адресуемо, а что нет:
- Область действия — на что конвенция распространяется во времени («новые таблицы; существующие не переписываются»). Это рамка для всех правил файла, а не правило.
- Связано — ссылки на смежные конвенции, ADR, код.
- Локальные регионы — содержимое принадлежит репозиторию.
- Вводная проза, объясняющая предмет конвенции.
Как на правила ссылаются копии
В репозитории:
<!-- local:механизировано -->
MIGR-2, MIGR-4 — `internal/archrules` (проверяются в новых миграциях).
<!-- /local -->
<!-- local:отступления -->
MIGR-6 — не соблюдается в легаси-таблицах `show_history`, `queue`: составные
ключи там появились до конвенции, переписывание требует миграции данных.
<!-- /local -->
Отсюда видно и то, чего раньше не было видно: конвенция из восьми правил, из которых два механизированы и одно не соблюдается.
Что стоит проверять машиной
Сейчас не реализовано; список — на будущее для conv:
- префикс в шапке файла совпадает с реестром, состоит из четырёх заглавных латинских букв и не значится в списке выбывших;
- заголовки правил файла используют только его собственный префикс;
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило берёт следующий свободный, а не первый освободившийся);
- у каждого
### <ПРЕФИКС>-<n>есть модальное слово (или отметка МЕХАНИЗИРОВАНО) и блок «Почему»; - ссылки вида
<ПРЕФИКС>-<n>— хоть в тексте канона, хоть в локальных регионах копии — указывают на правила, которые ещё существуют; - чужой префикс не встречается в абзаце с модальностью (META-20);
- путь файла канона не встречается в тексте конвенции (META-21);
- модальные слова не встречаются вне правил.
Порядок перевода
Все конвенции канона записаны на этом языке. Новая конвенция пишется на нём сразу; смешение форм в каноне больше не предполагается.