Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59a1c23f55
|
||
|
|
1d19e0357b
|
||
|
|
682fa075bb
|
||
|
|
170c06c1da
|
||
|
|
67d51db212
|
||
|
|
fe61ecd6c5
|
||
|
|
c1cb240540
|
||
|
|
d5118336cb
|
||
|
|
df8c58671f
|
||
|
|
4943bf1dd2
|
||
|
|
7b2869d3a4
|
@@ -9,8 +9,9 @@ code in this repository.
|
|||||||
|
|
||||||
Канон конвенций разработки для личных проектов. Сами конвенции лежат в
|
Канон конвенций разработки для личных проектов. Сами конвенции лежат в
|
||||||
`conventions/{arch,lang/<язык>,stack/<стек>}/`; обвязка канона (`README.md`,
|
`conventions/{arch,lang/<язык>,stack/<стек>}/`; обвязка канона (`README.md`,
|
||||||
`LANGUAGE.md`, `GUIDE.md`, `prefixes.toml`, `conv`) живёт в корне и в
|
`LANGUAGE.md`, `GUIDE.md`, `READING.md`, `manifest.toml`, `conv`) живёт в
|
||||||
репозитории-потребители не едет.
|
корне. К потребителю из неё едет только `READING.md` — короткое описание языка
|
||||||
|
для читателя копий.
|
||||||
|
|
||||||
Ниже — короткие инварианты с идентификаторами; детали и обоснования в
|
Ниже — короткие инварианты с идентификаторами; детали и обоснования в
|
||||||
`LANGUAGE.md` (форма записи) и `GUIDE.md` (процесс, префикс META).
|
`LANGUAGE.md` (форма записи) и `GUIDE.md` (процесс, префикс META).
|
||||||
@@ -20,7 +21,15 @@ code in this repository.
|
|||||||
- Четыре обязательные части: `### <ПРЕФИКС>-<N>. Заголовок`, абзац
|
- Четыре обязательные части: `### <ПРЕФИКС>-<N>. Заголовок`, абзац
|
||||||
`**МОДАЛЬНОСТЬ.** норма`, абзац `**ПОЧЕМУ.** …`. Правило без обоснования не
|
`**МОДАЛЬНОСТЬ.** норма`, абзац `**ПОЧЕМУ.** …`. Правило без обоснования не
|
||||||
принимается.
|
принимается.
|
||||||
|
- `**ПРИМЕРЫ.**` — необязательный пятый блок после обоснования: код парой
|
||||||
|
«плохо → хорошо». Иллюстрация нормы, а не спецификация — требований в блоке
|
||||||
|
нет, дословным сниппетом он не является, при расхождении действует норма.
|
||||||
- Норма — одна фраза; если в неё не влезает, это два правила.
|
- Норма — одна фраза; если в неё не влезает, это два правила.
|
||||||
|
- Область правила — от его заголовка до следующего заголовка любого уровня;
|
||||||
|
метка открывает блок, блок длится до следующей метки или до конца области.
|
||||||
|
Абзацы после `**ПОЧЕМУ.**` — продолжение обоснования: требований в них не
|
||||||
|
живёт, требование ставят в блок нормы. Таблица и список после модальной
|
||||||
|
метки — часть нормы.
|
||||||
- Шкала инвариантна, словарь — параметр языка набора. Канон русский, значит
|
- Шкала инвариантна, словарь — параметр языка набора. Канон русский, значит
|
||||||
слова: **ДОЛЖЕН**, **НЕ ДОЛЖЕН**, **СЛЕДУЕТ**, **НЕ СЛЕДУЕТ**,
|
слова: **ДОЛЖЕН**, **НЕ ДОЛЖЕН**, **СЛЕДУЕТ**, **НЕ СЛЕДУЕТ**,
|
||||||
**ДОПУСКАЕТСЯ**. Словарь один на канон, синонимов на ступень нет.
|
**ДОПУСКАЕТСЯ**. Словарь один на канон, синонимов на ступень нет.
|
||||||
@@ -28,14 +37,20 @@ code in this repository.
|
|||||||
- Нормативно только заглавное написание (правило RFC 8174): строчное
|
- Нормативно только заглавное написание (правило RFC 8174): строчное
|
||||||
«должен» в прозе нормой не является.
|
«должен» в прозе нормой не является.
|
||||||
- ДОЛЖЕН требует двух условий сразу: назван вред от нарушения (META-25) и
|
- ДОЛЖЕН требует двух условий сразу: назван вред от нарушения (META-25) и
|
||||||
норма проверяема машиной (META-6). Проверяемость сама по себе до ДОЛЖЕН не
|
вердикт о нарушении воспроизводим (META-6). Воспроизводимость сама по себе
|
||||||
повышает — иначе шкала наполняется проверяемыми мелочами.
|
до ДОЛЖЕН не повышает — иначе шкала наполняется проверяемыми мелочами.
|
||||||
- ДОПУСКАЕТСЯ адресовано рецензенту: помеченный им выбор на ревью не
|
- ДОПУСКАЕТСЯ адресовано рецензенту: помеченный им выбор на ревью не
|
||||||
обсуждается.
|
обсуждается.
|
||||||
- **МЕХАНИЗИРОВАНО** — не модальность, а способ проверки: отметка стоит
|
- **МЕХАНИЗИРОВАНО** — не модальность, а способ проверки, и свойство
|
||||||
рядом с модальным словом (`**ДОЛЖЕН. МЕХАНИЗИРОВАНО.**`), а не вместо него.
|
репозитория, а не канона: в тексте конвенции отметки нет, она стоит при
|
||||||
- Метки правила — **ПОЧЕМУ** и **МЕХАНИЗИРОВАНО** — тоже словарь набора и
|
записи о механизации в локальной части копии (META-7).
|
||||||
перечислены в строке о версии языка наравне с модальными словами.
|
- META-8: норма не удаляется из канона никогда, чем бы её ни проверяли.
|
||||||
|
Механизация её не заменяет и не сокращает.
|
||||||
|
- Метки правила — **ПОЧЕМУ**, **ПРИМЕРЫ**, **МЕХАНИЗИРОВАНО** и **СНЯТО** —
|
||||||
|
тоже словарь набора и перечислены в строке о версии языка наравне с
|
||||||
|
модальными словами.
|
||||||
|
- META-30: правка словаря или состава частей правила доходит до `READING.md` —
|
||||||
|
документа, который едет к потребителю. Словари двух описаний совпадают.
|
||||||
- Заглавные модальные слова не употребляются вне правил: ни в «Область
|
- Заглавные модальные слова не употребляются вне правил: ни в «Область
|
||||||
действия», ни в «Связано», ни в локальной части копии, ни во вводной прозе.
|
действия», ни в «Связано», ни в локальной части копии, ни во вводной прозе.
|
||||||
Исключение — строка о версии языка, которая их перечисляет.
|
Исключение — строка о версии языка, которая их перечисляет.
|
||||||
@@ -55,18 +70,32 @@ code in this repository.
|
|||||||
действия.
|
действия.
|
||||||
- Модальность принадлежит правилу, а не файлу: `status:` в шапке отменён.
|
- Модальность принадлежит правилу, а не файлу: `status:` в шапке отменён.
|
||||||
|
|
||||||
## Идентификаторы и префиксы
|
## Идентификаторы: тема и префикс
|
||||||
|
|
||||||
|
- Тема — набор правил об одном фокусе разработки и единица подписки. Имя —
|
||||||
|
латиницей, рекомендуется нижний kebab-case, годится любой идентификатор,
|
||||||
|
пригодный для имени файла.
|
||||||
|
- META-28: тема объявлена в шапке (`topic: time`) и стоит в манифесте набора
|
||||||
|
(`manifest.toml`, секция `[topics.live]`). Слои одной темы несут одно имя —
|
||||||
|
по нему собираются в один файл, как бы ни назывались их файлы; имя файла
|
||||||
|
повторяет тему из удобства.
|
||||||
|
- META-29: имя темы не переиспользуется, снятое уходит в `[topics.retired]`
|
||||||
|
с причиной и датой. Оно живёт в `origin:` копий и в подписках манифестов.
|
||||||
- Формат `<ПРЕФИКС>-<номер>`, нумерация сквозная внутри файла. Порядок правил
|
- Формат `<ПРЕФИКС>-<номер>`, нумерация сквозная внутри файла. Порядок правил
|
||||||
в файле — по читаемости: номер это идентификатор, а не позиция.
|
в файле — по читаемости: номер это идентификатор, а не позиция.
|
||||||
- Идентификаторы не переиспользуются. Удалённое правило оставляет дыру, новое
|
- Идентификаторы не переиспользуются: новое правило берёт номер, следующий за
|
||||||
берёт следующий свободный номер, а не первый освободившийся.
|
наибольшим.
|
||||||
|
- META-31: нумерация в файле сплошная. Снятое правило не исчезает, а остаётся
|
||||||
|
заглушкой: заголовок с номером плюс блок `**СНЯТО <дата>.**` с причиной
|
||||||
|
вместо нормы и ПОЧЕМУ. Реестра снятых номеров нет — файл сам себе реестр.
|
||||||
|
- META-32: ссылок на несуществующие правила нет; неразрешённый идентификатор —
|
||||||
|
всегда ошибка, а не «правило, наверное, сняли».
|
||||||
- Новый файл конвенции — новый префикс: четыре заглавные латинские буквы,
|
- Новый файл конвенции — новый префикс: четыре заглавные латинские буквы,
|
||||||
уникальные по всему канону, выбираются под файл, а не выводятся по формуле.
|
уникальные по всему канону, выбираются под файл, а не выводятся по формуле.
|
||||||
Объявляется в шапке (`prefix: KEYS`) и регистрируется в `prefixes.toml`,
|
Объявляется в шапке (`prefix: KEYS`) и регистрируется в манифесте набора,
|
||||||
секция `[live]`, путём от корня репозитория.
|
секция `[prefixes.live]`, путём от корня репозитория.
|
||||||
- Удаление или разделение файла: префикс уходит в `[retired]` с причиной и
|
- Удаление или разделение файла: префикс уходит в `[prefixes.retired]` с
|
||||||
датой, а не освобождается.
|
причиной и датой, а не освобождается.
|
||||||
- Префиксы на букву `X` канон не занимает: они зарезервированы за локальными
|
- Префиксы на букву `X` канон не занимает: они зарезервированы за локальными
|
||||||
правилами репозиториев-потребителей.
|
правилами репозиториев-потребителей.
|
||||||
- Перенос правила в другой файл — смысловое изменение: новый префикс и новый
|
- Перенос правила в другой файл — смысловое изменение: новый префикс и новый
|
||||||
@@ -93,11 +122,13 @@ code in this repository.
|
|||||||
- META-5: расхождение кода с правилом — отступление, а не повод переписать
|
- META-5: расхождение кода с правилом — отступление, а не повод переписать
|
||||||
правило. Направление всегда конвенция → код; факт «в приложении уже иначе»
|
правило. Направление всегда конвенция → код; факт «в приложении уже иначе»
|
||||||
не является аргументом.
|
не является аргументом.
|
||||||
- META-6: ДОЛЖЕН без механической проверки либо механизируется, либо
|
- META-6: ДОЛЖЕН требует воспроизводимого вердикта — двое проверяющих по
|
||||||
понижается в СЛЕДУЕТ. Правило, непроверяемое машиной в принципе (вкус
|
тексту правила отвечают одинаково. Правило, вердикт которого зависит от
|
||||||
формулировки, суждение о ситуации), — СЛЕДУЕТ по построению.
|
суждения (вкус формулировки, уместность в конкретном месте), — СЛЕДУЕТ по
|
||||||
|
построению. META-27: машинная проверка желательна, но ступени не задаёт;
|
||||||
|
проверяющий по умолчанию — читатель правила, человек или агент.
|
||||||
- META-10: блок ПОЧЕМУ не удаляется никогда, в том числе после того, как
|
- META-10: блок ПОЧЕМУ не удаляется никогда, в том числе после того, как
|
||||||
норма уехала в линтер.
|
правило стало проверяться линтером.
|
||||||
- META-1: один файл — ровно один повторяющийся выбор. META-2: конвенция
|
- META-1: один файл — ровно один повторяющийся выбор. META-2: конвенция
|
||||||
заводится, когда решение принимается третий раз.
|
заводится, когда решение принимается третий раз.
|
||||||
- Репозиторного в каноне нет вовсе: механизация, отступления и ссылки на код
|
- Репозиторного в каноне нет вовсе: механизация, отступления и ссылки на код
|
||||||
@@ -114,13 +145,12 @@ code in this repository.
|
|||||||
|
|
||||||
## Оформление файла
|
## Оформление файла
|
||||||
|
|
||||||
Шапка `prefix:` (плюс `extends:`) → `# Тема` → вводная проза → отдельным
|
Шапка `topic:` и `prefix:` (плюс `extends:`) → `# Тема` → вводная проза →
|
||||||
абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`, раздел
|
отдельным абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`,
|
||||||
«Ссылка на язык из конвенции») → `## Область действия` (обязателен для
|
раздел «Ссылка на язык из конвенции») → `## Область действия` (обязателен для
|
||||||
трудноизменяемых слоёв — META-11) → правила → `## Связано`, если
|
трудноизменяемых слоёв — META-11) → правила → `## Связано`, если канонические
|
||||||
канонические ссылки есть (META-17; пустого раздела не заводят). Имя файла —
|
ссылки есть (META-17; пустого раздела не заводят). Имя файла повторяет имя
|
||||||
kebab-case по теме. Проза
|
темы. Проза переносится по ~76 колонок; таблицы и блоки кода не переносятся.
|
||||||
переносится по ~76 колонок; таблицы и блоки кода не переносятся.
|
|
||||||
|
|
||||||
## Ревью формы
|
## Ревью формы
|
||||||
|
|
||||||
@@ -128,6 +158,12 @@ kebab-case по теме. Проза
|
|||||||
проверять машиной». Ни одна из проверок не реализована, поэтому при ревью их
|
проверять машиной». Ни одна из проверок не реализована, поэтому при ревью их
|
||||||
выполняют чтением.
|
выполняют чтением.
|
||||||
|
|
||||||
|
Проверяется всё, что язык **употребляет**: конвенции и `GUIDE.md` (он несёт
|
||||||
|
правила META и строку о версии языка). `LANGUAGE.md` и `README.md` язык
|
||||||
|
цитируют — ключевые слова в них предмет описания, а не норма. Проверки
|
||||||
|
распространения (тема в шапке, самодостаточность нормы, отсутствие путей
|
||||||
|
канона) касаются только конвенций: обвязка к потребителю не едет.
|
||||||
|
|
||||||
## Коммиты
|
## Коммиты
|
||||||
|
|
||||||
Русский, строчная буква, без точки в конце, прошедшее время или страдательный
|
Русский, строчная буква, без точки в конце, прошедшее время или страдательный
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ prefix: META
|
|||||||
[LANGUAGE.md](LANGUAGE.md). Здесь — про то, зачем конвенции заводятся, где
|
[LANGUAGE.md](LANGUAGE.md). Здесь — про то, зачем конвенции заводятся, где
|
||||||
живут и как соотносятся с соседними видами документов.
|
живут и как соотносятся с соседними видами документов.
|
||||||
|
|
||||||
|
Правила ниже записаны тем же языком, что и сами конвенции, и проверяются так
|
||||||
|
же.
|
||||||
|
|
||||||
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
Правила ниже адресованы автору конвенции — тому, кто заводит новый файл или
|
Правила ниже адресованы автору конвенции — тому, кто заводит новый файл или
|
||||||
@@ -32,11 +39,11 @@ prefix: META
|
|||||||
|
|
||||||
## Оформление
|
## Оформление
|
||||||
|
|
||||||
Имя файла — kebab-case по теме: `app-directories.md`. Правилом это не
|
Имя файла повторяет имя темы: `app-directories.md`. Правилом это не
|
||||||
записано, и это случай META-25: регуляркой имя проверяется тривиально, но
|
записано, и это случай META-25: регуляркой имя проверяется тривиально, но
|
||||||
обоснование сводится к «чтобы имя файла в реестре префиксов писалось одним
|
вреда от нарушения нет — тема объявлена в шапке (META-28), и сборка идёт по
|
||||||
способом» — вреда от нарушения нет, значит и высшей модальности нет, а на
|
объявленному имени, а не по имени файла. Значит, и высшей модальности нет, а
|
||||||
СЛЕДУЕТ такое правило не окупает строчку.
|
ступенью ниже такое правило не окупает строчку.
|
||||||
|
|
||||||
## Канон и копии
|
## Канон и копии
|
||||||
|
|
||||||
@@ -68,6 +75,70 @@ prefix: META
|
|||||||
дорого: перенос правила в другой файл — это новый префикс и новая
|
дорого: перенос правила в другой файл — это новый префикс и новая
|
||||||
нумерация, поэтому после разреза все внешние ссылки обходят руками.
|
нумерация, поэтому после разреза все внешние ссылки обходят руками.
|
||||||
|
|
||||||
|
### META-28. Тема объявляется в шапке файла и стоит в манифесте набора
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Шапка несёт ключ `topic:` с именем темы, и это имя стоит в
|
||||||
|
манифесте набора.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Тема — единица подписки и единица сборки: потребитель перечисляет
|
||||||
|
темы в своём манифесте, а сборщик складывает в один файл все слои темы. Пока
|
||||||
|
имя выводится из имени файла, у сборщика нет способа узнать, что два слоя,
|
||||||
|
названные по-разному, — один документ; переименование файла при этом молча
|
||||||
|
заводит новую тему, подписка перестаёт находить прежнюю, а ссылки «конвенция
|
||||||
|
`logging`» в копиях остаются висеть. Объявленное имя вдобавок сверяется с
|
||||||
|
манифестом — выведенное сверять не с чем.
|
||||||
|
|
||||||
|
### META-29. Имя темы не переиспользуется
|
||||||
|
|
||||||
|
**НЕ ДОЛЖЕН.** Снятое или переименованное имя темы другой теме не выдаётся:
|
||||||
|
оно уходит в раздел выбывших манифеста с причиной и датой.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Имя темы живёт в чужих репозиториях — в шапке `origin:` каждой
|
||||||
|
копии, в подписке потребителя, в тексте ссылок. Выданное второй теме, оно
|
||||||
|
начинает указывать на другой набор правил, и обнаруживается это не на сборке,
|
||||||
|
а по содержанию: файл обновится штатно, изменится текст. Та же дисциплина и по
|
||||||
|
той же причине действует для префиксов правил.
|
||||||
|
|
||||||
|
### META-30. Правка словаря или формы правила доходит до документа для читателя
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Изменение ключевых слов, их значений или состава частей правила
|
||||||
|
вносится и в короткое описание языка, которое едет в копию.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Полное описание языка остаётся у автора набора, а по правилам код
|
||||||
|
проверяет читатель копии — человек или агент в чужом репозитории, у которого
|
||||||
|
из двух документов есть только короткий. Разошедшись, он начинает толковать
|
||||||
|
слова по прежней версии: ДОПУСКАЕТСЯ читается как бытовое «можно», отступление
|
||||||
|
от ДОЛЖЕН перестаёт требовать записи — то есть отказывает ровно то, ради чего
|
||||||
|
слова вводились, и молча. Проверить расхождение дёшево: словари в двух
|
||||||
|
документах либо совпадают, либо нет.
|
||||||
|
|
||||||
|
### META-31. Нумерация правил в файле сплошная
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Номера идут от единицы до наибольшего без пропусков: снятое
|
||||||
|
правило остаётся на месте заглушкой с меткой СНЯТО, а не исчезает.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Дыра в нумерации неотличима от опечатки в номере и от правила,
|
||||||
|
которое забыли дописать, — проверка, увидев пропуск, не может сказать, ошибка
|
||||||
|
это или норма, поэтому либо молчит всегда, либо краснеет на живом файле.
|
||||||
|
Заглушка отвечает на тот же вопрос текстом: номер занят, правило снято
|
||||||
|
тогда-то и по такой-то причине. Переиспользовать номер по-прежнему нельзя —
|
||||||
|
ссылка из чужого репозитория обязана указывать на то же утверждение, — но и
|
||||||
|
отдельный
|
||||||
|
реестр снятых номеров не нужен: он был бы вторым источником правды рядом с
|
||||||
|
файлом, который и так всё сказал.
|
||||||
|
|
||||||
|
### META-32. Ссылка ведёт на правило, которое существует
|
||||||
|
|
||||||
|
**НЕ ДОЛЖЕН.** Идентификатор в тексте не указывает на правило, которого в
|
||||||
|
наборе нет.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Неразрешимая ссылка означает одно из двух: опечатку в номере или
|
||||||
|
след переноса правила в другой файл. Читатель — тем более в чужом
|
||||||
|
репозитории — не различит эти случаи и решит, что правила больше нет, хотя оно
|
||||||
|
могло переехать. С заглушками (META-31) проверка становится однозначной:
|
||||||
|
идентификатор либо ведёт к правилу, либо к объяснению, почему его сняли, а
|
||||||
|
третьего исхода нет — и любой неразрешённый идентификатор точно ошибка.
|
||||||
|
|
||||||
### META-2. Конвенция заводится, когда решение принимается третий раз
|
### META-2. Конвенция заводится, когда решение принимается третий раз
|
||||||
|
|
||||||
**СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и
|
**СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и
|
||||||
@@ -81,9 +152,9 @@ prefix: META
|
|||||||
|
|
||||||
### META-3. Новая конвенция пишется там, где заболело
|
### META-3. Новая конвенция пишется там, где заболело
|
||||||
|
|
||||||
**СЛЕДУЕТ.** Первые шаги пути «находка → конвенция → правило линтера →
|
**СЛЕДУЕТ.** Первые шаги пути «находка → конвенция → правило линтера»
|
||||||
удаление прозы» делаются в репозитории, где случилась находка; в канон
|
делаются в репозитории, где случилась находка; в канон продвигается общая
|
||||||
продвигается общая часть.
|
часть.
|
||||||
|
|
||||||
**ПОЧЕМУ.** Правило, написанное сразу в общем виде, не проверено ни одним
|
**ПОЧЕМУ.** Правило, написанное сразу в общем виде, не проверено ни одним
|
||||||
применением, и условие применимости у него придумано, а не найдено, —
|
применением, и условие применимости у него придумано, а не найдено, —
|
||||||
@@ -157,33 +228,52 @@ prefix: META
|
|||||||
переписывает его снова. Направление «конвенция → код» держится ровно тем,
|
переписывает его снова. Направление «конвенция → код» держится ровно тем,
|
||||||
что факт не считается аргументом.
|
что факт не считается аргументом.
|
||||||
|
|
||||||
### META-6. `ДОЛЖЕН` без механической проверки либо механизируется, либо понижается
|
### META-6. Высшая модальность требует воспроизводимого вердикта
|
||||||
|
|
||||||
**ДОЛЖЕН.** Правило, нарушение которого объявлено ошибкой, получает
|
**ДОЛЖЕН.** Правило со ступенью ДОЛЖЕН или НЕ ДОЛЖЕН формулируется так, что
|
||||||
машинную проверку или переводится в СЛЕДУЕТ.
|
двое проверяющих по одному его тексту выносят один и тот же вердикт.
|
||||||
|
|
||||||
**ПОЧЕМУ.** Без проверки правило держится на внимании: нарушения копятся
|
**ПОЧЕМУ.** Проверяют конвенцию в первую очередь агент и человек — они читают
|
||||||
молча и всплывают выборочно — на том ревью, куда дошли руки. Для СЛЕДУЕТ
|
текст правила и по нему смотрят код. Проверка, стало быть, есть у каждого
|
||||||
это честно, а ДОЛЖЕН при этом обещает то, чего не делает, и через несколько
|
правила с первого дня, и её инструмент — формулировка, а не скрипт. Отсюда
|
||||||
таких случаев обесценивает остальные ДОЛЖЕН в файле.
|
цена невоспроизводимой нормы: вердикт зависит от того, кто читал, нарушения
|
||||||
|
всплывают выборочно, а отступление нечем записать — неизвестно, нарушено ли.
|
||||||
|
Для СЛЕДУЕТ это честно, там суждение и есть содержание правила; ДОЛЖЕН в
|
||||||
|
таком виде обещает то, чего не делает, и через несколько случаев обесценивает
|
||||||
|
остальные ДОЛЖЕН в файле.
|
||||||
|
|
||||||
Отсюда следствие: правило, машинная проверка которого невозможна в принципе
|
Отсюда следствие: правило, вердикт которого зависит от суждения по построению
|
||||||
(вкус формулировки, выбор границы, суждение о ситуации), не может быть
|
(вкус формулировки, выбор границы, уместность в конкретном месте), не может
|
||||||
ДОЛЖЕН — его модальность СЛЕДУЕТ по построению, а не по слабости.
|
быть ДОЛЖЕН — его модальность СЛЕДУЕТ по природе нормы, а не по слабости.
|
||||||
|
|
||||||
### META-25. Высшая модальность выбирается, только когда назван вред
|
### META-25. Высшая модальность выбирается, только когда назван вред
|
||||||
|
|
||||||
**СЛЕДУЕТ.** Правило получает ДОЛЖЕН или НЕ ДОЛЖЕН, если в обосновании
|
**СЛЕДУЕТ.** Правило получает ДОЛЖЕН или НЕ ДОЛЖЕН, если в обосновании
|
||||||
сказано, что́ ломается при нарушении.
|
сказано, что́ ломается при нарушении.
|
||||||
|
|
||||||
**ПОЧЕМУ.** Машинная проверка — условие необходимое (META-6), но не
|
**ПОЧЕМУ.** Воспроизводимость вердикта — условие необходимое (META-6), но не
|
||||||
достаточное: проверяемых мелочей больше, чем важных вещей, и без второго
|
достаточное: воспроизводимо проверяемых мелочей больше, чем важных вещей, и
|
||||||
условия единственным фильтром остаётся удобство проверки. Шкала наполняется
|
без второго условия единственным фильтром остаётся удобство проверки. Шкала
|
||||||
опрятностью, читатель перестаёт отличать «уронит прод» от «неаккуратно» — и
|
наполняется опрятностью, читатель перестаёт отличать «уронит прод» от
|
||||||
обесцениваются все ДОЛЖЕН в файле, ровно то, от чего META-6 защищает с
|
«неаккуратно» — и обесцениваются все ДОЛЖЕН в файле, ровно то, от чего META-6
|
||||||
другой стороны. Само это правило машиной не проверяется: «вред назван»
|
защищает с другой стороны. Собственная ступень этого правила — СЛЕДУЕТ:
|
||||||
устанавливается чтением, поэтому его собственная модальность по META-6 —
|
форма обоснования ничем не ограничена, поэтому «вред назван» вердикта не
|
||||||
СЛЕДУЕТ.
|
даёт — один читатель увидит названный вред там, где другой увидит объяснение
|
||||||
|
мотива.
|
||||||
|
|
||||||
|
### META-27. Механизация правила желательна, но ступени не задаёт
|
||||||
|
|
||||||
|
**СЛЕДУЕТ.** Правило со ступенью ДОЛЖЕН получает машинную проверку, когда
|
||||||
|
такую проверку можно написать.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Линтер не забывает, ничего не стоит на каждом прогоне и краснеет
|
||||||
|
до ревью, а не на нём: там, где проверка пишется, она дешевле самого
|
||||||
|
внимательного чтения, и путь «находка → конвенция → проверка» кончается ею.
|
||||||
|
Норму она при этом не заменяет и не отменяет (META-8). Условием ступени
|
||||||
|
механизация не является:
|
||||||
|
проверяющий по умолчанию — читатель правила (META-6), а если требовать
|
||||||
|
скрипт, весь канон стоит в СЛЕДУЕТ до того дня, когда скрипты появятся.
|
||||||
|
Ступень говорит о важности нормы, а не о состоянии инструментов.
|
||||||
|
|
||||||
### META-7. Факт механизации фиксируется в копии со ссылкой на правило
|
### META-7. Факт механизации фиксируется в копии со ссылкой на правило
|
||||||
|
|
||||||
@@ -196,36 +286,25 @@ prefix: META
|
|||||||
читатель догадывается сам, к какому утверждению относится проверка, — и
|
читатель догадывается сам, к какому утверждению относится проверка, — и
|
||||||
догадывается по-разному.
|
догадывается по-разному.
|
||||||
|
|
||||||
### META-8. Формулировка не удаляется из канона, пока механизирована не у всех
|
### META-8. Норма из канона не удаляется, чем бы она ни проверялась
|
||||||
|
|
||||||
**НЕ ДОЛЖЕН.** Норма остаётся в каноне, пока хотя бы у одного потребителя
|
**НЕ ДОЛЖЕН.** Формулировка нормы остаётся в правиле независимо от того, кто и
|
||||||
машинной проверки нет.
|
чем её проверяет.
|
||||||
|
|
||||||
**ПОЧЕМУ.** У кого линтера нет, тот после удаления остаётся без правила
|
**ПОЧЕМУ.** Проверяющий по умолчанию — читатель правила (META-6), и удаление
|
||||||
вообще: ни проверки, ни текста. Механизация у одного потребителя ничего не
|
нормы забирает у него ровно то, чем он проверяет: линтер сообщает, что
|
||||||
говорит о прочих, поэтому удалять по факту «у нас уже проверяется» —
|
нарушено, но не сообщает, что требуется. Условие «механизировано у всех»
|
||||||
значит чинить свой файл за чужой счёт.
|
спасти не может: оно измеряется в день удаления, а подписчики появляются
|
||||||
|
после. Репозиторий, подключившийся через год, получил бы правило без нормы и
|
||||||
Списка подписчиков канон по построению не знает, поэтому факт «механизировано
|
без проверки — заголовок с обоснованием и никакого способа узнать, что́ именно
|
||||||
у всех» устанавливается обходом репозиториев вручную — это часть работы по
|
предписано, кроме git-истории канона, до которой он не дойдёт. Списка
|
||||||
удалению нормы, а не то, что можно проверить машиной (см. `LANGUAGE.md`,
|
подписчиков у канона к тому же нет по построению, так что «у всех» ему всё
|
||||||
состояние МЕХАНИЗИРОВАНО).
|
равно не проверить.
|
||||||
|
|
||||||
### META-9. Общая механизация разрешает удалить норму из канона
|
|
||||||
|
|
||||||
**ДОПУСКАЕТСЯ.** Правило, уехавшее в общий конфиг линтера или в общую роль,
|
|
||||||
удаляется из канона.
|
|
||||||
|
|
||||||
**ПОЧЕМУ.** Формулировка, дублирующая работающую у всех проверку,
|
|
||||||
размазывает внимание: файл на несколько сотен строк заставляет человека и
|
|
||||||
агента добросовестно вычитывать тривиальное именование и не доходить до
|
|
||||||
формы решения. Явное разрешение нужно, чтобы META-8 не читался как запрет
|
|
||||||
удалять вообще.
|
|
||||||
|
|
||||||
### META-10. Обоснование не удаляется никогда
|
### META-10. Обоснование не удаляется никогда
|
||||||
|
|
||||||
**НЕ ДОЛЖЕН.** Блок ПОЧЕМУ остаётся и после того, как норма уехала в
|
**НЕ ДОЛЖЕН.** Блок ПОЧЕМУ остаётся и после того, как правило стало
|
||||||
линтер.
|
проверяться линтером.
|
||||||
|
|
||||||
**ПОЧЕМУ.** Линтер сообщает, что нарушено, но не сообщает, зачем правило
|
**ПОЧЕМУ.** Линтер сообщает, что нарушено, но не сообщает, зачем правило
|
||||||
существует. Без обоснования не видно, когда причина отпала, — проверка
|
существует. Без обоснования не видно, когда причина отпала, — проверка
|
||||||
@@ -338,13 +417,26 @@ prefix: META
|
|||||||
подробностями идут; перенос деталей туда же вернул бы задачу поддержки двух
|
подробностями идут; перенос деталей туда же вернул бы задачу поддержки двух
|
||||||
текстов.
|
текстов.
|
||||||
|
|
||||||
## Освободившиеся номера
|
## Снятые правила
|
||||||
|
|
||||||
Номер удалённого правила не переиспользуется, поэтому дыры в нумерации —
|
Снятое правило остаётся здесь заглушкой: номер занят навсегда, ссылка на него
|
||||||
норма. Здесь перечислено, что́ под ними было: без этого упоминание номера в
|
ведёт к объяснению, а нумерация в файле остаётся сплошной (META-31).
|
||||||
прозе не отличить от ссылки на исчезнувшее правило.
|
|
||||||
|
|
||||||
| Номер | Что было | Почему снято |
|
### META-9. Общая механизация разрешала удалить норму из канона
|
||||||
|---|---|---|
|
|
||||||
| META-16 | имя файла — kebab-case | вреда от нарушения нет (META-25); осталось прозой в «Оформлении» |
|
**СНЯТО 2026-07-26.** Удаление нормы оставляло подписчика, пришедшего позже,
|
||||||
| META-26 | запрет слов обязательства в обосновании | правило о заглавных уже делает строчное слово ненормативным, а форму обоснования рамками не ограничивают |
|
без текста и без проверки, а условие «механизировано у всех» набору не
|
||||||
|
проверить: списка подписчиков у него нет. Взамен — META-8, запрет удалять
|
||||||
|
норму вообще.
|
||||||
|
|
||||||
|
### META-16. Имя файла — kebab-case
|
||||||
|
|
||||||
|
**СНЯТО 2026-07-26.** Вреда от нарушения нет, а значит нет и высшей
|
||||||
|
модальности (META-25): сборка идёт по имени темы из шапки, а не по имени
|
||||||
|
файла. Осталось прозой в разделе «Оформление».
|
||||||
|
|
||||||
|
### META-26. Запрет слов обязательства в обосновании
|
||||||
|
|
||||||
|
**СНЯТО 2026-07-26.** Правило о заглавных уже делает строчное «обязан»
|
||||||
|
ненормативным, поэтому запрет ничего не добавлял, а форму обоснования рамками
|
||||||
|
не ограничивают.
|
||||||
|
|||||||
+292
-83
@@ -12,6 +12,18 @@ version: 1
|
|||||||
пополниться, и текст, написанный по предыдущей версии, должен читаться по
|
пополниться, и текст, написанный по предыдущей версии, должен читаться по
|
||||||
той, по которой написан.
|
той, по которой написан.
|
||||||
|
|
||||||
|
Документ адресован автору набора и в репозиторий-потребитель не едет. К
|
||||||
|
читателю копии едет короткое `READING.md`: словарь со значениями, форма
|
||||||
|
правила и её граница, ссылки, локальная часть — без разделов о ведении набора.
|
||||||
|
Словарь в двух документах обязан совпадать (META-30), и это единственное
|
||||||
|
место, где между ними возможен дрейф.
|
||||||
|
|
||||||
|
Описание языка ни на один набор конвенций не опирается, поэтому все примеры
|
||||||
|
здесь — вымышленные правила с префиксами на `X` (`XKEY`, `XMIG`, `XLOG`).
|
||||||
|
Такие префиксы канон не занимает никогда, в манифесте набора их нет — значит
|
||||||
|
пример не спутать с настоящим правилом, а перенумерация конвенций описание
|
||||||
|
языка не задевает.
|
||||||
|
|
||||||
## Опора на стандарты
|
## Опора на стандарты
|
||||||
|
|
||||||
Язык не выводится из вкуса автора. Каждое решение о форме взято из
|
Язык не выводится из вкуса автора. Каждое решение о форме взято из
|
||||||
@@ -22,9 +34,9 @@ version: 1
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **BCP 14** (RFC 2119 + RFC 8174) | шкала модальности; правило «нормативно только заглавное»; сдержанность в высшей модальности; англоязычный словарь как готовый | синонимы `REQUIRED`, `RECOMMENDED`, `OPTIONAL`; `SHALL` как форма требования |
|
| **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 Directives, Part 2** | разделение «требование — рекомендация — разрешение — возможность»; запрет модальных глаголов в утверждениях о факте | списки равнозначных словесных форм («is to», «is required to», «only … is permitted») |
|
||||||
| **ISO/IEC/IEEE 29148** | обоснование как обязательный атрибут; единичность нормы; проверяемость; метод верификации отдельным атрибутом | остальной аппарат требований: приоритеты, источники, матрицы трассируемости |
|
| **ISO/IEC/IEEE 29148** | характеристики хорошего требования — единичность и проверяемость; обоснование и метод верификации как отдельные атрибуты требования | остальной аппарат требований: приоритеты, источники, матрицы трассируемости |
|
||||||
| **DMN** | таблица решений с объявленной политикой совпадения и требованием полноты | исполняемая семантика и всё, что предполагает движок решений |
|
| **DMN** | таблица решений с объявленной политикой совпадения | исполняемая семантика и всё, что предполагает движок решений |
|
||||||
| **EARS** | вывод о том, что выигрыш даёт жёсткий шаблон, а не его конкретный вид; паттерн «нежелательное поведение» — в виде таблицы | шаблоны как форма записи правила: `WHEN`, `WHILE`, `WHERE` |
|
| **EARS** | паттерн «нежелательное поведение» — в виде таблицы | шаблоны как форма записи правила: `WHEN`, `WHILE`, `WHERE` |
|
||||||
| **OpenSpec** | четырёхчастная форма правила; адресуемость правила идентификатором; форма «условие → следствие» для стыка правил | `SHALL`; `GIVEN/WHEN/THEN` как общая форма записи |
|
| **OpenSpec** | четырёхчастная форма правила; адресуемость правила идентификатором; форма «условие → следствие» для стыка правил | `SHALL`; `GIVEN/WHEN/THEN` как общая форма записи |
|
||||||
|
|
||||||
Три отклонения стоят объяснения, потому что выглядят как произвол.
|
Три отклонения стоят объяснения, потому что выглядят как произвол.
|
||||||
@@ -44,27 +56,50 @@ version: 1
|
|||||||
система, и её поведение разворачивается во времени: состояние, событие,
|
система, и её поведение разворачивается во времени: состояние, событие,
|
||||||
исход. У конвенции субъект — автор кода, и разворачивать нечего: есть
|
исход. У конвенции субъект — автор кода, и разворачивать нечего: есть
|
||||||
ситуация выбора и вердикт. Это таблица, а не траектория. Тем же рассуждением
|
ситуация выбора и вердикт. Это таблица, а не траектория. Тем же рассуждением
|
||||||
отклонены шаблоны EARS как форма записи правила, а взят из EARS другой
|
отклонены шаблоны EARS как форма записи правила, а взято из EARS другое —
|
||||||
результат: измеримый выигрыш дала там сама обязательность шаблона, а не его
|
сообщённое снижение числа дефектов после введения шаблонов. Вывод, что дело в
|
||||||
конкретная форма.
|
самой обязательности формы, а не в её конкретном виде, наш; он ниже, среди
|
||||||
|
усилений.
|
||||||
|
|
||||||
Исключение — стык правил, где субъект действительно система: там форма
|
Исключение — стык правил, где субъект действительно система: там форма
|
||||||
«условие → следствие» берётся сознательно, вместе со служебными словами под
|
«условие → следствие» берётся сознательно, вместе со служебными словами под
|
||||||
неё. Это единственное место, и оно описано в «Таблицах решений».
|
неё. Это единственное место, и оно описано в «Таблицах решений».
|
||||||
|
|
||||||
|
## Где источник усилен
|
||||||
|
|
||||||
|
Три решения идут дальше источника, и это наши решения, а не его требования.
|
||||||
|
Названы они отдельно, чтобы довод не подменялся ссылкой: спорить с ними нужно
|
||||||
|
по существу, а не со стандартом.
|
||||||
|
|
||||||
|
- **Обоснование обязательно.** В 29148 rationale — из списка рекомендуемых
|
||||||
|
атрибутов требования; обязательный костяк там другой, это характеристики
|
||||||
|
самого требования. Здесь правило без блока ПОЧЕМУ не принимается, потому что
|
||||||
|
конвенция живёт годами и переживает автора: норма без причины через год либо
|
||||||
|
отменяется первым возражением, либо соблюдается там, где вредит.
|
||||||
|
- **Полнота таблицы решений.** DMN даёт политику совпадения как именованный
|
||||||
|
атрибут, а полноты не требует: индикатор полноты был в первой версии
|
||||||
|
спецификации и из последующих убран, полноту проверяют валидаторы
|
||||||
|
инструментов. Здесь она требуется, потому что таблицу и заводят ради
|
||||||
|
видимости пропуска: неперечисленный случай в прозе не виден, а пустая
|
||||||
|
клетка видна.
|
||||||
|
- **Вывод про обязательность шаблона.** В EARS сообщается о снижении числа
|
||||||
|
дефектов в требованиях после введения шаблонов. Вывод, что выигрыш даёт сама
|
||||||
|
обязательность формы, а не её конкретный вид, — наш: он объясняет, почему мы
|
||||||
|
берём из EARS результат, но не берём сами шаблоны.
|
||||||
|
|
||||||
## Что даёт формализация
|
## Что даёт формализация
|
||||||
|
|
||||||
Адресуемое правило — не украшение формы, а условие работы трёх механизмов:
|
Адресуемое правило — не украшение формы, а условие работы трёх механизмов:
|
||||||
|
|
||||||
- **Механизация.** Запись о ней должна говорить «правило `MIGR-4` проверяет
|
- **Механизация.** Запись о ней должна говорить «правило `XMIG-4` проверяет
|
||||||
`archrules`», а не «`AUTOINCREMENT` в новых миграциях — `archrules`»: во
|
`archrules`», а не «`AUTOINCREMENT` в новых миграциях — `archrules`»: во
|
||||||
втором случае читатель сам догадывается, к какому утверждению это
|
втором случае читатель сам догадывается, к какому утверждению это
|
||||||
относится, и догадывается по-разному.
|
относится, и догадывается по-разному.
|
||||||
- **Отступления.** «У нас не так» бесполезно, пока не сказано, что именно
|
- **Отступления.** «У нас не так» бесполезно, пока не сказано, что именно
|
||||||
«не так». Со ссылкой на правило отступления становятся счётными: видно,
|
«не так». Со ссылкой на правило отступления становятся счётными: видно,
|
||||||
сколько правил конвенции репозиторий реально не соблюдает.
|
сколько правил конвенции репозиторий реально не соблюдает.
|
||||||
- **Промоут находки.** Путь «находка → конвенция → правило линтера →
|
- **Промоут находки.** Путь «находка → конвенция → правило линтера» требует
|
||||||
удаление прозы» требует ручки, за которую берут конкретное правило.
|
ручки, за которую берут конкретное правило.
|
||||||
|
|
||||||
Общий знаменатель — **идентификатор**. Модальные слова и таблицы полезны,
|
Общий знаменатель — **идентификатор**. Модальные слова и таблицы полезны,
|
||||||
но вторичны.
|
но вторичны.
|
||||||
@@ -72,7 +107,7 @@ version: 1
|
|||||||
## Единица — правило
|
## Единица — правило
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
### KEYS-5. Разбор внешнего идентификатора на границе
|
### XKEY-5. Разбор внешнего идентификатора на границе
|
||||||
|
|
||||||
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
|
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
|
||||||
к базе.
|
к базе.
|
||||||
@@ -83,20 +118,112 @@ version: 1
|
|||||||
```
|
```
|
||||||
|
|
||||||
Четыре обязательные части: **идентификатор**, **заголовок**, **модальность
|
Четыре обязательные части: **идентификатор**, **заголовок**, **модальность
|
||||||
с нормой**, **обоснование под меткой ПОЧЕМУ**. Норма — одна фраза; если в неё
|
с нормой**, **обоснование под меткой ПОЧЕМУ**. Пятый блок, ПРИМЕРЫ,
|
||||||
не влезает, это два правила. Требование единичности взято из ISO/IEC/IEEE
|
необязателен — о нём ниже. Норма — одна фраза; если в неё не влезает, это два
|
||||||
29148: составная норма не проверяема целиком, и нарушение одной её половины
|
правила. Требование единичности взято из ISO/IEC/IEEE 29148: составная норма
|
||||||
нечем адресовать.
|
не проверяема целиком, и нарушение одной её половины нечем адресовать.
|
||||||
|
|
||||||
Обе метки правила — модальное слово и ПОЧЕМУ — пишутся заглавными и
|
Метки правила — модальное слово, ПОЧЕМУ, ПРИМЕРЫ — пишутся заглавными и
|
||||||
принадлежат словарю набора: скелет правила читается одинаково в любом языке,
|
принадлежат словарю набора: скелет правила читается одинаково в любом языке,
|
||||||
на который канон переведён.
|
на который канон переведён.
|
||||||
|
|
||||||
|
**Правило кончается перед следующим заголовком.** Область правила — от его
|
||||||
|
заголовка до следующего заголовка любого уровня. Внутри области текст
|
||||||
|
принадлежит последнему открытому блоку: метка блок открывает, и блок длится
|
||||||
|
до следующей метки или до конца области.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### XKEY-3. Заголовок правила
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Норма одной фразой.
|
||||||
|
|
||||||
|
| № | ситуация | вердикт | ← блок нормы: таблица уточняет её
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Причина.
|
||||||
|
|
||||||
|
Продолжение причины, пример, ← блок обоснования продолжается
|
||||||
|
ссылка на внешнюю практику.
|
||||||
|
|
||||||
|
### XKEY-4. Следующее правило ← здесь область кончилась
|
||||||
|
```
|
||||||
|
|
||||||
|
Отсюда три следствия:
|
||||||
|
|
||||||
|
- **Хвост после ПОЧЕМУ — обоснование** до следующей метки или до конца
|
||||||
|
области, а не безымянная часть правила и не проза вокруг. Требований в нём
|
||||||
|
не живёт: то, что подлежит исполнению, стоит в блоке нормы, где у него есть
|
||||||
|
модальность и адрес. Требование, оставленное
|
||||||
|
в хвосте, требованием не является — сослаться на него нельзя и отступление
|
||||||
|
от него записать нельзя.
|
||||||
|
- **Таблица и список после модальной метки — часть нормы.** Правило,
|
||||||
|
классифицирующее ситуации, ровно так и записывается («Таблицы решений»), а
|
||||||
|
вердикт из такой таблицы адресуется номером строки.
|
||||||
|
- **Проза — это то, что лежит вне областей правил.** Тем самым проверка
|
||||||
|
«заглавных модальных слов вне правил нет» становится реализуемой: границу
|
||||||
|
считает разметка, а не читательское суждение о том, где правило кончилось.
|
||||||
|
|
||||||
|
Заглавное модальное слово внутри области правила законно, когда это
|
||||||
|
упоминание ступени в обосновании («для СЛЕДУЕТ это честно»). Метку от
|
||||||
|
упоминания отличает положение: метка стоит первой в своём абзаце, полужирным
|
||||||
|
и с точкой.
|
||||||
|
|
||||||
|
## Примеры к правилу
|
||||||
|
|
||||||
|
Пятый блок правила — необязательный, под меткой ПРИМЕРЫ. В нём код,
|
||||||
|
показывающий норму в деле, обычно парой «плохо → хорошо». Стоит он после
|
||||||
|
обоснования: сначала требование, потом причина, потом иллюстрация.
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
### XKEY-5. Внешний идентификатор разбирается до обращения к базе
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Значение, пришедшее снаружи, проходит разбор и нормализацию
|
||||||
|
раньше, чем по нему делается запрос.
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Синтаксически невалидное значение не может соответствовать
|
||||||
|
записи, поэтому поход в базу за ним — заведомо холостой.
|
||||||
|
|
||||||
|
**ПРИМЕРЫ.**
|
||||||
|
|
||||||
|
Плохо — строка уходит в запрос как пришла:
|
||||||
|
|
||||||
|
```go
|
||||||
|
row := db.QueryRow("select … where id = ?", r.PathValue("id"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Хорошо — разбор на границе, запроса при неудаче нет:
|
||||||
|
|
||||||
|
```go
|
||||||
|
id, err := ident.Parse(r.PathValue("id"))
|
||||||
|
if err != nil {
|
||||||
|
return notFound(w)
|
||||||
|
}
|
||||||
|
row := db.QueryRow("select … where id = ?", id)
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
**Пример иллюстрирует норму, а не задаёт её.** Три следствия, ради которых
|
||||||
|
это сказано:
|
||||||
|
|
||||||
|
- **требований в блоке нет.** Всё, что подлежит исполнению, стоит в блоке
|
||||||
|
нормы; деталь примера — имя переменной, конкретная функция, форма ответа —
|
||||||
|
требованием не становится. Разошёлся пример с нормой — действует норма, а
|
||||||
|
пример правят;
|
||||||
|
- **это не готовый сниппет.** Код в примере сокращён до того, что показывает
|
||||||
|
правило: обработка ошибок, контекст, импорты в нём условны, и копировать его
|
||||||
|
дословно не нужно;
|
||||||
|
- **пример стареет быстрее нормы.** Он привязан к сегодняшнему API, поэтому
|
||||||
|
расхождение примера с текущим кодом — повод поправить пример, а не отменять
|
||||||
|
правило.
|
||||||
|
|
||||||
|
Блок необязателен: он окупается там, где норму словами описать дороже, чем
|
||||||
|
показать, — форма вызова, структура записи в логе, раскладка файла. У правила
|
||||||
|
про выбор границы или про уровень лога иллюстрировать нечего.
|
||||||
|
|
||||||
## Обоснование обязательно
|
## Обоснование обязательно
|
||||||
|
|
||||||
Правило без блока ПОЧЕМУ не принимается. Это требование к форме, а не
|
Правило без блока ПОЧЕМУ не принимается. Это требование к форме, а не
|
||||||
пожелание; в 29148 обоснование — атрибут требования наравне с самим
|
пожелание. В 29148 обоснование — отдельный атрибут требования, но из
|
||||||
требованием, и по тем же причинам:
|
рекомендуемых; здесь оно обязательно, и вот почему:
|
||||||
|
|
||||||
- **Обоснование — единственный способ увидеть, что правило устарело.**
|
- **Обоснование — единственный способ увидеть, что правило устарело.**
|
||||||
Норма стареет молча; причина стареет заметно. Когда причина отпала, видно,
|
Норма стареет молча; причина стареет заметно. Когда причина отпала, видно,
|
||||||
@@ -114,9 +241,9 @@ version: 1
|
|||||||
|
|
||||||
Форма обоснования при этом ничем не ограничена: рамки здесь только
|
Форма обоснования при этом ничем не ограничена: рамки здесь только
|
||||||
смысловые. Абзац может быть длинным, вести рассуждение, приводить пример,
|
смысловые. Абзац может быть длинным, вести рассуждение, приводить пример,
|
||||||
ссылаться на внешние практики, стандарты и чужие проекты — канон это уже
|
ссылаться на стандарты, внешние практики и чужие проекты — на устройство
|
||||||
делает («адаптация OpenTelemetry», «как по умолчанию в zap и zerolog»,
|
OpenTelemetry, на умолчания библиотек логирования, на процедуру миграции из
|
||||||
двенадцатишаговая процедура SQLite). Запрещённых слов и обязательной
|
документации СУБД. Запрещённых слов и обязательной
|
||||||
структуры у обоснования нет, и заводить их не нужно: обязательность несёт
|
структуры у обоснования нет, и заводить их не нужно: обязательность несёт
|
||||||
норма, а обоснование её объясняет — путаницу между этими двумя ролями
|
норма, а обоснование её объясняет — путаницу между этими двумя ролями
|
||||||
исключает правило о заглавных.
|
исключает правило о заглавных.
|
||||||
@@ -162,18 +289,19 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
1. нарушение причиняет названный вред, а не расходится со вкусом — META-25,
|
1. нарушение причиняет названный вред, а не расходится со вкусом — META-25,
|
||||||
он же критерий BCP 14, где высшая модальность резервируется под то, что
|
он же критерий BCP 14, где высшая модальность резервируется под то, что
|
||||||
действительно ломается, и не употребляется для навязывания метода;
|
действительно ломается, и не употребляется для навязывания метода;
|
||||||
2. норма проверяема машиной — META-6, иначе обязательность держится на
|
2. вердикт о нарушении воспроизводим — META-6: по тексту правила двое
|
||||||
внимании и обещает то, чего не делает.
|
проверяющих приходят к одному ответу, иначе обязательность держится на
|
||||||
|
том, кто читал.
|
||||||
|
|
||||||
Не выполнено первое — правилу место в СЛЕДУЕТ или нигде. Не выполнено
|
Не выполнено первое — правилу место в СЛЕДУЕТ или нигде. Не выполнено
|
||||||
второе — в СЛЕДУЕТ. Проверяемость сама по себе не повышает правило до
|
второе — в СЛЕДУЕТ. Воспроизводимость сама по себе не повышает правило до
|
||||||
ДОЛЖЕН: механически проверяемых мелочей больше, чем важных вещей, и
|
ДОЛЖЕН: проверяемых мелочей больше, чем важных вещей, и безразборное
|
||||||
безразборное повышение обесценивает шкалу быстрее, чем её отсутствие.
|
повышение обесценивает шкалу быстрее, чем её отсутствие.
|
||||||
|
|
||||||
Модальность живёт на **правиле**, а не на файле. Файловый статус
|
Модальность живёт на **правиле**, а не на файле. Файловый статус
|
||||||
(`status: рекомендуемая` / `обязательная` в шапке) не используется: он
|
(`status: рекомендуемая` / `обязательная` в шапке) не используется: он
|
||||||
неизбежно врёт, потому что один файл смешивает жёсткие требования с
|
неизбежно врёт, потому что один файл смешивает жёсткие требования с
|
||||||
советами. В шапке остаются только `prefix` и `extends`.
|
советами. В шапке остаются только `topic`, `prefix` и `extends`.
|
||||||
|
|
||||||
## Словарь другого языка
|
## Словарь другого языка
|
||||||
|
|
||||||
@@ -192,14 +320,18 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
| рекомендация против | НЕ СЛЕДУЕТ | SHOULD NOT |
|
| рекомендация против | НЕ СЛЕДУЕТ | SHOULD NOT |
|
||||||
| разрешение | ДОПУСКАЕТСЯ | MAY |
|
| разрешение | ДОПУСКАЕТСЯ | MAY |
|
||||||
|
|
||||||
**Метки правила.** Обязательности не задают, а размечают его части.
|
**Метки.** Обязательности не задают, а размечают: ПОЧЕМУ — обоснование,
|
||||||
Стандартом не даются ни в одном языке: в BCP 14 таких понятий нет, слова
|
ПРИМЕРЫ — иллюстрации к норме, МЕХАНИЗИРОВАНО — запись о проверке в копии,
|
||||||
подбираются под язык так же, как остальные.
|
СНЯТО — заглушку на месте убранного правила. Стандартом не даются ни в одном
|
||||||
|
языке: в BCP 14 таких понятий нет, слова подбираются под язык так же, как
|
||||||
|
остальные.
|
||||||
|
|
||||||
| Метка | Русский | Английский |
|
| Метка | Русский | Английский |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| обоснование | ПОЧЕМУ | WHY |
|
| обоснование | ПОЧЕМУ | WHY |
|
||||||
|
| иллюстрации | ПРИМЕРЫ | EXAMPLES |
|
||||||
| способ проверки | МЕХАНИЗИРОВАНО | MECHANIZED |
|
| способ проверки | МЕХАНИЗИРОВАНО | MECHANIZED |
|
||||||
|
| снятое правило | СНЯТО | RETIRED |
|
||||||
|
|
||||||
**Служебные слова сценарного блока** — `КОГДА`, `ТОГДА`, `И`, `ИЛИ`; таблица
|
**Служебные слова сценарного блока** — `КОГДА`, `ТОГДА`, `И`, `ИЛИ`; таблица
|
||||||
и объяснение в разделе «Таблицы решений».
|
и объяснение в разделе «Таблицы решений».
|
||||||
@@ -226,15 +358,15 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
Каждая конвенция называет язык одной строкой во вводной прозе:
|
Каждая конвенция называет язык одной строкой во вводной прозе:
|
||||||
|
|
||||||
> Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
> Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
> ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
> ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
> тогда и только тогда, когда написаны заглавными.
|
> конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Слова в строке — из словаря того языка, на котором написан набор. Для
|
Слова в строке — из словаря того языка, на котором написан набор. Для
|
||||||
англоязычного набора та же строка выглядит так:
|
англоязычного набора та же строка выглядит так:
|
||||||
|
|
||||||
> The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY and the marks WHY
|
> The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY and the marks WHY,
|
||||||
> and MECHANIZED are to be interpreted as described in the conventions
|
> EXAMPLES, MECHANIZED and RETIRED are to be interpreted as described in the
|
||||||
> language, version 1, and only when written in capitals.
|
> conventions language, version 1, and only when written in capitals.
|
||||||
|
|
||||||
Форма скопирована у BCP 14, где та же задача решается тем же способом:
|
Форма скопирована у BCP 14, где та же задача решается тем же способом:
|
||||||
спецификация не прикладывает к себе словарь и не указывает путь к нему, а
|
спецификация не прикладывает к себе словарь и не указывает путь к нему, а
|
||||||
@@ -249,40 +381,55 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
правило обязательно, а о том, чем эта обязательность обеспечена. В 29148 это
|
правило обязательно, а о том, чем эта обязательность обеспечена. В 29148 это
|
||||||
два разных атрибута требования, и здесь тоже два.
|
два разных атрибута требования, и здесь тоже два.
|
||||||
|
|
||||||
Когда правило механизировано у всех потребителей, его норма из канона
|
**Проверяющий по умолчанию — читатель правила**, человек или агент. Канон
|
||||||
удаляется, а модальность и обоснование остаются:
|
пишется прежде всего под агента: он читает конвенцию и по ней смотрит код,
|
||||||
|
то есть проверка есть у каждого правила с первого дня, и её инструмент —
|
||||||
|
формулировка нормы. Поэтому вторым условием ДОЛЖЕН стоит воспроизводимость
|
||||||
|
вердикта (META-6), а не наличие скрипта: ступень говорит о важности нормы и о
|
||||||
|
том, сколько внимания она получает при проверке, а не о состоянии
|
||||||
|
инструментов. Линтер сильнее чтения — он не забывает, ничего не стоит на
|
||||||
|
каждом прогоне и краснеет до ревью, — поэтому механизация желательна везде,
|
||||||
|
где проверка пишется (META-27), и остаётся концом пути «находка → конвенция →
|
||||||
|
проверка». Но обязательным условием высшей ступени она не является: иначе весь
|
||||||
|
канон стоял бы в СЛЕДУЕТ до появления скриптов, которых пока нет ни одного.
|
||||||
|
|
||||||
|
**Механизация нормы не заменяет и не сокращает.** Норма остаётся в правиле
|
||||||
|
навсегда — как и обоснование (META-8, META-10), — сколько бы проверок её ни
|
||||||
|
подпирало. Причин три:
|
||||||
|
|
||||||
|
- **линтер сообщает, что нарушено, но не сообщает, что требуется.** Без нормы
|
||||||
|
правило нечем исполнить и не с чем сверить вердикт проверки, а проверяющий
|
||||||
|
по умолчанию читает именно норму;
|
||||||
|
- **подписчики появляются позже.** Репозиторий, подключившийся через год,
|
||||||
|
получил бы правило без нормы и без линтера — ни текста, ни проверки;
|
||||||
|
- **«механизировано у всех» набору не проверить:** списка подписчиков у него
|
||||||
|
нет по построению.
|
||||||
|
|
||||||
|
**Отметка — свойство репозитория, а не набора.** Механизирована норма или нет,
|
||||||
|
зависит от того, чей это репозиторий, поэтому в тексте конвенции отметки нет:
|
||||||
|
её место — запись о механизации в локальной части копии, со ссылкой на
|
||||||
|
идентификатор правила (META-7).
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
### MIGR-6. Дефолтов времени в схеме БД нет
|
<!-- conv:local -->
|
||||||
|
|
||||||
**ДОЛЖЕН. МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера;
|
XMIG-2, XMIG-4 — МЕХАНИЗИРОВАНО: `internal/archrules`, в новых миграциях.
|
||||||
формулировка удалена, потому что дублировала работающую проверку.
|
|
||||||
|
|
||||||
**ПОЧЕМУ.** Дефолт превращает забытую вставку в тихо работающий код…
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- Идентификатор и заголовок сохраняются: ссылки из репозиториев продолжают
|
Так у правила остаются оба атрибута сразу: обязательность — в норме, которая
|
||||||
указывать на то же утверждение.
|
приезжает из набора и одинакова у всех, способ проверки — в записи, которая
|
||||||
- Модальность сохраняется, поэтому «все ли ДОЛЖЕН механизированы»
|
принадлежит репозиторию и у каждого своя.
|
||||||
остаётся вычислимым вопросом, а не предметом чтения всего канона.
|
|
||||||
- Обоснование остаётся навсегда — линтер сообщает, что нарушено, но не
|
|
||||||
сообщает, зачем правило существует, и без обоснования нельзя понять,
|
|
||||||
когда проверку пора отменять.
|
|
||||||
|
|
||||||
Факт «механизировано у всех» устанавливается вручную: канон по построению
|
|
||||||
не знает списка подписчиков, и обойти репозитории перед удалением нормы —
|
|
||||||
часть работы, а не то, что можно проверить автоматически.
|
|
||||||
|
|
||||||
## Таблицы решений
|
## Таблицы решений
|
||||||
|
|
||||||
Часть правил **классифицирует ситуации**: какой уровень лога, какая
|
Часть правил **классифицирует ситуации**: какой уровень лога, какая
|
||||||
категория директории, что делать с невалидным вводом в зависимости от его
|
категория директории, что делать с невалидным вводом в зависимости от его
|
||||||
источника. Каноническая форма для них — таблица «ситуация → вердикт», строки
|
источника. Каноническая форма для них — таблица «ситуация → вердикт», строки
|
||||||
которой нумеруются как подпункты правила (`SLOG-8.1`).
|
которой нумеруются как подпункты правила (`XLOG-8.1`).
|
||||||
|
|
||||||
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а
|
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а
|
||||||
неупомянутый случай в абзаце — нет. Два свойства такой таблицы взяты из DMN,
|
неупомянутый случай в абзаце — нет. От такой таблицы требуются два свойства —
|
||||||
где они называются и проверяются:
|
первое названо в DMN, второе мы добавили сами («Где источник усилен»):
|
||||||
|
|
||||||
- **Политика совпадения.** По умолчанию строки взаимоисключающи: любой
|
- **Политика совпадения.** По умолчанию строки взаимоисключающи: любой
|
||||||
ситуации соответствует ровно одна. Если это не так, таблица объявляет
|
ситуации соответствует ровно одна. Если это не так, таблица объявляет
|
||||||
@@ -326,19 +473,30 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
|
|
||||||
## Идентификаторы
|
## Идентификаторы
|
||||||
|
|
||||||
- Формат — `<ПРЕФИКС>-<номер>`: `KEYS-5`, `SLOG-27`. Префикс принадлежит
|
Идентификаторов в языке два: **правило** адресуется префиксом с номером,
|
||||||
|
**конвенция целиком** — именем темы. Ссылаться путём к файлу нельзя ни на то,
|
||||||
|
ни на другое.
|
||||||
|
|
||||||
|
**Правило.**
|
||||||
|
|
||||||
|
- Формат — `<ПРЕФИКС>-<номер>`: `XKEY-5`, `XLOG-27`. Префикс принадлежит
|
||||||
файлу, нумерация внутри файла сквозная и начинается с единицы.
|
файлу, нумерация внутри файла сквозная и начинается с единицы.
|
||||||
- Строка таблицы, если на неё нужно ссылаться отдельно, — `KEYS-5.1`,
|
- Строка таблицы, если на неё нужно ссылаться отдельно, — `XKEY-5.1`,
|
||||||
`KEYS-5.2`.
|
`XKEY-5.2`.
|
||||||
- **Идентификатор глобален.** Префикс уникален по всему канону, поэтому
|
- **Идентификатор глобален.** Префикс уникален по всему канону, поэтому
|
||||||
путь файла в ссылке не нужен: `KEYS-5` адресует правило одинаково изнутри
|
путь файла в ссылке не нужен: `XKEY-5` адресует правило одинаково изнутри
|
||||||
файла, из соседней конвенции и из чужого репозитория. В собранной копии
|
файла, из соседней конвенции и из чужого репозитория. В собранной копии
|
||||||
слои разных осей лежат в одном документе, так что ссылка на базовый слой
|
слои разных осей лежат в одном документе, так что ссылка на базовый слой
|
||||||
из языкового вообще никуда не ведёт — правило рядом.
|
из языкового вообще никуда не ведёт — правило рядом.
|
||||||
- **Идентификаторы стабильны и не переиспользуются.** Удалённое правило
|
- **Идентификаторы стабильны и не переиспользуются.** Занять номер снятого
|
||||||
оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из
|
правила новым нельзя — иначе ссылка из чужого репозитория начнёт указывать
|
||||||
чужого репозитория начнёт указывать на другое утверждение. То же
|
на другое утверждение. То же относится к префиксам: выбывшие хранит манифест
|
||||||
относится к префиксам: выбывшие хранит `prefixes.toml`.
|
набора.
|
||||||
|
- **Снятое правило остаётся заглушкой.** Заголовок и номер сохраняются, норму
|
||||||
|
с обоснованием заменяет блок СНЯТО с датой и причиной. Поэтому нумерация в
|
||||||
|
файле сплошная, а любая ссылка разрешается — либо в правило, либо в
|
||||||
|
объяснение, почему его сняли (META-31, META-32). Отдельного реестра снятых
|
||||||
|
номеров нет: он был бы вторым источником правды рядом с файлом.
|
||||||
- Префикс **выбирается под файл, а не выводится по формуле**: он нужен,
|
- Префикс **выбирается под файл, а не выводится по формуле**: он нужен,
|
||||||
чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок
|
чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок
|
||||||
привязал бы идентификатор к таксономии, которую канон перестраивает, и
|
привязал бы идентификатор к таксономии, которую канон перестраивает, и
|
||||||
@@ -352,6 +510,25 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это
|
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это
|
||||||
идентификатор, а не позиция.
|
идентификатор, а не позиция.
|
||||||
|
|
||||||
|
**Тема.**
|
||||||
|
|
||||||
|
- **Тема — набор правил об одном фокусе разработки:** время, конфигурация,
|
||||||
|
схема БД. Она же — единица подписки: потребитель берёт тему целиком, а не
|
||||||
|
отдельные правила.
|
||||||
|
- Имя темы записывается латиницей. Рекомендуется нижний kebab-case
|
||||||
|
(`db-identifiers`), но годится любой идентификатор, пригодный для имени
|
||||||
|
файла: имя попадает и в файловую систему потребителя, и в его манифест.
|
||||||
|
- **Тему объявляет файл, а не файловая система.** Имя стоит в шапке
|
||||||
|
(`topic:`) и зарегистрировано в манифесте набора. Слои одной темы несут
|
||||||
|
одно и то же имя — по нему они и собираются в один документ, как бы ни
|
||||||
|
назывались их файлы.
|
||||||
|
- **Имя темы не переиспользуется** — как и префикс: оно живёт в шапке
|
||||||
|
`origin:` каждой копии, в подписке манифеста и в тексте ссылок, поэтому
|
||||||
|
снятое имя уходит в раздел выбывших манифеста, а не достаётся другой теме.
|
||||||
|
- Ссылка на конвенцию — имя темы (конвенция `logging`), ссылка на правило —
|
||||||
|
идентификатор (`XLOG-27`). Путь файла не употребляется ни там, ни там: в
|
||||||
|
собранной копии путей канона не существует.
|
||||||
|
|
||||||
## Что правилом не является
|
## Что правилом не является
|
||||||
|
|
||||||
Заглавные модальные слова в этих частях **не употребляются** — иначе
|
Заглавные модальные слова в этих частях **не употребляются** — иначе
|
||||||
@@ -364,6 +541,10 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
- **Локальная часть копии** — содержимое принадлежит репозиторию.
|
- **Локальная часть копии** — содержимое принадлежит репозиторию.
|
||||||
- Вводная проза, объясняющая предмет конвенции.
|
- Вводная проза, объясняющая предмет конвенции.
|
||||||
|
|
||||||
|
Все четыре части лежат вне областей правил: до первого заголовка правила или
|
||||||
|
после заголовка, которым область закрылась. Хвост обоснования сюда не
|
||||||
|
относится — он внутри правила, и модальные слова в нём законны как упоминания.
|
||||||
|
|
||||||
## Как на правила ссылаются копии
|
## Как на правила ссылаются копии
|
||||||
|
|
||||||
Ниже маркера локальной части, в репозитории:
|
Ниже маркера локальной части, в репозитории:
|
||||||
@@ -371,10 +552,9 @@ Directives, Part 2, по одной форме записи на ступень,
|
|||||||
```markdown
|
```markdown
|
||||||
<!-- conv:local -->
|
<!-- conv:local -->
|
||||||
|
|
||||||
MIGR-2, MIGR-4 механизированы — `internal/archrules` (проверяются в новых
|
XMIG-2, XMIG-4 — МЕХАНИЗИРОВАНО: `internal/archrules`, в новых миграциях.
|
||||||
миграциях).
|
|
||||||
|
|
||||||
MIGR-6 не соблюдается в легаси-таблицах `show_history`, `queue`: составные
|
XMIG-6 не соблюдается в легаси-таблицах `show_history`, `queue`: составные
|
||||||
ключи там появились до конвенции, переписывание требует миграции данных.
|
ключи там появились до конвенции, переписывание требует миграции данных.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -383,38 +563,67 @@ MIGR-6 не соблюдается в легаси-таблицах `show_histor
|
|||||||
|
|
||||||
## Что стоит проверять машиной
|
## Что стоит проверять машиной
|
||||||
|
|
||||||
Проверки применяются к файлам конвенций; обвязка канона в них не входит —
|
Проверке подлежит всё, что язык **употребляет**: файлы конвенций и документ,
|
||||||
она ключевые слова цитирует, а не употребляет. Ни одна пока не реализована,
|
которым канон сам себя ведёт (в этом каноне — `GUIDE.md`, префикс META). Файл,
|
||||||
поэтому при ревью их выполняют чтением.
|
который язык **цитирует**, — это описание вроде текущего: ключевые слова стоят
|
||||||
|
в нём как предмет разговора, а не как норма, и проверки к нему не применяются.
|
||||||
|
Различает не расположение файла, а роль слова в нём.
|
||||||
|
|
||||||
Разбором текста:
|
Ни одна проверка пока не реализована, поэтому при ревью их выполняют чтением.
|
||||||
|
|
||||||
|
**Форма правила** — разбором текста, в любом файле, который язык употребляет:
|
||||||
|
|
||||||
- модальные и служебные слова принадлежат объявленному словарю канона, а не
|
- модальные и служебные слова принадлежат объявленному словарю канона, а не
|
||||||
смеси словарей;
|
смеси словарей;
|
||||||
- префикс в шапке файла совпадает с реестром, состоит из четырёх заглавных
|
- префикс в шапке файла совпадает с манифестом набора, состоит из четырёх
|
||||||
латинских букв, не начинается на `X` и не значится в списке выбывших;
|
заглавных латинских букв, не начинается на `X` и не значится в списке
|
||||||
|
выбывших;
|
||||||
- заголовки правил файла используют только его собственный префикс;
|
- заголовки правил файла используют только его собственный префикс;
|
||||||
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило
|
- нумерация внутри файла сплошная: от единицы до наибольшего номера без
|
||||||
берёт следующий свободный, а не первый освободившийся);
|
пропусков, номера не повторяются, новое правило берёт следующий за
|
||||||
- у каждого `### <ПРЕФИКС>-<n>` есть модальное слово и блок ПОЧЕМУ;
|
наибольшим (META-31);
|
||||||
отметка МЕХАНИЗИРОВАНО стоит рядом с модальностью, а не вместо неё;
|
- у каждого `### <ПРЕФИКС>-<n>` есть либо модальное слово с нормой и блок
|
||||||
|
ПОЧЕМУ — ни норма, ни обоснование не удаляются никогда (META-8, META-10), —
|
||||||
|
либо блок СНЯТО с датой и причиной;
|
||||||
|
- блок ПРИМЕРЫ, если он есть, стоит после обоснования и не открывает правило:
|
||||||
|
порядок блоков — норма, ПОЧЕМУ, ПРИМЕРЫ;
|
||||||
- вводная проза содержит строку о версии языка;
|
- вводная проза содержит строку о версии языка;
|
||||||
- ссылки вида `<ПРЕФИКС>-<n>` — хоть в тексте канона, хоть в локальной части
|
- ссылки вида `<ПРЕФИКС>-<n>` — хоть в тексте набора, хоть в локальной части
|
||||||
копии — указывают на правила, которые ещё существуют;
|
копии — разрешаются: неразрешённый идентификатор всегда ошибка (META-32);
|
||||||
|
- заглавные модальные слова не встречаются вне областей правил (область —
|
||||||
|
от заголовка правила до следующего заголовка) — кроме строки о версии
|
||||||
|
языка, которая их перечисляет по назначению;
|
||||||
|
- модальная метка стоит первой в своём абзаце: заглавное слово в середине
|
||||||
|
фразы — упоминание ступени, а не вторая норма правила.
|
||||||
|
|
||||||
|
**Распространение** — разбором текста, только в файлах конвенций: эти проверки
|
||||||
|
о том, что документ уезжает к потребителю, а документ, которым канон ведёт
|
||||||
|
себя, не уезжает никуда.
|
||||||
|
|
||||||
|
- шапка файла несёт имя темы, и это имя стоит в манифесте набора — среди
|
||||||
|
живых, а не среди выбывших;
|
||||||
|
- имя темы, названное в ссылке или в подписке потребителя, тоже разрешается по
|
||||||
|
манифесту: ссылка на снятую тему не проходит молча;
|
||||||
- префиксы локальных правил копии начинаются на `X`;
|
- префиксы локальных правил копии начинаются на `X`;
|
||||||
- заглавные модальные слова не встречаются вне правил — кроме строки о
|
- отметки МЕХАНИЗИРОВАНО в тексте конвенции нет: её место — запись о
|
||||||
версии языка, которая их перечисляет по назначению;
|
механизации в локальной части копии (META-7);
|
||||||
|
- словарь в коротком описании языка совпадает с этим: те же ступени, те же
|
||||||
|
метки, те же значения (META-30);
|
||||||
- префикс **чужой темы** не встречается в абзаце с модальностью (META-20);
|
- префикс **чужой темы** не встречается в абзаце с модальностью (META-20);
|
||||||
префикс арх-слоя своей темы там допустим (META-24), префикс другого языка
|
префикс арх-слоя своей темы там допустим (META-24), префикс другого языка
|
||||||
или стека — нет;
|
или стека — нет;
|
||||||
- путь файла канона не встречается в тексте конвенции (META-21).
|
- путь файла канона не встречается в тексте конвенции (META-21).
|
||||||
|
|
||||||
Чтением, потому что машине не даётся:
|
**Чтением**, потому что машине не даётся:
|
||||||
|
|
||||||
- строки таблицы взаимоисключающи либо политика совпадения объявлена;
|
- строки таблицы взаимоисключающи либо политика совпадения объявлена;
|
||||||
- перечисленные в таблице случаи покрывают область действия;
|
- перечисленные в таблице случаи покрывают область действия;
|
||||||
- норма исполнима без обращения к другим файлам;
|
- норма исполнима без обращения к другим файлам (в файлах конвенций: они
|
||||||
- обоснование отвечает на «что сломается», а не пересказывает норму.
|
уезжают по одной, а обвязка ссылается на соседей свободно);
|
||||||
|
- обоснование отвечает на «что сломается», а не пересказывает норму;
|
||||||
|
- хвост обоснования не вводит требований, которых нет в блоке нормы;
|
||||||
|
- примеры иллюстрируют норму и не расширяют её: деталь примера не читается
|
||||||
|
как требование.
|
||||||
|
|
||||||
## Версия языка
|
## Версия языка
|
||||||
|
|
||||||
|
|||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
version: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Как читать конвенцию
|
||||||
|
|
||||||
|
Файлы рядом с этим — конвенции: правила о том, как в этом репозитории пишут
|
||||||
|
код. Здесь сказано, как они записаны: что означают заглавные слова, из чего
|
||||||
|
состоит правило и как на него сослаться. Читается один раз, дальше нужен как
|
||||||
|
справка.
|
||||||
|
|
||||||
|
Файл кладёт сюда сборщик конвенций и перезаписывает целиком при каждом
|
||||||
|
обновлении. Правки в нём не живут.
|
||||||
|
|
||||||
|
## Ключевые слова
|
||||||
|
|
||||||
|
Заглавное слово в начале абзаца задаёт обязательность правила.
|
||||||
|
|
||||||
|
| Слово | Что означает | Если делаем иначе |
|
||||||
|
|---|---|---|
|
||||||
|
| **ДОЛЖЕН** | нарушение считается ошибкой | только с записью в отступления |
|
||||||
|
| **НЕ ДОЛЖЕН** | запрет, та же строгость | то же |
|
||||||
|
| **СЛЕДУЕТ** | сильная рекомендация: новый код пишем так | допустимо, причину записываем |
|
||||||
|
| **НЕ СЛЕДУЕТ** | обратное к СЛЕДУЕТ | то же |
|
||||||
|
| **ДОПУСКАЕТСЯ** | выбор за автором кода | ничего не требуется — правило не запрещает |
|
||||||
|
|
||||||
|
Две вещи, которые легко прочитать неверно:
|
||||||
|
|
||||||
|
- **ДОПУСКАЕТСЯ — не бытовое «можно».** У слова есть вторая половина: выбор,
|
||||||
|
помеченный им, на ревью не обсуждается. Возражение «сделай иначе» против
|
||||||
|
такого выбора не принимается — иначе разрешение ничего не значило бы.
|
||||||
|
- **Отступление от ДОЛЖЕН — не запрет на отступление.** Нарушать можно, но
|
||||||
|
тогда об этом появляется запись: какое правило, где именно, почему. Разница
|
||||||
|
между ДОЛЖЕН и СЛЕДУЕТ — в том, чем платят за отклонение, а не в том,
|
||||||
|
возможно ли оно.
|
||||||
|
|
||||||
|
Ещё четыре метки заглавными: **ПОЧЕМУ** открывает обоснование правила,
|
||||||
|
**ПРИМЕРЫ** — код, показывающий норму в деле, **МЕХАНИЗИРОВАНО** стоит при
|
||||||
|
записи о том, что правило проверяет линтер или скрипт, **СНЯТО** — на месте
|
||||||
|
правила, которое убрали.
|
||||||
|
|
||||||
|
Заглушка со СНЯТО занимает место убранного правила вместе с его номером:
|
||||||
|
так нумерация остаётся сплошной, а ссылка на снятое правило приводит к
|
||||||
|
объяснению, а не в пустоту. Требований в такой заглушке нет.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### XLOG-4. Уровень записи выбирался по громкости отказа
|
||||||
|
|
||||||
|
**СНЯТО 2026-05-14.** Заменено на XLOG-8: громкость каждый оценивал
|
||||||
|
по-своему, и шкала расползалась.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Нормативно только заглавное написание.** Строчное «должен» в прозе — обычная
|
||||||
|
речь, а не норма; спорить с ней как с правилом не нужно.
|
||||||
|
|
||||||
|
## Из чего состоит правило
|
||||||
|
|
||||||
|
Правило в примере вымышленное: префиксы на `X` общий набор не занимает
|
||||||
|
никогда, поэтому пример нельзя спутать с настоящим правилом.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### XLOG-8. Уровень выбирается по адресату
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Уровень отвечает на вопрос «кому сообщение», а не «насколько
|
||||||
|
громко сломалось».
|
||||||
|
|
||||||
|
| № | Уровень | Кому и когда |
|
||||||
|
|---|---|---|
|
||||||
|
| XLOG-8.1 | `DEBUG` | разработчику при отладке; в проде выключен |
|
||||||
|
| XLOG-8.2 | `INFO` | владельцу, аудит постфактум |
|
||||||
|
|
||||||
|
**ПОЧЕМУ.** Адресат — единственный признак, по которому разные авторы в
|
||||||
|
разных местах кода выберут уровень одинаково…
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Идентификатор и заголовок.** `XLOG-8` — адрес правила: по нему на правило
|
||||||
|
ссылаются, им помечают отступления и механизацию.
|
||||||
|
- **Модальность с нормой.** Собственно требование, одной фразой. Таблица или
|
||||||
|
список сразу за модальным словом — часть нормы: она уточняет вердикт, и на
|
||||||
|
её строку ссылаются номером (`XLOG-8.2`).
|
||||||
|
- **ПОЧЕМУ.** Зачем правило существует и что сломается, если сделать иначе.
|
||||||
|
Обоснование ничего не требует — по нему решают, применимо ли правило к
|
||||||
|
случаю, и видно, когда причина отпала.
|
||||||
|
- **ПРИМЕРЫ** — необязательный последний блок: код, обычно парой «плохо →
|
||||||
|
хорошо». Иллюстрация, а не спецификация: деталь примера требованием не
|
||||||
|
становится, дословно копировать его не нужно, а если пример разошёлся с
|
||||||
|
нормой — действует норма.
|
||||||
|
|
||||||
|
**Правило кончается перед следующим заголовком.** Абзацы после ПОЧЕМУ — это
|
||||||
|
продолжение обоснования: примеры, разбор границ, ссылки на внешние практики.
|
||||||
|
Требований в них нет; всё, что подлежит исполнению, стоит в блоке нормы.
|
||||||
|
|
||||||
|
## Как ссылаться
|
||||||
|
|
||||||
|
- На **правило** — идентификатором: `XLOG-27`. Путь к файлу не нужен,
|
||||||
|
идентификатор уникален.
|
||||||
|
- На **конвенцию целиком** — именем темы: конвенция `logging`. Имя темы стоит
|
||||||
|
в шапке файла (`origin:`).
|
||||||
|
- Строка таблицы адресуется номером с точкой: `XLOG-8.2`.
|
||||||
|
|
||||||
|
## Что ниже маркера
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<!-- conv:local -->
|
||||||
|
```
|
||||||
|
|
||||||
|
Всё выше маркера приезжает из общего набора и перезаписывается при
|
||||||
|
обновлении. Всё ниже принадлежит этому репозиторию и обновление переживает.
|
||||||
|
Там живёт:
|
||||||
|
|
||||||
|
- **отступления** — какое правило не соблюдается, где и почему: «`XMIG-6` не
|
||||||
|
соблюдается в `queue`: составные ключи там появились до конвенции»;
|
||||||
|
- **механизация** — кто проверяет правило машинно: «`XMIG-4` —
|
||||||
|
МЕХАНИЗИРОВАНО: `internal/archrules`»;
|
||||||
|
- **разрешение условий**, которые правило оставило открытыми;
|
||||||
|
- **свои правила** — по той же форме, но с префиксом на `X` (`XLOG-1`).
|
||||||
|
Префиксы на `X` общий набор не занимает никогда, так что столкнуться они не
|
||||||
|
могут.
|
||||||
|
|
||||||
|
Правка выше маркера живёт до первого обновления и исчезает молча. Если
|
||||||
|
исправить нужно приехавший текст — либо правку переносят в общий набор, либо
|
||||||
|
файл перестаёт быть копией: из шапки убирают `origin:`.
|
||||||
|
|
||||||
|
## Чего в конвенции не бывает
|
||||||
|
|
||||||
|
- **Утверждений о том, как сейчас устроен этот репозиторий.** Правило пишется
|
||||||
|
в предписывающем времени; «у нас пока не так» — это отступление, и его
|
||||||
|
место ниже маркера.
|
||||||
|
- **Заглавных ключевых слов вне правил.** Во вводной прозе, в разделах
|
||||||
|
«Область действия» и «Связано» их нет, поэтому искать там требования не
|
||||||
|
нужно.
|
||||||
|
|
||||||
|
Язык записи — версия 1. Полное описание живёт в наборе конвенций, у автора;
|
||||||
|
здесь ровно то, что нужно читателю.
|
||||||
@@ -12,13 +12,15 @@
|
|||||||
| `README.md` | устройство канона, оси, сборка копий, жизненный цикл |
|
| `README.md` | устройство канона, оси, сборка копий, жизненный цикл |
|
||||||
| [LANGUAGE.md](LANGUAGE.md) | язык записи правил: идентификаторы, модальность, обоснование |
|
| [LANGUAGE.md](LANGUAGE.md) | язык записи правил: идентификаторы, модальность, обоснование |
|
||||||
| [GUIDE.md](GUIDE.md) | как ведут конвенции: когда заводить, механизация, отступления |
|
| [GUIDE.md](GUIDE.md) | как ведут конвенции: когда заводить, механизация, отступления |
|
||||||
| `prefixes.toml` | реестр префиксов правил |
|
| [READING.md](READING.md) | как читать конвенцию: то, что едет к потребителю |
|
||||||
|
| [manifest.toml](manifest.toml) | манифест набора: язык, темы, префиксы правил |
|
||||||
| `conv` | сборка копий |
|
| `conv` | сборка копий |
|
||||||
|
|
||||||
Обвязка живёт только в каноне и в репозитории не оказывается — в копию едет
|
К потребителю едет содержимое `conventions/` и один файл обвязки —
|
||||||
лишь содержимое `conventions/`. Самодостаточность копии это не нарушает:
|
`READING.md`; остальная обвязка остаётся в каноне. Самодостаточность копии это
|
||||||
конвенция называет язык записи одной строкой с номером версии и не ссылается
|
не нарушает: конвенция называет язык записи одной
|
||||||
на путь (`LANGUAGE.md`, раздел «Ссылка на язык из конвенции»).
|
строкой с номером версии и не ссылается на путь (`LANGUAGE.md`, раздел «Ссылка
|
||||||
|
на язык из конвенции»).
|
||||||
|
|
||||||
Правило то же, что у ролей: **деплоится и читается только то, что лежит в
|
Правило то же, что у ролей: **деплоится и читается только то, что лежит в
|
||||||
git репозитория**. Канон никем не подключается на лету.
|
git репозитория**. Канон никем не подключается на лету.
|
||||||
@@ -55,8 +57,9 @@ conventions/
|
|||||||
тему. Пути файлов даются относительно `conventions/`
|
тему. Пути файлов даются относительно `conventions/`
|
||||||
(`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии.
|
(`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии.
|
||||||
На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс
|
На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс
|
||||||
уникален по всему канону (реестр — `prefixes.toml`), поэтому идентификатор
|
уникален по всему канону (он перечислен в манифесте набора), поэтому
|
||||||
не зависит ни от оси, ни от того, как собран файл у потребителя.
|
идентификатор не зависит ни от оси, ни от того, как собран файл у
|
||||||
|
потребителя.
|
||||||
|
|
||||||
Тест — по тому, замена чего убивает правило:
|
Тест — по тому, замена чего убивает правило:
|
||||||
|
|
||||||
@@ -81,6 +84,31 @@ conventions/
|
|||||||
пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая
|
пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая
|
||||||
работа.
|
работа.
|
||||||
|
|
||||||
|
## Темы
|
||||||
|
|
||||||
|
**Тема — набор правил об одном фокусе разработки:** время, конфигурация,
|
||||||
|
схема БД. Она же единица подписки и единица сборки: потребитель берёт тему
|
||||||
|
целиком, а сборщик складывает в один файл все её слои.
|
||||||
|
|
||||||
|
Имя темы записывается латиницей; рекомендуется нижний kebab-case, но годится
|
||||||
|
любой идентификатор, пригодный для имени файла — имя попадает и в файловую
|
||||||
|
систему потребителя, и в его манифест. Файл конвенции объявляет тему в шапке:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
topic: db-identifiers
|
||||||
|
prefix: KEYS
|
||||||
|
```
|
||||||
|
|
||||||
|
Слои одной темы несут одно и то же имя — по нему они и собираются в один
|
||||||
|
документ, как бы ни назывались их файлы. Имя файла повторяет тему из
|
||||||
|
удобства, но истина — в шапке.
|
||||||
|
|
||||||
|
Темы перечислены в манифесте набора — [`manifest.toml`](manifest.toml),
|
||||||
|
секция `[topics.live]`: имя и однострочное описание. Имя темы не
|
||||||
|
переиспользуется по той же причине, что и префикс: оно живёт в чужих
|
||||||
|
репозиториях — в шапке `origin:` каждой копии, в подписке манифеста, в тексте
|
||||||
|
ссылок, — и выданное второй теме начинает указывать на другой набор правил.
|
||||||
|
|
||||||
## Префиксы
|
## Префиксы
|
||||||
|
|
||||||
Каждый файл канона объявляет в шапке свой префикс правил:
|
Каждый файл канона объявляет в шапке свой префикс правил:
|
||||||
@@ -89,10 +117,11 @@ conventions/
|
|||||||
prefix: KEYS
|
prefix: KEYS
|
||||||
```
|
```
|
||||||
|
|
||||||
Четыре заглавные латинские буквы, уникальные по всему канону; реестр —
|
Четыре заглавные латинские буквы, уникальные по всему канону; перечислены в
|
||||||
[`prefixes.toml`](prefixes.toml). Префикс выбирается под файл, а не выводится
|
манифесте набора, секция `[prefixes.live]`. Префикс выбирается под файл, а не
|
||||||
по формуле, и не переиспользуется никогда. Правила адресуются идентификатором
|
выводится по формуле, и не переиспользуется никогда. Правила адресуются
|
||||||
`KEYS-5` — без пути к файлу. Подробности формы — `LANGUAGE.md`.
|
идентификатором `KEYS-5` — без пути к файлу. Подробности формы —
|
||||||
|
`LANGUAGE.md`.
|
||||||
|
|
||||||
Буква `X` в начале префикса зарезервирована за репозиториями: канон её не
|
Буква `X` в начале префикса зарезервирована за репозиториями: канон её не
|
||||||
занимает никогда, а локальные правила потребителя берут префиксы только на
|
занимает никогда, а локальные правила потребителя берут префиксы только на
|
||||||
@@ -124,6 +153,7 @@ extends: arch/db-identifiers.md
|
|||||||
```
|
```
|
||||||
docs/conventions/
|
docs/conventions/
|
||||||
README.md собственный, не собирается
|
README.md собственный, не собирается
|
||||||
|
READING.md как читать конвенцию — приезжает из канона
|
||||||
time.md arch/time.md + lang/go/time.md
|
time.md arch/time.md + lang/go/time.md
|
||||||
db-identifiers.md arch/db-identifiers.md + lang/go/db-identifiers.md
|
db-identifiers.md arch/db-identifiers.md + lang/go/db-identifiers.md
|
||||||
app-directories.md arch/… + stack/ansible/…
|
app-directories.md arch/… + stack/ansible/…
|
||||||
@@ -132,6 +162,10 @@ docs/conventions/
|
|||||||
Так конвенция остаётся самодостаточным документом: тот, кто проверяет по ней
|
Так конвенция остаётся самодостаточным документом: тот, кто проверяет по ней
|
||||||
код — человек или агент, — читает один файл и не собирает тему из трёх мест.
|
код — человек или агент, — читает один файл и не собирает тему из трёх мест.
|
||||||
|
|
||||||
|
Имена в директории делятся на три вида: `README.md` принадлежит репозиторию и
|
||||||
|
сборщик его не трогает, `READING.md` принадлежит канону и перезаписывается
|
||||||
|
целиком, остальные файлы — копии тем с шапкой `origin:` и локальной частью.
|
||||||
|
|
||||||
**Шапка копии** ставится при сборке и в каноне не хранится:
|
**Шапка копии** ставится при сборке и в каноне не хранится:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -140,10 +174,11 @@ origin: time
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
Больше в шапке ничего нет. Отпечатка канона и даты синхронизации в ней не
|
В `origin:` стоит имя темы — то же, что в манифесте набора и в шапках
|
||||||
хранится: обновление перезаписывает файл в рабочем дереве, и что именно
|
`topic:` слоёв, из которых файл собран. Больше в шапке ничего нет: отпечатка
|
||||||
изменилось, показывает `git diff` до коммита. Второй механизм сравнения
|
канона и даты синхронизации в ней не хранится, потому что обновление
|
||||||
рядом с git не нужен.
|
перезаписывает файл в рабочем дереве, и что именно изменилось, показывает
|
||||||
|
`git diff` до коммита. Второй механизм сравнения рядом с git не нужен.
|
||||||
|
|
||||||
**Маркер локальной части** — единственная машинно значимая разметка внутри
|
**Маркер локальной части** — единственная машинно значимая разметка внутри
|
||||||
файла:
|
файла:
|
||||||
@@ -151,7 +186,7 @@ origin: time
|
|||||||
```markdown
|
```markdown
|
||||||
<!-- conv:local -->
|
<!-- conv:local -->
|
||||||
|
|
||||||
MIGR-2, MIGR-4 механизированы — `internal/archrules`.
|
MIGR-2, MIGR-4 — МЕХАНИЗИРОВАНО: `internal/archrules`.
|
||||||
MIGR-6 не соблюдается в `show_history`, `queue`: составные ключи там
|
MIGR-6 не соблюдается в `show_history`, `queue`: составные ключи там
|
||||||
появились до конвенции, миграция данных не окупается.
|
появились до конвенции, миграция данных не окупается.
|
||||||
```
|
```
|
||||||
@@ -170,10 +205,36 @@ MIGR-6 не соблюдается в `show_history`, `queue`: составны
|
|||||||
репозитория. Файл, оставивший шапку, при следующем обновлении потеряет
|
репозитория. Файл, оставивший шапку, при следующем обновлении потеряет
|
||||||
всё, что выше маркера.
|
всё, что выше маркера.
|
||||||
|
|
||||||
## Манифест
|
## Язык записи едет вместе с копиями
|
||||||
|
|
||||||
Откуда взяты копии и где брать обновления — `.conventions.toml` в корне
|
Конвенция называет язык одной строкой с номером версии и без пути — строка
|
||||||
репозитория-потребителя:
|
работает и сама по себе. Но семантика заглавных слов живёт в описании языка, а
|
||||||
|
описание в репозиторий-потребитель раньше не попадало: агент, читающий копию,
|
||||||
|
принимал ДОПУСКАЕТСЯ за бытовое «можно» и терял ровно то, ради чего слово
|
||||||
|
введено.
|
||||||
|
|
||||||
|
Поэтому в `docs/conventions/` сборщик кладёт `READING.md` — короткое описание
|
||||||
|
для читателя правил: словарь со значениями, правило заглавных, из чего состоит
|
||||||
|
правило и где его граница, как ссылаться, что живёт ниже маркера. Полное
|
||||||
|
[LANGUAGE.md](LANGUAGE.md) остаётся в каноне: три его раздела адресованы
|
||||||
|
автору набора и ссылаются на правила `GUIDE.md`, которых у потребителя нет.
|
||||||
|
|
||||||
|
Два документа — один словарь, и это единственное место, где возможен дрейф.
|
||||||
|
Правка ключевых слов или состава частей правила обязана дойти до `READING.md`
|
||||||
|
(META-30), а сверить их дёшево: таблицы либо совпадают, либо нет.
|
||||||
|
|
||||||
|
## Два манифеста
|
||||||
|
|
||||||
|
Манифестов в модели два, и они отвечают на разные вопросы:
|
||||||
|
|
||||||
|
| Файл | Где лежит | Что описывает |
|
||||||
|
|---|---|---|
|
||||||
|
| `manifest.toml` | в наборе | сам набор: темы и префиксы правил |
|
||||||
|
| `.conventions.toml` | в проекте | подключение: откуда копии, какие темы, язык, стек |
|
||||||
|
|
||||||
|
Манифест набора — единственное место, где перечислены оба идентификатора
|
||||||
|
канона; правила у них общие, поэтому и файл один. Манифест подключения
|
||||||
|
отвечает, откуда взяты копии и где брать обновления:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git"
|
source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git"
|
||||||
@@ -185,8 +246,10 @@ topics = ["time", "config", "db-identifiers"]
|
|||||||
```
|
```
|
||||||
|
|
||||||
`lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает
|
`lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает
|
||||||
только те слои, которые репозиторию подходят. `topics` — подписка; списка
|
только те слои, которые репозиторию подходят. `topics` — подписка, именами из
|
||||||
подписчиков у канона по-прежнему нет, список тем есть только у потребителя.
|
манифеста набора; списка подписчиков у канона по-прежнему нет, список подписок
|
||||||
|
есть
|
||||||
|
только у потребителя.
|
||||||
|
|
||||||
Как именно инструмент добирается до канона — путь на диске, git, HTTP —
|
Как именно инструмент добирается до канона — путь на диске, git, HTTP —
|
||||||
дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это
|
дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это
|
||||||
@@ -213,6 +276,7 @@ topics = ["time", "config", "db-identifiers"]
|
|||||||
conv list # какие темы есть в каноне
|
conv list # какие темы есть в каноне
|
||||||
conv add time # добавить тему в манифест и собрать файл
|
conv add time # добавить тему в манифест и собрать файл
|
||||||
conv pull # пересобрать всё, что перечислено в манифесте
|
conv pull # пересобрать всё, что перечислено в манифесте
|
||||||
|
# (и обновить READING.md рядом с копиями)
|
||||||
```
|
```
|
||||||
|
|
||||||
Отчёт о том, что изменилось, отдельной командой не выдаётся: после `pull`
|
Отчёт о том, что изменилось, отдельной командой не выдаётся: после `pull`
|
||||||
@@ -250,6 +314,7 @@ conv pull # пересобрать всё, что переч
|
|||||||
Модель выше — согласованная, а не реализованная. `conv` пока собран под
|
Модель выше — согласованная, а не реализованная. `conv` пока собран под
|
||||||
прежнюю: зеркальное дерево копий вместо плоского, именованные регионы
|
прежнюю: зеркальное дерево копий вместо плоского, именованные регионы
|
||||||
`<!-- local:имя -->` вместо одного маркера, `origin_hash` в шапке и команды
|
`<!-- local:имя -->` вместо одного маркера, `origin_hash` в шапке и команды
|
||||||
`status`, `diff`, `push`. Сами конвенции уже приведены к новой модели —
|
`status`, `diff`, `push`; `READING.md` рядом с копиями он тоже пока не
|
||||||
именованных регионов в каноне нет. Ни один репозиторий-потребитель не
|
кладёт. Сами конвенции уже приведены к новой модели — именованных регионов в
|
||||||
|
каноне нет. Ни один репозиторий-потребитель не
|
||||||
подключён, поэтому переход никого не ломает.
|
подключён, поэтому переход никого не ломает.
|
||||||
|
|||||||
@@ -4,23 +4,67 @@
|
|||||||
решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в
|
решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в
|
||||||
`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле.
|
`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле.
|
||||||
|
|
||||||
## 1. Тулинг: две разные задачи в одном `conv`
|
Две секции: сначала язык и подход, потом канон с тулингом.
|
||||||
|
|
||||||
|
# Язык и подход
|
||||||
|
|
||||||
|
## 1. Одиннадцать таблиц не прочитаны на взаимоисключительность
|
||||||
|
|
||||||
|
`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по
|
||||||
|
умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы
|
||||||
|
такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна
|
||||||
|
таблица под новое требование не прочитана.
|
||||||
|
|
||||||
|
Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению»
|
||||||
|
против «повторяющаяся служебная, по таймеру или поллингу». Периодическая
|
||||||
|
операция, которая всё-таки меняет данные, подходит под обе строки, и уровень
|
||||||
|
из таблицы не выводится однозначно.
|
||||||
|
|
||||||
|
Работа читательская, машине не даётся; в список проверок она уже записана в
|
||||||
|
разделе «Чтением, потому что машине не даётся».
|
||||||
|
|
||||||
|
## 2. Описание языка отдельно от набора конвенций
|
||||||
|
|
||||||
|
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
|
||||||
|
`conventions/` — **один конкретный** набор. Сейчас они склеены в одном
|
||||||
|
репозитории, и из одного описания нельзя собрать второй набор (рабочий,
|
||||||
|
доменный, чужой).
|
||||||
|
|
||||||
|
Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ
|
||||||
|
`version:`), и конвенции ссылаются на неё номером, а не путём, — то есть
|
||||||
|
самодостаточность копии выноса не требует. Примеры в `LANGUAGE.md` вдобавок
|
||||||
|
переведены на вымышленные `X`-правила, так что на конкретный набор описание
|
||||||
|
языка больше не ссылается вовсе.
|
||||||
|
|
||||||
|
Что осталось поводом:
|
||||||
|
|
||||||
|
- из одного описания по-прежнему нельзя собрать второй набор;
|
||||||
|
- тулинг валидирует правила, зашитые в его код, а не объявленную версию
|
||||||
|
языка.
|
||||||
|
|
||||||
|
Оба повода включаются, только когда появится второй набор. Цена — ещё одна
|
||||||
|
сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже
|
||||||
|
болезни.
|
||||||
|
|
||||||
|
# Канон, тулинг, подключение
|
||||||
|
|
||||||
|
## 3. Тулинг: две разные задачи в одном `conv`
|
||||||
|
|
||||||
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
|
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
|
||||||
по частоте запуска, по тому, кто запускает, и по тому, что считается
|
по частоте запуска, по тому, кто запускает, и по тому, что считается
|
||||||
провалом.
|
провалом.
|
||||||
|
|
||||||
**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка
|
**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка
|
||||||
совпадает с реестром, номера без дыр вниз, у каждого правила модальность и
|
совпадает с манифестом, у каждого правила модальность и блок ПОЧЕМУ, ссылки
|
||||||
«Почему», ссылки разрешаются, префикс чужой темы не лезет в норму (META-20),
|
разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в
|
||||||
путей канона в тексте нет (META-21), строка о версии языка на месте.
|
тексте нет (META-21), строка о версии языка на месте. Запускается в каноне,
|
||||||
Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже
|
при каждой правке, провал — это ошибка. Логика уже написана и много раз
|
||||||
написана и много раз прогнана руками, но живёт в скретчпаде, а не в
|
прогнана руками, но живёт в скретчпаде, а не в репозитории.
|
||||||
репозитории.
|
|
||||||
|
|
||||||
**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из
|
**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из
|
||||||
слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже
|
слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже
|
||||||
маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается
|
маркера, `READING.md` рядом с копиями, предупреждение о висячих ссылках на
|
||||||
|
неподписанные темы. Запускается
|
||||||
в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами»,
|
в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами»,
|
||||||
чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff`
|
чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff`
|
||||||
после пересборки.
|
после пересборки.
|
||||||
@@ -36,19 +80,25 @@
|
|||||||
ссылках: это установка, а не целостность, но список подписок ему нужен из
|
ссылках: это установка, а не целостность, но список подписок ему нужен из
|
||||||
манифеста.
|
манифеста.
|
||||||
|
|
||||||
|
Список проверок теперь реализуем целиком: граница правила определена,
|
||||||
|
нумерация сплошная, снятое правило остаётся заглушкой — данных со стороны
|
||||||
|
языка проверке хватает.
|
||||||
|
|
||||||
Перед тем как переписывать, стоит посмотреть на два готовых прототипа:
|
Перед тем как переписывать, стоит посмотреть на два готовых прототипа:
|
||||||
дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец
|
дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец
|
||||||
манифеста и `vendir.yml` — как пример того, где проходит граница между «чего
|
манифеста и `vendir.yml` — как пример того, где проходит граница между «чего
|
||||||
хочу» и «что получил».
|
хочу» и «что получил».
|
||||||
|
|
||||||
## 2. Пары слоёв и темы без базы
|
## 4. Пары слоёв и темы без базы
|
||||||
|
|
||||||
Отложено сознательно, но список стоит держать перед глазами:
|
Отложено сознательно, но список стоит держать перед глазами:
|
||||||
|
|
||||||
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
|
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
|
||||||
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
|
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
|
||||||
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
|
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
|
||||||
ссылку «связано».
|
ссылку «связано». Вдобавок это ломает гарантию META-24: она верна только
|
||||||
|
для базы своей темы, а `arch/time.md` объявляет тему `time`, не `logging`.
|
||||||
|
С объявленной темой расхождение стало проверяемым машинно.
|
||||||
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
|
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
|
||||||
одной секцией — само по себе не ломается, но это и есть тот невыделенный
|
одной секцией — само по себе не ломается, но это и есть тот невыделенный
|
||||||
арх-слой из известного долга.
|
арх-слой из известного долга.
|
||||||
@@ -60,7 +110,7 @@
|
|||||||
- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из
|
- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из
|
||||||
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
|
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
|
||||||
|
|
||||||
## 3. Подключение к репозиториям
|
## 5. Подключение к репозиториям
|
||||||
|
|
||||||
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
|
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
|
||||||
Понадобится: заполнить локальную часть копий тем, что сейчас в этих
|
Понадобится: заполнить локальную часть копий тем, что сейчас в этих
|
||||||
@@ -69,28 +119,7 @@
|
|||||||
строка в `AGENTS.md` каждого потребителя про то, что файлы в
|
строка в `AGENTS.md` каждого потребителя про то, что файлы в
|
||||||
`docs/conventions/` — копии.
|
`docs/conventions/` — копии.
|
||||||
|
|
||||||
## 4. Описание языка отдельно от набора конвенций
|
## 6. Тулинг на Go, живущий независимо
|
||||||
|
|
||||||
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
|
|
||||||
`conventions/` — **один конкретный** набор. Сейчас они склеены в одном
|
|
||||||
репозитории, и из одного описания нельзя собрать второй набор (рабочий,
|
|
||||||
доменный, чужой).
|
|
||||||
|
|
||||||
Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ
|
|
||||||
`version:`), и конвенции ссылаются на неё номером, а не путём, — то есть
|
|
||||||
самодостаточность копии выноса не требует.
|
|
||||||
|
|
||||||
Что осталось поводом:
|
|
||||||
|
|
||||||
- из одного описания по-прежнему нельзя собрать второй набор;
|
|
||||||
- тулинг валидирует правила, зашитые в его код, а не объявленную версию
|
|
||||||
языка.
|
|
||||||
|
|
||||||
Оба повода включаются, только когда появится второй набор. Цена — ещё одна
|
|
||||||
сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже
|
|
||||||
болезни.
|
|
||||||
|
|
||||||
## 5. Тулинг на Go, живущий независимо
|
|
||||||
|
|
||||||
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
|
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
|
||||||
одном репозитории и правятся одним движением. Мысль: вынести в отдельный
|
одном репозитории и правятся одним движением. Мысль: вынести в отдельный
|
||||||
@@ -99,32 +128,10 @@ Go-бинарь со своим релизным циклом, ставить ч
|
|||||||
|
|
||||||
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
|
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
|
||||||
инструмент «заодно» с правкой конвенции, работает против **любого** канона и
|
инструмент «заодно» с правкой конвенции, работает против **любого** канона и
|
||||||
любого потребителя — что прямо требуется вопросом 4, — и снимает питон из
|
любого потребителя — что прямо требуется вопросом 2, — и снимает питон из
|
||||||
зависимостей репозиториев-потребителей.
|
зависимостей репозиториев-потребителей.
|
||||||
|
|
||||||
Порядок обратный ожидаемому: пока вопрос 4 не сделан, инструмент всё равно
|
Порядок обратный ожидаемому: пока вопрос 2 не сделан, инструмент всё равно
|
||||||
работает против одного конкретного канона, и независимый релизный цикл ему
|
работает против одного конкретного канона, и независимый релизный цикл ему
|
||||||
нечего обслуживать. Сначала 4, потом 5. Разделение из вопроса 1 при этом
|
нечего обслуживать. Сначала 2, потом 6. Разделение из вопроса 3 при этом
|
||||||
дешевле заложить сразу, чем отпиливать потом.
|
дешевле заложить сразу, чем отпиливать потом.
|
||||||
|
|
||||||
## 6. Одиннадцать таблиц не прочитаны на взаимоисключительность
|
|
||||||
|
|
||||||
`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по
|
|
||||||
умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы
|
|
||||||
такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна
|
|
||||||
таблица под новое требование не прочитана.
|
|
||||||
|
|
||||||
Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению»
|
|
||||||
против «повторяющаяся служебная, по таймеру или поллингу». Периодическая
|
|
||||||
операция, которая всё-таки меняет данные, подходит под обе строки, и уровень
|
|
||||||
из таблицы не выводится однозначно.
|
|
||||||
|
|
||||||
Работа читательская, машине не даётся; в список проверок она уже записана в
|
|
||||||
разделе «Чтением, потому что машине не даётся».
|
|
||||||
|
|
||||||
## Мелкое, не закрыто
|
|
||||||
|
|
||||||
- `conv check` и отличие ссылки на удалённое правило от упоминания дыры:
|
|
||||||
теперь освободившиеся номера перечислены в `GUIDE.md`, раздел
|
|
||||||
«Освободившиеся номера», — проверке остаётся читать этот список, а не
|
|
||||||
угадывать. Реализации по-прежнему нет.
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: app-directories
|
||||||
prefix: DIRS
|
prefix: DIRS
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,8 +12,8 @@ prefix: DIRS
|
|||||||
механически выводится состав бэкапа.
|
механически выводится состав бэкапа.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: config
|
||||||
prefix: CONF
|
prefix: CONF
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -8,8 +9,8 @@ prefix: CONF
|
|||||||
секретами и когда падает.
|
секретами и когда падает.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: db-identifiers
|
||||||
prefix: KEYS
|
prefix: KEYS
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -7,8 +8,8 @@ prefix: KEYS
|
|||||||
Как выбираются и как выглядят первичные ключи сущностей.
|
Как выбираются и как выглядят первичные ключи сущностей.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: time
|
||||||
prefix: TIME
|
prefix: TIME
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -8,8 +9,8 @@ prefix: TIME
|
|||||||
берётся значение и где появляется не-UTC.
|
берётся значение и где появляется не-UTC.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: config
|
||||||
prefix: GCFG
|
prefix: GCFG
|
||||||
extends: arch/config.md
|
extends: arch/config.md
|
||||||
---
|
---
|
||||||
@@ -9,8 +10,8 @@ extends: arch/config.md
|
|||||||
запрета на окружение.
|
запрета на окружение.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Секретов Go-специфика не касается: они приходят из деплоя уже в файле, а
|
Секретов Go-специфика не касается: они приходят из деплоя уже в файле, а
|
||||||
проверка их непустоты идёт вместе с остальной валидацией — как описано в
|
проверка их непустоты идёт вместе с остальной валидацией — как описано в
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: db-identifiers
|
||||||
prefix: GKEY
|
prefix: GKEY
|
||||||
extends: arch/db-identifiers.md
|
extends: arch/db-identifiers.md
|
||||||
---
|
---
|
||||||
@@ -8,8 +9,8 @@ extends: arch/db-identifiers.md
|
|||||||
Как базовый слой выглядит в Go-приложении.
|
Как базовый слой выглядит в Go-приложении.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Единая точка из `KEYS-3` — пакет `internal/ident`: он
|
Единая точка из `KEYS-3` — пакет `internal/ident`: он
|
||||||
порождает идентификаторы (`NewID`, `NewIDAt`) и он же их разбирает
|
порождает идентификаторы (`NewID`, `NewIDAt`) и он же их разбирает
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: db-schema
|
||||||
prefix: MIGR
|
prefix: MIGR
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -8,8 +9,8 @@ prefix: MIGR
|
|||||||
Go-приложении.
|
Go-приложении.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: errors
|
||||||
prefix: GERR
|
prefix: GERR
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -9,8 +10,8 @@ prefix: GERR
|
|||||||
границе).
|
границе).
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Две границы, о которых говорят правила ниже:
|
Две границы, о которых говорят правила ниже:
|
||||||
|
|
||||||
@@ -344,8 +345,9 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
|
|
||||||
| № | Где перехвачена паника | Что дальше |
|
| № | Где перехвачена паника | Что дальше |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| GERR-26.1 | обработчик HTTP-запроса | ответ 500, если он ещё не начат; процесс и прочие запросы не затрагиваются |
|
| GERR-26.1 | обработчик HTTP-запроса, паника любая, кроме сигнала намеренного прерывания | ответ 500, если он ещё не начат; процесс и прочие запросы не затрагиваются |
|
||||||
| GERR-26.2 | итерация цикла обработки — бот, воркер | цикл продолжается со следующего элемента, упавший элемент повторно не берётся |
|
| GERR-26.2 | итерация цикла обработки — бот, воркер | цикл продолжается со следующего элемента, упавший элемент повторно не берётся |
|
||||||
|
| GERR-26.3 | обработчик HTTP-запроса, паника — сигнал намеренного прерывания (`http.ErrAbortHandler`) | значение пробрасывается дальше, ответ не подменяется |
|
||||||
|
|
||||||
**ПОЧЕМУ.** Паника внутри обработки одного элемента почти всегда говорит о
|
**ПОЧЕМУ.** Паника внутри обработки одного элемента почти всегда говорит о
|
||||||
баге в работе с данными этого элемента, а не о порче общего состояния, —
|
баге в работе с данными этого элемента, а не о порче общего состояния, —
|
||||||
@@ -356,10 +358,11 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
обязательным (GERR-22): неперехваченная паника в любой горутине завершает весь
|
обязательным (GERR-22): неперехваченная паника в любой горутине завершает весь
|
||||||
процесс.
|
процесс.
|
||||||
|
|
||||||
Продолжать, не исключив упавший элемент, нельзя: детерминированная паника
|
Исключение упавшего элемента в GERR-26.2 — не осторожность, а условие
|
||||||
даёт бесконечный цикл — тот же элемент, тот же стек, залитый лог и нулевой
|
прогресса: детерминированная паника даёт бесконечный цикл — тот же элемент,
|
||||||
прогресс. Это классический poison message, и лекарство берём то же, что
|
тот же стек, залитый лог и нулевой прогресс. Это классический poison message,
|
||||||
принято в очередях: элемент выводится из оборота, а не берётся снова. У
|
и лекарство здесь то же, что принято в очередях: элемент выводится из
|
||||||
|
оборота, а не берётся снова. У
|
||||||
цикла, который и так подтверждает прогресс — сдвигает офсет, помечает
|
цикла, который и так подтверждает прогресс — сдвигает офсет, помечает
|
||||||
строку состоянием, — механизм для этого уже есть, заводить отдельный не
|
строку состоянием, — механизм для этого уже есть, заводить отдельный не
|
||||||
нужно.
|
нужно.
|
||||||
@@ -369,9 +372,10 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
|||||||
клиент получит обрывок с кодом 200. Отсюда же общее предпочтение собирать
|
клиент получит обрывок с кодом 200. Отсюда же общее предпочтение собирать
|
||||||
ответ целиком до записи там, где это возможно.
|
ответ целиком до записи там, где это возможно.
|
||||||
|
|
||||||
Из GERR-26.1 есть одно исключение: `http.ErrAbortHandler` — сигнал «прервать
|
Отдельная строка GERR-26.3 нужна потому, что `http.ErrAbortHandler` — не
|
||||||
обработку намеренно», и recover-обёртка пробрасывает его дальше, а не
|
отказ, а сигнал «прервать обработку намеренно»: подмена его на 500 превратила
|
||||||
превращает в 500. Так поступают и стандартные обёртки вроде chi.
|
бы штатный разрыв в ложную ошибку в логе и в метриках. Так поступают и
|
||||||
|
стандартные обёртки вроде chi.
|
||||||
|
|
||||||
### GERR-24. Независимые ошибки собираются `errors.Join`
|
### GERR-24. Независимые ошибки собираются `errors.Join`
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: logging
|
||||||
prefix: SLOG
|
prefix: SLOG
|
||||||
extends: arch/time.md
|
extends: arch/time.md
|
||||||
---
|
---
|
||||||
@@ -10,8 +11,8 @@ extends: arch/time.md
|
|||||||
функциональности, живут в спеках.
|
функциональности, живут в спеках.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Лог читают инструментами, а не глазами: повседневно — `jq`
|
Лог читают инструментами, а не глазами: повседневно — `jq`
|
||||||
(`jq 'select(.download_id=="a1b2")' app.jsonl`), тяжёлое (агрегации, JOIN) —
|
(`jq 'select(.download_id=="a1b2")' app.jsonl`), тяжёлое (агрегации, JOIN) —
|
||||||
@@ -337,6 +338,7 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
|
|||||||
| SLOG-25.1 | штатный конфликт состояния или некорректный ввод | пользователю, он уже получил ответ | `DEBUG` |
|
| SLOG-25.1 | штатный конфликт состояния или некорректный ввод | пользователю, он уже получил ответ | `DEBUG` |
|
||||||
| SLOG-25.2 | расхождение производного или учётного состояния, первичные данные целы | владельцу, «может стать проблемой» | `WARN` |
|
| SLOG-25.2 | расхождение производного или учётного состояния, первичные данные целы | владельцу, «может стать проблемой» | `WARN` |
|
||||||
| SLOG-25.3 | сбой БД, ФС, недоступность зависимости | владельцу, в разбор | `ERROR` |
|
| SLOG-25.3 | сбой БД, ФС, недоступность зависимости | владельцу, в разбор | `ERROR` |
|
||||||
|
| SLOG-25.4 | класса нет: отказ в классификацию не заведён | владельцу, как пропуск в классификации | `ERROR` с отметкой о непокрытом классе |
|
||||||
|
|
||||||
**ПОЧЕМУ.** Это применение SLOG-8 к отказам: пользователь уже увидел причину на
|
**ПОЧЕМУ.** Это применение SLOG-8 к отказам: пользователь уже увидел причину на
|
||||||
экране — владельцу разбирать нечего; целостность первичных данных отделяет
|
экране — владельцу разбирать нечего; целостность первичных данных отделяет
|
||||||
@@ -349,9 +351,11 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
|
|||||||
таблицу не входит: это не доменный отказ, и логирует его recover-граница
|
таблицу не входит: это не доменный отказ, и логирует его recover-граница
|
||||||
вместе со стеком (конвенция `errors`). Искать его класс здесь не нужно.
|
вместе со стеком (конвенция `errors`). Искать его класс здесь не нужно.
|
||||||
|
|
||||||
Мимо таблицы идёт и доменная ошибка, которой нет в маппинге: класса у неё
|
Строка SLOG-25.4 говорит не о классе отказа, а о пропуске в самой
|
||||||
нет, потому что её просто забыли завести. Она логируется `ERROR` с
|
классификации: ошибку забыли завести в маппинге. `ERROR` здесь — громкость,
|
||||||
признаком непокрытой (`GERR-25`).
|
по которой пропуск находят фильтром, а не оценка тяжести отказа; саму отметку
|
||||||
|
о непокрытом классе ставит трансляция ошибки (`GERR-25` в конвенции
|
||||||
|
`errors`).
|
||||||
|
|
||||||
### SLOG-26. Тот же отказ в асинхронной стадии — уровнем выше
|
### SLOG-26. Тот же отказ в асинхронной стадии — уровнем выше
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: time
|
||||||
prefix: GTIM
|
prefix: GTIM
|
||||||
extends: arch/time.md
|
extends: arch/time.md
|
||||||
---
|
---
|
||||||
@@ -9,8 +10,8 @@ extends: arch/time.md
|
|||||||
в каком виде время попадает в базу и в логи, что делать с зонами.
|
в каком виде время попадает в базу и в логи, что делать с зонами.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Правила
|
## Правила
|
||||||
|
|
||||||
@@ -180,8 +181,8 @@ func utcTime(_ []string, a slog.Attr) slog.Attr {
|
|||||||
текущего значения настройки: смена зоны задним числом сдвигает границы
|
текущего значения настройки: смена зоны задним числом сдвигает границы
|
||||||
суток у того, что давно посчитано и сохранено.
|
суток у того, что давно посчитано и сохранено.
|
||||||
|
|
||||||
Календарные вычисления бизнес-логики берут зону явно — как описано в
|
Явную зону в календарных вычислениях требует TIME-12 — это его правило, а не
|
||||||
базовом слое.
|
второе такое же здесь.
|
||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: app-directories
|
||||||
prefix: ANSD
|
prefix: ANSD
|
||||||
extends: arch/app-directories.md
|
extends: arch/app-directories.md
|
||||||
---
|
---
|
||||||
@@ -8,8 +9,8 @@ extends: arch/app-directories.md
|
|||||||
Как категории из базового слоя раскладываются на сервере плейбуком.
|
Как категории из базового слоя раскладываются на сервере плейбуком.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
topic: web-ui
|
||||||
prefix: HTMX
|
prefix: HTMX
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -9,8 +10,8 @@ prefix: HTMX
|
|||||||
какие действия поддерживает — в спеках, не здесь.
|
какие действия поддерживает — в спеках, не здесь.
|
||||||
|
|
||||||
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||||
ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 —
|
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||||
тогда и только тогда, когда написаны заглавными.
|
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
|
||||||
|
|
||||||
Логирование запросов — конвенция `logging` (HTTP-поля, рутинно-частое на
|
Логирование запросов — конвенция `logging` (HTTP-поля, рутинно-частое на
|
||||||
`DEBUG`). Трансляция доменных ошибок наружу — конвенция `errors`
|
`DEBUG`). Трансляция доменных ошибок наружу — конвенция `errors`
|
||||||
|
|||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
# Манифест набора конвенций.
|
||||||
|
#
|
||||||
|
# Манифестов в модели два, и они отвечают на разные вопросы:
|
||||||
|
#
|
||||||
|
# - этот, в наборе, описывает сам набор: какие в нём темы и какие префиксы
|
||||||
|
# правил заняты;
|
||||||
|
# - `.conventions.toml` в репозитории-потребителе описывает подключение:
|
||||||
|
# откуда взяты копии, какие темы выбраны, какие язык и стек.
|
||||||
|
#
|
||||||
|
# Оба идентификатора набора — тема и префикс — живут здесь, потому что
|
||||||
|
# правила у них общие: объявляются в шапке файла, сверяются с манифестом,
|
||||||
|
# не переиспользуются никогда, а снятые уходят в свой раздел `retired`
|
||||||
|
# вместе с причиной и датой.
|
||||||
|
|
||||||
|
# ─── Язык записи ────────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Набор объявляет версию языка, на котором записаны его правила, и два
|
||||||
|
# документа о нём. Полное описание остаётся у автора; в копию рядом с
|
||||||
|
# конвенциями едет короткое `READING.md` — то, что нужно читателю правил, без
|
||||||
|
# ссылок на правила ведения набора.
|
||||||
|
|
||||||
|
[language]
|
||||||
|
version = 1
|
||||||
|
description = "LANGUAGE.md"
|
||||||
|
reading = "READING.md"
|
||||||
|
|
||||||
|
# ─── Темы ───────────────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Тема — набор правил об одном фокусе разработки: время, конфигурация, схема
|
||||||
|
# БД. Имя записывается латиницей; рекомендуется нижний kebab-case, но годится
|
||||||
|
# любой идентификатор, пригодный для имени файла.
|
||||||
|
#
|
||||||
|
# Тема — единица подписки и единица сборки: потребитель перечисляет темы в
|
||||||
|
# своём манифесте, а сборщик складывает в один файл все слои темы в порядке
|
||||||
|
# arch → язык → стек. Слои узнают друг друга по объявленному имени, а не по
|
||||||
|
# имени файла: файл конвенции несёт тему в шапке (`topic: time`).
|
||||||
|
#
|
||||||
|
# Имя темы не переименовывается и не переиспользуется: на тему ссылаются
|
||||||
|
# словом — из текста конвенций («конвенция `logging`»), из подписки в
|
||||||
|
# манифесте потребителя, из шапки `origin:` каждой копии, — и такая ссылка
|
||||||
|
# обязана продолжать указывать на тот же набор правил. Тема живёт, пока в
|
||||||
|
# `conventions/` есть хотя бы один её слой.
|
||||||
|
#
|
||||||
|
# Описание — одна строка о том, про что тема: из него собирается таблица в
|
||||||
|
# README директории конвенций у потребителя (META-18).
|
||||||
|
|
||||||
|
[topics.live]
|
||||||
|
app-directories = "категории директорий приложения и что в каждой лежит"
|
||||||
|
config = "конфигурация: файл, валидация, секреты"
|
||||||
|
db-identifiers = "идентификаторы сущностей: вид ключа, генерация, границы"
|
||||||
|
db-schema = "схема БД и миграции: типы колонок, форма изменения"
|
||||||
|
errors = "ошибки: обёртки, границы трансляции, паники"
|
||||||
|
logging = "логирование: уровни, структура записи, что не логируем"
|
||||||
|
time = "время: хранение, зоны, форматы, календарные границы"
|
||||||
|
web-ui = "веб-UI: партиалы, свопы, поллинг"
|
||||||
|
|
||||||
|
[topics.retired]
|
||||||
|
# Пусто. Сюда попадают имена снятых и переименованных тем вместе с причиной
|
||||||
|
# и датой, чтобы их нельзя было выдать другой теме.
|
||||||
|
|
||||||
|
# ─── Префиксы правил ────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Префикс — четыре заглавные латинские буквы, уникальные по всему набору. Он
|
||||||
|
# выбирается под файл, а не выводится по формуле: префикс нужен, чтобы по нему
|
||||||
|
# искать, а не чтобы его разбирать. Поэтому подходящее слово лучше
|
||||||
|
# закономерности.
|
||||||
|
#
|
||||||
|
# Правила:
|
||||||
|
#
|
||||||
|
# - префикс не переименовывается и не переиспользуется никогда — ссылка
|
||||||
|
# из чужого репозитория обязана продолжать указывать на то же место;
|
||||||
|
# - при удалении или разделении файла префикс уходит в retired, а не
|
||||||
|
# освобождается;
|
||||||
|
# - переезд файла между осями префикс не меняет: идентификатор правила
|
||||||
|
# не зависит от таксономии;
|
||||||
|
# - вынос части правил в новый файл — это новый префикс и новая нумерация:
|
||||||
|
# перенос правила между документами есть смысловое изменение, а не
|
||||||
|
# переименование;
|
||||||
|
# - тот же префикс продублирован в шапке файла (`prefix:`), conv сверяет.
|
||||||
|
#
|
||||||
|
# Префикс принадлежит файлу, тема — набору файлов: у слоёв одной темы
|
||||||
|
# префиксы разные, а имя темы одно.
|
||||||
|
#
|
||||||
|
# Пути даются от корня репозитория, а не от `conventions/`: манифест покрывает
|
||||||
|
# и обвязку тоже.
|
||||||
|
#
|
||||||
|
# Буква `X` в начале префикса зарезервирована за репозиториями-потребителями:
|
||||||
|
# набор её не занимает никогда, локальные правила берут префиксы только на
|
||||||
|
# неё (XTIM, XLOG). Согласовывать их с манифестом не нужно — столкновение
|
||||||
|
# невозможно по построению.
|
||||||
|
|
||||||
|
[prefixes.live]
|
||||||
|
DIRS = "conventions/arch/app-directories.md"
|
||||||
|
CONF = "conventions/arch/config.md"
|
||||||
|
KEYS = "conventions/arch/db-identifiers.md"
|
||||||
|
TIME = "conventions/arch/time.md"
|
||||||
|
GCFG = "conventions/lang/go/config.md"
|
||||||
|
GKEY = "conventions/lang/go/db-identifiers.md"
|
||||||
|
MIGR = "conventions/lang/go/db-schema.md"
|
||||||
|
GERR = "conventions/lang/go/errors.md"
|
||||||
|
SLOG = "conventions/lang/go/logging.md"
|
||||||
|
GTIM = "conventions/lang/go/time.md"
|
||||||
|
ANSD = "conventions/stack/ansible/app-directories.md"
|
||||||
|
HTMX = "conventions/stack/htmx/web-ui.md"
|
||||||
|
|
||||||
|
# Документ, которым канон ведёт себя сам: к потребителю не едет, но правила в
|
||||||
|
# нём записаны тем же языком, цитируются по номерам и проверяются как
|
||||||
|
# конвенция — отсюда префикс. Темы у него нет: подписаться на него нельзя.
|
||||||
|
META = "GUIDE.md"
|
||||||
|
|
||||||
|
[prefixes.retired]
|
||||||
|
# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с
|
||||||
|
# причиной и датой, чтобы их нельзя было выдать повторно.
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# Реестр префиксов правил.
|
|
||||||
#
|
|
||||||
# Префикс — четыре заглавные латинские буквы, уникальные по всему канону.
|
|
||||||
# Он выбирается под файл, а не выводится по формуле: префикс нужен, чтобы
|
|
||||||
# по нему искать, а не чтобы его разбирать. Поэтому подходящее слово лучше
|
|
||||||
# закономерности.
|
|
||||||
#
|
|
||||||
# Правила реестра:
|
|
||||||
#
|
|
||||||
# - префикс не переименовывается и не переиспользуется никогда — ссылка
|
|
||||||
# из чужого репозитория обязана продолжать указывать на то же место;
|
|
||||||
# - при удалении или разделении файла префикс уходит в [retired], а не
|
|
||||||
# освобождается;
|
|
||||||
# - переезд файла между осями префикс не меняет: идентификатор правила
|
|
||||||
# не зависит от таксономии;
|
|
||||||
# - вынос части правил в новый файл — это новый префикс и новая
|
|
||||||
# нумерация: перенос правила между документами есть смысловое
|
|
||||||
# изменение, а не переименование;
|
|
||||||
# - тот же префикс продублирован в шапке файла (`prefix:`), conv сверяет.
|
|
||||||
#
|
|
||||||
# Пути даются от корня репозитория, а не от `conventions/`: реестр покрывает
|
|
||||||
# и обвязку тоже.
|
|
||||||
#
|
|
||||||
# Буква `X` в начале префикса зарезервирована за репозиториями-потребителями:
|
|
||||||
# канон её не занимает никогда, локальные правила берут префиксы только на
|
|
||||||
# неё (XTIM, XLOG). Согласовывать их с этим реестром не нужно — столкновение
|
|
||||||
# невозможно по построению.
|
|
||||||
|
|
||||||
[live]
|
|
||||||
DIRS = "conventions/arch/app-directories.md"
|
|
||||||
CONF = "conventions/arch/config.md"
|
|
||||||
KEYS = "conventions/arch/db-identifiers.md"
|
|
||||||
TIME = "conventions/arch/time.md"
|
|
||||||
GCFG = "conventions/lang/go/config.md"
|
|
||||||
GKEY = "conventions/lang/go/db-identifiers.md"
|
|
||||||
MIGR = "conventions/lang/go/db-schema.md"
|
|
||||||
GERR = "conventions/lang/go/errors.md"
|
|
||||||
SLOG = "conventions/lang/go/logging.md"
|
|
||||||
GTIM = "conventions/lang/go/time.md"
|
|
||||||
ANSD = "conventions/stack/ansible/app-directories.md"
|
|
||||||
HTMX = "conventions/stack/htmx/web-ui.md"
|
|
||||||
|
|
||||||
# Обвязка канона: не синхронизируется в репозитории, но правила
|
|
||||||
# записаны тем же языком и цитируются по номерам, поэтому префикс нужен.
|
|
||||||
META = "GUIDE.md"
|
|
||||||
|
|
||||||
[retired]
|
|
||||||
# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с
|
|
||||||
# причиной и датой, чтобы их нельзя было выдать повторно.
|
|
||||||
Reference in New Issue
Block a user