- запрет слов обязательства в «Почему» был лишним по построению: правило о заглавных уже делает строчное «обязан» ненормативным, так что второй копии нормы не возникает, а цена — автор воюет со списком слов вместо объяснения - в LANGUAGE записано прямо: рамки у обоснования только смысловые, длина, рассуждение, примеры и ссылки на внешние практики и чужие проекты допустимы - заведён раздел «Освободившиеся номера»: META-16 и META-26 с причинами. Без такого списка упоминание номера в прозе не отличить от ссылки на исчезнувшее правило — это же нужно будущей проверке ссылок
33 KiB
version
| version |
|---|
| 1 |
Язык конвенций
Формальный язык, на котором записаны правила этого канона: что считается правилом, чем оно отличается от прозы вокруг, какими словами задаётся обязательность и как на правило сослаться извне.
Версия языка — 1. Номер называется в каждой конвенции: словарь может пополниться, и текст, написанный по предыдущей версии, должен читаться по той, по которой написан.
Опора на стандарты
Язык не выводится из вкуса автора. Каждое решение о форме взято из документа, где эта задача уже решена и обкатана, и отклонения от источника названы явно.
| Источник | Что взято | Что отклонено |
|---|---|---|
| BCP 14 (RFC 2119 + RFC 8174) | шкала модальности; правило «нормативно только заглавное»; сдержанность в высшей модальности; англоязычный словарь как готовый | синонимы REQUIRED, RECOMMENDED, OPTIONAL; SHALL как форма требования |
| ISO/IEC Directives, Part 2 | разделение «требование — рекомендация — разрешение — возможность»; запрет модальных глаголов в утверждениях о факте | списки равнозначных словесных форм («is to», «is required to», «only … is permitted») |
| ISO/IEC/IEEE 29148 | обоснование как обязательный атрибут; единичность нормы; проверяемость; метод верификации отдельным атрибутом | остальной аппарат требований: приоритеты, источники, матрицы трассируемости |
| DMN | таблица решений с объявленной политикой совпадения и требованием полноты | исполняемая семантика и всё, что предполагает движок решений |
| EARS | вывод о том, что выигрыш даёт жёсткий шаблон, а не его конкретный вид; паттерн «нежелательное поведение» — в виде таблицы | шаблоны как форма записи правила: WHEN, WHILE, WHERE |
| OpenSpec | четырёхчастная форма правила; адресуемость правила идентификатором; форма «условие → следствие» для стыка правил | SHALL; GIVEN/WHEN/THEN как общая форма записи |
Три отклонения стоят объяснения, потому что выглядят как произвол.
Синонимов нет. BCP 14 держит REQUIRED рядом с MUST и OPTIONAL
рядом с MAY ради читаемости английской прозы. Одна форма записи на ступень
означает, что проверка «модальное слово употреблено вне правила» становится
перечислением, а не разбором синонимических рядов.
SHALL не используется ни в каком словаре этого языка. Слово занято
спецификациями (OpenSpec), и общая с ними форма стирала бы границу между
конвенцией и описанием поведения системы: SHALL в конвенции читался бы как
контракт, которого конвенция не даёт. Для англоязычного словаря это означает
выбор в пользу MUST из BCP 14, а не shall из ISO/IEC Directives.
GIVEN/WHEN/THEN не берётся как общая форма. У спецификации субъект —
система, и её поведение разворачивается во времени: состояние, событие,
исход. У конвенции субъект — автор кода, и разворачивать нечего: есть
ситуация выбора и вердикт. Это таблица, а не траектория. Тем же рассуждением
отклонены шаблоны EARS как форма записи правила, а взят из EARS другой
результат: измеримый выигрыш дала там сама обязательность шаблона, а не его
конкретная форма.
Исключение — стык правил, где субъект действительно система: там форма «условие → следствие» берётся сознательно, вместе со служебными словами под неё. Это единственное место, и оно описано в «Таблицах решений».
Что даёт формализация
Адресуемое правило — не украшение формы, а условие работы трёх механизмов:
- Механизация. Запись о ней должна говорить «правило
MIGR-4проверяетarchrules», а не «AUTOINCREMENTв новых миграциях —archrules»: во втором случае читатель сам догадывается, к какому утверждению это относится, и догадывается по-разному. - Отступления. «У нас не так» бесполезно, пока не сказано, что именно «не так». Со ссылкой на правило отступления становятся счётными: видно, сколько правил конвенции репозиторий реально не соблюдает.
- Промоут находки. Путь «находка → конвенция → правило линтера → удаление прозы» требует ручки, за которую берут конкретное правило.
Общий знаменатель — идентификатор. Модальные слова и таблицы полезны, но вторичны.
Единица — правило
### KEYS-5. Разбор внешнего идентификатора на границе
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
к базе.
**Почему.** Разбор валидирует формат и нормализует регистр. Сравнение строк
в базе побайтовое, поэтому без нормализации запрос молча не находит
существующую запись — отладка такого случая стоит дороже, чем сам разбор.
Четыре обязательные части: идентификатор, заголовок, модальность с нормой, обоснование. Норма — одна фраза; если в неё не влезает, это два правила. Требование единичности взято из ISO/IEC/IEEE 29148: составная норма не проверяема целиком, и нарушение одной её половины нечем адресовать.
Обоснование обязательно
Правило без блока «Почему» не принимается. Это требование к форме, а не пожелание; в 29148 обоснование — атрибут требования наравне с самим требованием, и по тем же причинам:
- Обоснование — единственный способ увидеть, что правило устарело. Норма стареет молча; причина стареет заметно. Когда причина отпала, видно, что правило пора убрать, а не соблюдать по инерции.
- Правило без обоснования не переживает спор. Через год ни автор, ни агент не восстановят мотив, и правило будет либо отменено первым же возражением, либо соблюдено там, где вредит.
- Формулировка обоснования — проверка на то, что это вообще правило. Если причина не формулируется, перед нами привычка или вкусовщина; ей место в черновиках, а не в конвенции.
«Почему» отвечает на «что сломается, если сделать иначе», а не пересказывает норму другими словами. «Потому что так принято» — не обоснование.
Форма обоснования при этом ничем не ограничена: рамки здесь только смысловые. Абзац может быть длинным, вести рассуждение, приводить пример, ссылаться на внешние практики, стандарты и чужие проекты — канон это уже делает («адаптация OpenTelemetry», «как по умолчанию в zap и zerolog», двенадцатишаговая процедура SQLite). Запрещённых слов и обязательной структуры у обоснования нет, и заводить их не нужно: обязательность несёт норма, а обоснование её объясняет — путаницу между этими двумя ролями исключает правило о заглавных.
Модальные слова
Инвариант языка — шкала: пять ступеней в четырёх категориях ISO/IEC Directives, Part 2, по одной форме записи на ступень, заглавными. Какими словами ступени названы — параметр естественного языка набора, а не часть языка конвенций. Этот канон написан по-русски и несёт русский словарь.
Пишутся заглавными — это ключевые слова, а не обычный текст.
| Слово | Категория | Значение | Отступление |
|---|---|---|---|
| ДОЛЖЕН | требование | нарушение считается ошибкой | только с записью в отступления |
| НЕ ДОЛЖЕН | требование | запрет | то же |
| СЛЕДУЕТ | рекомендация | сильная рекомендация; новый код пишем так | допустимо, причину записываем |
| НЕ СЛЕДУЕТ | рекомендация | обратное к СЛЕДУЕТ | то же |
| ДОПУСКАЕТСЯ | разрешение | выбор за автором кода; возражение на ревью не принимается | не требуется — правило ничего не запрещает |
Нормативно только заглавное написание. Это правило RFC 8174, и оно здесь по той же причине, по которой понадобилось там: без него каждое строчное «должен» во вводной прозе становится предметом спора о том, норма это или речь. Строчное слово нормой не является никогда, поэтому проза свободна, а проверка «модальное слово вне правила» сводится к поиску заглавных форм.
Четвёртая категория ISO — возможность — ключевого слова не имеет. Утверждения о том, что бывает и что технически осуществимо, пишутся обычной прозой и модальных слов не несут. Модальное слово в таком утверждении превращает описание в норму, которую никто не собирался вводить.
ДОПУСКАЕТСЯ адресовано рецензенту. В BCP 14 у MAY есть вторая
половина, которую обычно не замечают: сторона, не выбравшая опцию, обязана
работать с той, что выбрала. В конвенции этому соответствует запрет
возражать: выбор, помеченный ДОПУСКАЕТСЯ, на ревью не обсуждается. Без этой
половины слово было бы удобством читателя, а не нормой, и не работало бы в
единственной точке, где у конвенции есть принуждение.
ДОЛЖЕН требует двух условий сразу:
- нарушение причиняет названный вред, а не расходится со вкусом — META-25, он же критерий BCP 14, где высшая модальность резервируется под то, что действительно ломается, и не употребляется для навязывания метода;
- норма проверяема машиной — META-6, иначе обязательность держится на внимании и обещает то, чего не делает.
Не выполнено первое — правилу место в СЛЕДУЕТ или нигде. Не выполнено второе — в СЛЕДУЕТ. Проверяемость сама по себе не повышает правило до ДОЛЖЕН: механически проверяемых мелочей больше, чем важных вещей, и безразборное повышение обесценивает шкалу быстрее, чем её отсутствие.
Модальность живёт на правиле, а не на файле. Файловый статус
(status: рекомендуемая / обязательная в шапке) не используется: он
неизбежно врёт, потому что один файл смешивает жёсткие требования с
советами. В шапке остаются только prefix и extends.
Словарь другого языка
Словарь набора — это два перечня: модальные слова и служебные слова
сценарного блока (КОГДА, ТОГДА, И, ИЛИ — см. «Таблицы решений»).
Требования к ним одни и те же.
Для английского готовый словарь модальных слов даёт BCP 14. Для любого другого языка слова берут из перевода стандарта, если он есть, или переводят сами: шкала и семантика ступеней при этом не меняются — меняется только запись.
| Ступень | Русский | Английский (BCP 14) |
|---|---|---|
| требование | ДОЛЖЕН | MUST |
| запрет | НЕ ДОЛЖЕН | MUST NOT |
| рекомендация | СЛЕДУЕТ | SHOULD |
| рекомендация против | НЕ СЛЕДУЕТ | SHOULD NOT |
| разрешение | ДОПУСКАЕТСЯ | MAY |
| отметка о способе проверки | МЕХАНИЗИРОВАНО | MECHANIZED |
Последняя строка стандартом не даётся ни в одном языке: способа проверки в шкале BCP 14 нет, слово подбирается под язык так же, как остальные.
Что требуется от любого словаря:
- одна форма на ступень. Синонимы отклонены не из аскетизма: проверка «модальное слово вне правила» перечисляет формы, и синонимический ряд превращает перечисление в разбор.
- слово заглавными не встречается в обычной прозе этого языка. Иначе правило «нормативно только заглавное» перестаёт спасать: проверка ловит оформление, а не модальность.
- словарь перечислен целиком в строке о версии языка. Читателю копии он известен из самого файла, без обращения к этому документу, — иначе конвенция в чужом репозитории теряет ключ к собственному тексту.
- словарь один на канон. Два словаря параллельно дают две формы записи одного требования и удваивают каждую проверку; выбор языка — свойство набора, а не отдельного файла.
Смена словаря версию языка не меняет: версия принадлежит шкале и правилам формы, а не буквам.
Ссылка на язык из конвенции
Каждая конвенция называет язык одной строкой во вводной прозе:
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и отметка МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
Слова в строке — из словаря того языка, на котором написан набор. Для англоязычного набора та же строка выглядит так:
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY and the mark MECHANIZED are to be interpreted as described in the conventions language, version 1, and only when written in capitals.
Форма скопирована у BCP 14, где та же задача решается тем же способом: спецификация не прикладывает к себе словарь и не указывает путь к нему, а называет документ и версию. Пути в этой строке нет намеренно — конвенция уезжает в чужой репозиторий, где путей канона не существует, а норму исполнить всё равно можно: строка сама перечисляет ключевые слова набора и сама несёт правило заглавных.
Обязательность и способ проверки — разные атрибуты
Механизация не входит в шкалу модальности: она говорит не о том, насколько правило обязательно, а о том, чем эта обязательность обеспечена. В 29148 это два разных атрибута требования, и здесь тоже два.
Когда правило механизировано у всех потребителей, его норма из канона удаляется, а модальность и обоснование остаются:
### MIGR-6. Дефолтов времени в схеме БД нет
**ДОЛЖЕН. МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера;
формулировка удалена, потому что дублировала работающую проверку.
**Почему.** Дефолт превращает забытую вставку в тихо работающий код…
- Идентификатор и заголовок сохраняются: ссылки из репозиториев продолжают указывать на то же утверждение.
- Модальность сохраняется, поэтому «все ли ДОЛЖЕН механизированы» остаётся вычислимым вопросом, а не предметом чтения всего канона.
- «Почему» остаётся навсегда — линтер сообщает, что нарушено, но не сообщает, зачем правило существует, и без обоснования нельзя понять, когда проверку пора отменять.
Факт «механизировано у всех» устанавливается вручную: канон по построению не знает списка подписчиков, и обойти репозитории перед удалением нормы — часть работы, а не то, что можно проверить автоматически.
Таблицы решений
Часть правил классифицирует ситуации: какой уровень лога, какая
категория директории, что делать с невалидным вводом в зависимости от его
источника. Каноническая форма для них — таблица «ситуация → вердикт», строки
которой нумеруются как подпункты правила (SLOG-8.1).
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а неупомянутый случай в абзаце — нет. Два свойства такой таблицы взяты из DMN, где они называются и проверяются:
- Политика совпадения. По умолчанию строки взаимоисключающи: любой ситуации соответствует ровно одна. Если это не так, таблица объявляет порядок строкой над собой — «применяется первое совпадение». Молчание об этом означает, что при двух подходящих строках читатель выбирает сам, и два автора выберут по-разному.
- Полнота. Перечислены все случаи, попадающие в область действия. Если возможен случай вне перечисленных, он назван отдельной строкой, а не оставлен на догадку.
Сценарный блок остаётся точечным инструментом — для стыка правил, когда два правила вместе дают неочевидный результат:
КОГДА зависимость недоступна И ретраи вызова исчерпаны
ТОГДА внешний вызов даёт запись ERROR,
И тик фонового цикла, упавший по той же причине, — запись WARN
Такой блок ставится после обоих правил и ссылается на их идентификаторы. Если стыков нет — сценариев в файле нет.
Форма «условие → следствие» здесь взята намеренно, хотя как общая форма записи она отклонена: на стыке правил субъект действительно система, и результат разворачивается во времени — то самое, для чего эта форма и придумана. Служебные слова блока перечислены ниже и подчиняются тем же требованиям, что модальные: одна форма на роль, заглавными, набор один на канон.
| Роль | Русский | Английский |
|---|---|---|
| условие | КОГДА | WHEN |
| следствие | ТОГДА | THEN |
| соединение | И | AND |
| выбор | ИЛИ | OR |
Модальными словами они не являются: обязательности не задают, только структуру. Поэтому в строку о версии языка они не попадают — там перечисляется то, чему нужно определение, а логическая связка читается сама, — и под проверку «модальные слова вне правил» не подпадают.
Идентификаторы
- Формат —
<ПРЕФИКС>-<номер>:KEYS-5,SLOG-27. Префикс принадлежит файлу, нумерация внутри файла сквозная и начинается с единицы. - Строка таблицы, если на неё нужно ссылаться отдельно, —
KEYS-5.1,KEYS-5.2. - Идентификатор глобален. Префикс уникален по всему канону, поэтому
путь файла в ссылке не нужен:
KEYS-5адресует правило одинаково изнутри файла, из соседней конвенции и из чужого репозитория. В собранной копии слои разных осей лежат в одном документе, так что ссылка на базовый слой из языкового вообще никуда не ведёт — правило рядом. - Идентификаторы стабильны и не переиспользуются. Удалённое правило
оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из
чужого репозитория начнёт указывать на другое утверждение. То же
относится к префиксам: выбывшие хранит
prefixes.toml. - Префикс выбирается под файл, а не выводится по формуле: он нужен, чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок привязал бы идентификатор к таксономии, которую канон перестраивает, и упёрся бы в потолок из числа букв алфавита.
- Префиксы на букву
Xканоном не занимаются: они принадлежат локальным правилам репозиториев-потребителей. - Перенос правила в другой файл — смысловое изменение, а не переименование: новый файл означает новый префикс и новую нумерацию. Переезд самого файла между осями идентификаторы не трогает.
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это идентификатор, а не позиция.
Что правилом не является
Заглавные модальные слова в этих частях не употребляются — иначе перестанет быть понятно, что адресуемо, а что нет:
- Область действия — на что конвенция распространяется во времени («новые таблицы; существующие не переписываются»). Это рамка для всех правил файла, а не правило.
- Связано — ссылки на смежные конвенции, ADR, код.
- Локальная часть копии — содержимое принадлежит репозиторию.
- Вводная проза, объясняющая предмет конвенции.
Как на правила ссылаются копии
Ниже маркера локальной части, в репозитории:
<!-- conv:local -->
MIGR-2, MIGR-4 механизированы — `internal/archrules` (проверяются в новых
миграциях).
MIGR-6 не соблюдается в легаси-таблицах `show_history`, `queue`: составные
ключи там появились до конвенции, переписывание требует миграции данных.
Отсюда видно и то, чего раньше не было видно: конвенция из восьми правил, из которых два механизированы и одно не соблюдается.
Что стоит проверять машиной
Проверки применяются к файлам конвенций; обвязка канона в них не входит — она ключевые слова цитирует, а не употребляет. Ни одна пока не реализована, поэтому при ревью их выполняют чтением.
Разбором текста:
- модальные и служебные слова принадлежат объявленному словарю канона, а не смеси словарей;
- префикс в шапке файла совпадает с реестром, состоит из четырёх заглавных
латинских букв, не начинается на
Xи не значится в списке выбывших; - заголовки правил файла используют только его собственный префикс;
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило берёт следующий свободный, а не первый освободившийся);
- у каждого
### <ПРЕФИКС>-<n>есть модальное слово и блок «Почему»; отметка МЕХАНИЗИРОВАНО стоит рядом с модальностью, а не вместо неё; - вводная проза содержит строку о версии языка;
- ссылки вида
<ПРЕФИКС>-<n>— хоть в тексте канона, хоть в локальной части копии — указывают на правила, которые ещё существуют; - префиксы локальных правил копии начинаются на
X; - заглавные модальные слова не встречаются вне правил — кроме строки о версии языка, которая их перечисляет по назначению;
- префикс чужой темы не встречается в абзаце с модальностью (META-20); префикс арх-слоя своей темы там допустим (META-24), префикс другого языка или стека — нет;
- путь файла канона не встречается в тексте конвенции (META-21).
Чтением, потому что машине не даётся:
- строки таблицы взаимоисключающи либо политика совпадения объявлена;
- перечисленные в таблице случаи покрывают область действия;
- норма исполнима без обращения к другим файлам;
- обоснование отвечает на «что сломается», а не пересказывает норму.