конвенции отделены от обвязки
- сами конвенции переехали в conventions/, описательное — в корень: LANGUAGE.md (язык записи) и GUIDE.md (как ведут конвенции) - conv синхронизирует только conventions/, пути в origin даются относительно неё — раскладка копий в репозиториях не меняется
This commit is contained in:
+205
@@ -0,0 +1,205 @@
|
||||
# Язык конвенций
|
||||
|
||||
Как записываются правила в этом каноне. Документ описывает форму, а не
|
||||
содержание: что такое правило, чем оно отличается от прозы вокруг и как на
|
||||
него сослаться.
|
||||
|
||||
Форма подсмотрена у OpenSpec, но взято оттуда не всё — см. «Чего мы не
|
||||
берём».
|
||||
|
||||
## Зачем формализовать
|
||||
|
||||
Не ради строгости. Три конкретные вещи, которые без адресуемых правил не
|
||||
работают:
|
||||
|
||||
- **Механизация.** Регион `механизировано` должен говорить «правило R4
|
||||
проверяет `archrules`», а не «`AUTOINCREMENT` в новых миграциях —
|
||||
`archrules`»: во втором случае читатель сам догадывается, к какому
|
||||
утверждению это относится, и догадывается по-разному.
|
||||
- **Отступления.** «У нас не так» бесполезно, пока не сказано, что именно
|
||||
«не так». Со ссылкой на правило отступления становятся счётными: видно,
|
||||
сколько правил конвенции репозиторий реально не соблюдает.
|
||||
- **Промоут находки.** Путь «находка → конвенция → правило линтера →
|
||||
удаление прозы» требует ручки, за которую берут конкретное правило.
|
||||
|
||||
Общий знаменатель — **идентификатор**. Модальные слова и таблицы полезны,
|
||||
но вторичны.
|
||||
|
||||
## Единица — правило
|
||||
|
||||
```markdown
|
||||
### R5. Разбор внешнего идентификатора на границе
|
||||
|
||||
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
|
||||
к базе.
|
||||
|
||||
**Почему.** Разбор валидирует формат и нормализует регистр. Сравнение строк
|
||||
в базе побайтовое, поэтому без нормализации запрос молча не находит
|
||||
существующую запись — отладка такого случая стоит дороже, чем сам разбор.
|
||||
```
|
||||
|
||||
Четыре обязательные части: **номер**, **заголовок**, **модальность с
|
||||
нормой**, **почему**. Норма — одна фраза; если в неё не влезает, это два
|
||||
правила.
|
||||
|
||||
## Правило без «почему» не принимается
|
||||
|
||||
Это жёсткое требование к форме, а не пожелание. Причины:
|
||||
|
||||
- **«Почему» — единственный способ понять, когда правило перестало
|
||||
действовать.** Норма стареет молча; обоснование стареет заметно. Когда
|
||||
причина отпала, видно, что правило пора убрать, а не соблюдать по
|
||||
инерции.
|
||||
- **Правило без обоснования не переживает спор.** Через год ни автор, ни
|
||||
агент не восстановят мотив, и правило будет либо отменено первым же
|
||||
возражением, либо соблюдено там, где вредит.
|
||||
- **Формулировка «почему» — проверка на то, что это вообще правило.** Если
|
||||
причина не формулируется, перед нами привычка или вкусовщина; ей место в
|
||||
черновиках, а не в конвенции.
|
||||
|
||||
«Почему» отвечает на «что сломается, если сделать иначе», а не пересказывает
|
||||
норму другими словами. «Потому что так принято» — не обоснование.
|
||||
|
||||
## Модальные слова
|
||||
|
||||
Пишутся капсом — это ключевые слова, а не обычный текст.
|
||||
|
||||
| Слово | Значение | Отступление |
|
||||
|---|---|---|
|
||||
| **ДОЛЖЕН** | нарушение считается ошибкой | только с записью в регион `отступления` |
|
||||
| **НЕ ДОЛЖЕН** | запрет | то же |
|
||||
| **СЛЕДУЕТ** | сильная рекомендация; новый код пишем так | допустимо, причину записываем |
|
||||
| **НЕ СЛЕДУЕТ** | обратное к СЛЕДУЕТ | то же |
|
||||
| **ДОПУСКАЕТСЯ** | явное разрешение | не требуется — правило ничего не запрещает |
|
||||
|
||||
**ДОПУСКАЕТСЯ** нужно не для симметрии: оно снимает вопрос «а так можно?»
|
||||
там, где соседнее правило звучит строго и его легко перечитать шире, чем
|
||||
задумано.
|
||||
|
||||
Модальность живёт на **правиле**, а не на файле. Прежний файловый статус
|
||||
(`status: рекомендуемая` / `обязательная` в шапке) отменён: он неизбежно
|
||||
врал, потому что один файл смешивает жёсткие требования с советами. В шапке
|
||||
остаются только `extends` и служебные ключи копии.
|
||||
|
||||
Мы **не используем SHALL и прочие английские ключевые слова**. Они заняты
|
||||
спецификациями (OpenSpec), и общий словарь стирал бы границу «конвенция —
|
||||
не capability». Разный словарь эту границу держит бесплатно.
|
||||
|
||||
## Идентификаторы
|
||||
|
||||
- Формат — `R<номер>`, сквозная нумерация внутри файла, начиная с `R1`.
|
||||
- Строка таблицы, если на неё нужно ссылаться отдельно, — `R5.1`, `R5.2`.
|
||||
- **Номера стабильны и не переиспользуются.** Удалённое правило оставляет
|
||||
дыру в нумерации; занимать её новым правилом нельзя — иначе ссылка из
|
||||
чужого репозитория начнёт указывать на другое утверждение.
|
||||
- Глобальный адрес — путь файла плюс номер: `arch/db-identifiers.md R5`.
|
||||
В пределах одного файла достаточно `R5`.
|
||||
|
||||
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это
|
||||
идентификатор, а не позиция.
|
||||
|
||||
## Правило, чья норма уехала в линтер
|
||||
|
||||
Когда правило механизировано у всех потребителей, его норма из канона
|
||||
удаляется, а обоснование — нет. Остаётся **правило без модальности**, и
|
||||
чтобы оно не выглядело недописанным, место нормы занимает отметка:
|
||||
|
||||
```markdown
|
||||
### R6. Дефолтов времени в схеме БД нет
|
||||
|
||||
**МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера; формулировка
|
||||
удалена, потому что дублировала работающую проверку.
|
||||
|
||||
**Почему.** Дефолт превращает забытую вставку в тихо работающий код…
|
||||
```
|
||||
|
||||
- Номер и заголовок сохраняются: ссылки из репозиториев продолжают
|
||||
указывать на то же утверждение.
|
||||
- «Почему» остаётся навсегда — линтер сообщает, что нарушено, но не
|
||||
сообщает, зачем правило существует, и без обоснования нельзя понять,
|
||||
когда проверку пора отменять.
|
||||
- **МЕХАНИЗИРОВАНО** — не шестое модальное слово: оно не задаёт
|
||||
обязательность, а сообщает, что обязательность теперь обеспечена машиной.
|
||||
В остальном такое правило равно ДОЛЖЕН.
|
||||
|
||||
Факт «механизировано у всех» устанавливается вручную: канон по построению
|
||||
не знает списка подписчиков, и обойти репозитории перед удалением нормы —
|
||||
часть работы, а не то, что можно проверить автоматически.
|
||||
|
||||
## Таблицы вместо сценариев
|
||||
|
||||
Часть правил **классифицирует ситуации**: какой уровень лога, какая
|
||||
категория директории, что делать с невалидным вводом в зависимости от его
|
||||
источника. Для них каноническая форма — таблица «ситуация → вердикт»,
|
||||
строки которой при необходимости нумеруются.
|
||||
|
||||
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а
|
||||
неупомянутый случай в абзаце — нет.
|
||||
|
||||
## Чего мы не берём из OpenSpec
|
||||
|
||||
**GIVEN/WHEN/THEN.** У спецификации субъект — система, и её поведение
|
||||
разворачивается во времени: состояние, событие, исход. У конвенции субъект
|
||||
— автор кода, и разворачивать нечего: есть ситуация выбора и вердикт. Это
|
||||
таблица, а не траектория.
|
||||
|
||||
**SHALL.** См. выше про словарь.
|
||||
|
||||
**Сценарии как общая форма.** Прозаический сценарий остаётся точечным
|
||||
инструментом — для **стыка правил**, когда два правила вместе дают
|
||||
неочевидный результат:
|
||||
|
||||
```
|
||||
WHEN зависимость недоступна и ретраи вызова исчерпаны → ext-запись ERROR
|
||||
AND тик фонового цикла упал по той же причине → доменная запись WARN
|
||||
```
|
||||
|
||||
Такой блок ставится после обоих правил и ссылается на их номера. Если
|
||||
стыков нет — сценариев в файле нет.
|
||||
|
||||
## Что правилом не является
|
||||
|
||||
Модальные слова в этих частях **не употребляются** — иначе перестанет быть
|
||||
понятно, что адресуемо, а что нет:
|
||||
|
||||
- **Область действия** — на что конвенция распространяется во времени
|
||||
(«новые таблицы; существующие не переписываются»). Это рамка для всех
|
||||
правил файла, а не правило.
|
||||
- **Связано** — ссылки на смежные конвенции, ADR, код.
|
||||
- **Локальные регионы** — содержимое принадлежит репозиторию.
|
||||
- Вводная проза, объясняющая предмет конвенции.
|
||||
|
||||
## Как на правила ссылаются копии
|
||||
|
||||
В репозитории:
|
||||
|
||||
```markdown
|
||||
<!-- local:механизировано -->
|
||||
R2, R4 — `internal/archrules` (проверяются в новых миграциях).
|
||||
<!-- /local -->
|
||||
|
||||
<!-- local:отступления -->
|
||||
R6 — не соблюдается в легаси-таблицах `show_history`, `queue`: составные
|
||||
ключи там появились до конвенции, переписывание требует миграции данных.
|
||||
<!-- /local -->
|
||||
```
|
||||
|
||||
Отсюда видно и то, чего раньше не было видно: конвенция из восьми правил,
|
||||
из которых два механизированы и одно не соблюдается.
|
||||
|
||||
## Что стоит проверять машиной
|
||||
|
||||
Сейчас не реализовано; список — на будущее для `conv`:
|
||||
|
||||
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило
|
||||
берёт следующий свободный, а не первый освободившийся);
|
||||
- у каждого `### R<n>` есть модальное слово (или отметка МЕХАНИЗИРОВАНО) и
|
||||
блок «Почему»;
|
||||
- ссылки вида `R<n>` в локальных регионах копии указывают на правила,
|
||||
которые в каноне ещё существуют;
|
||||
- модальные слова не встречаются вне правил.
|
||||
|
||||
## Порядок перевода
|
||||
|
||||
Все конвенции канона записаны на этом языке. Новая конвенция пишется на нём
|
||||
сразу; смешение форм в каноне больше не предполагается.
|
||||
Reference in New Issue
Block a user