- метка обоснования пишется заглавными и вошла в словарь набора: скелет правила теперь целиком из ключевых слов, а не смесь `**ДОЛЖЕН.**` и `**Почему.**`; в переводе на другой язык метка меняется как остальные слова (ПОЧЕМУ / WHY), 235 вхождений заменены - метки правила выделены из шкалы в отдельный перечень: ПОЧЕМУ и МЕХАНИЗИРОВАНО обязательности не задают, а размечают части, и стандартом не даются ни в одном языке — раньше МЕХАНИЗИРОВАНО висело строкой в таблице модальности - версия языка поднята до 2, потому что изменение формы меняет чтение уже написанного текста; строка о версии в двенадцати конвенциях перечисляет теперь и метки, а служебные слова сценария в неё по-прежнему не входят
28 KiB
prefix
| prefix |
|---|
| META |
Как мы ведём конвенции
Конвенция описывает повторяющийся выбор: как называть директории, как раскладывать данные, как оформлять ошибки. Она отвечает на вопрос «как принято», а не «что здесь происходит».
Как записывается сама конвенция — правила, модальность, обоснования — в LANGUAGE.md. Здесь — про то, зачем конвенции заводятся, где живут и как соотносятся с соседними видами документов.
Область действия
Правила ниже адресованы автору конвенции — тому, кто заводит новый файл или правит существующий, в каноне и в копиях репозиториев. Обязательность живёт на отдельном правиле, а не на файле; шкала модальных слов — в LANGUAGE.md.
Отличие от соседей
docs/adr/— решение, принятое однажды и постфактум («почему выбрали Authelia, а не Keycloak»). Запись неизменяема.docs/specs/и OpenSpec, где они есть, — что система делает, наблюдаемое поведение как контракт. Конвенция — как написан код; в спеки она не переносится, это не capability.docs/drafts/— оперативная хроника и черновики, «что собираюсь сделать».docs/conventions/— правило на будущее, применяемое многократно. Живой документ: правится, когда договорённость меняется.
Оформление
Имя файла — kebab-case по теме: app-directories.md. Правилом это не
записано, и это случай META-25: регуляркой имя проверяется тривиально, но
обоснование сводится к «чтобы имя файла в реестре префиксов писалось одним
способом» — вреда от нарушения нет, значит и высшей модальности нет, а на
СЛЕДУЕТ такое правило не окупает строчку.
Канон и копии
Файлы в docs/conventions/ с шапкой origin: — копии из общего канона
dev-conventions, а не собственные документы репозитория. Копия собирается
из канона целиком, поэтому репозиторное живёт ниже маркера локальной части
в конце файла: обновление сохраняет всё, что ниже маркера, и переписывает
всё, что выше. Откуда взяты копии и где брать обновления — в манифесте
.conventions.toml в корне репозитория.
Отдельного механизма отчёта о расхождении нет: обновление перезаписывает
файлы в рабочем дереве, а что именно изменилось, показывает git diff до
коммита. Поэтому в шапке копии хранится только origin: — отпечатков
канона и дат синхронизации в ней нет, историю держит git.
Правка выше маркера означает одно из двух: улучшение, которое переносят в
канон, или документ, переставший быть копией, — тогда origin: из шапки
убирают.
Правила
META-1. Одна конвенция — один файл
ДОЛЖЕН. Файл описывает ровно один повторяющийся выбор.
ПОЧЕМУ. Подписка перечисляется по темам, и тему берут целиком. Файл, собравший две темы, вынуждает репозиторий взять правила, которые ему не нужны, и вычитывать чужую половину при каждом обновлении. Разрезать позже дорого: перенос правила в другой файл — это новый префикс и новая нумерация, поэтому после разреза все внешние ссылки обходят руками.
META-2. Конвенция заводится, когда решение принимается третий раз
СЛЕДУЕТ. Поводом служит одно и то же решение, принятое третий раз и каждый раз чуть по-другому.
ПОЧЕМУ. По одному-двум случаям не видно, что в решении повторяется, а что было частностью места: правило, выведенное из первого случая, кодирует частность и дальше мешает больше, чем помогает. Единичный выбор, к тому же спорный, читателю нужен вместе с мотивом — это ADR, где мотив и есть содержание записи.
META-3. Новая конвенция пишется там, где заболело
СЛЕДУЕТ. Первые шаги пути «находка → конвенция → правило линтера → удаление прозы» делаются в репозитории, где случилась находка; в канон продвигается общая часть.
ПОЧЕМУ. Правило, написанное сразу в общем виде, не проверено ни одним применением, и условие применимости у него придумано, а не найдено, — платят за это все потребители сразу. Формулировка, обкатанная на одном репозитории, приезжает в канон уже с известной границей.
META-4. В тексте конвенции нет утверждений о состоянии репозитория
НЕ ДОЛЖЕН. Норма пишется в настоящем предписывающем времени, без описаний того, как сейчас устроен конкретный репозиторий.
ПОЧЕМУ. Такое утверждение устаревает молча и подменяет норму описанием: читатель перестаёт понимать, что от него требуется, а что просто констатировано. В копиях у остальных потребителей чужой факт вдобавок ложен с первого дня. «Так сделано у нас» — содержимое региона отступлений, где оно и локально, и проверяемо.
META-20. Норма самодостаточна, наружу смотрит только обоснование
ДОЛЖЕН. Норму правила можно исполнить, имея один этот файл. Ссылка на правило чужой темы допустима в обосновании, в «Связано» и в разграничении области действия — но не в самой норме. Если норме нужен концепт соседней темы, он коротко повторяется здесь, а сосед называется в обосновании как источник решения.
ПОЧЕМУ. Репозиторий подписывается на произвольное подмножество конвенций, и графа зависимостей у него нет по построению. Норма, которую нельзя исполнить без отсутствующего файла, делает такое подмножество невалидным молча: читатель видит связный текст и не замечает, что часть нормы не определена. Обоснование, потерявшее адресата, деградирует честно — пропадает перекрёстная проверка, смысл остаётся. Цена повтора — риск разойтись с источником; она платится сознательно и видна, в отличие от скрытой зависимости.
META-21. Ссылка ведёт на тему или на правило, но не на путь в каноне
ДОЛЖЕН. На соседнюю конвенцию ссылаются именем темы (конвенция
logging), на конкретное правило — идентификатором (SLOG-27); путь файла
канона в тексте конвенции не употребляется.
ПОЧЕМУ. В репозитории конвенция лежит собранной: слои одной темы — это
секции одного файла, и пути lang/go/logging.md там не существует. Ссылка
на путь канона умирает при сборке, причём молча — текст остаётся связным.
Имя темы и идентификатор правила переживают и сборку, и переезд файла между
осями. Слой своей темы поэтому называют идентификатором его правила, а не
словами «базовый слой»: слова не проверяются и не ведут к утверждению.
META-24. Слой ссылается на идентификаторы своего базового слоя
ДОПУСКАЕТСЯ. Правило языкового или стекового слоя называет идентификатор правила арх-слоя своей темы прямо в норме.
ПОЧЕМУ. Подписываются темой, а не слоем: собранный файл начинается с арх-слоя независимо от того, какие язык и стек выбраны, — базовое правило в копии всегда рядом, и ссылка на него никуда не ведёт. Повтор его концепта здесь заводил бы второй источник правды внутри одного документа: META-20 требует повторять концепт там, где соседнего файла может не быть, а базовый слой отсутствовать не может. Остальные слои темы попадают в копию по манифесту, и такой гарантии у них нет — отсюда узость разрешения. Записано оно явно, потому что META-20 читают строже, чем он есть, и без этой строки базу дублируют без нужды.
META-5. Расхождение кода с правилом — отступление, а не повод переписать правило
ДОЛЖЕН. Правило правится, только когда неверно по существу: содержит фактическую ошибку, внутреннее противоречие или условие применимости, которое не даёт ответа.
ПОЧЕМУ. Правило, подогнанное под текущий код, перестаёт что-либо требовать — оно описывает то, что и так происходит, и первое же расхождение переписывает его снова. Направление «конвенция → код» держится ровно тем, что факт не считается аргументом.
META-6. ДОЛЖЕН без механической проверки либо механизируется, либо понижается
ДОЛЖЕН. Правило, нарушение которого объявлено ошибкой, получает машинную проверку или переводится в СЛЕДУЕТ.
ПОЧЕМУ. Без проверки правило держится на внимании: нарушения копятся молча и всплывают выборочно — на том ревью, куда дошли руки. Для СЛЕДУЕТ это честно, а ДОЛЖЕН при этом обещает то, чего не делает, и через несколько таких случаев обесценивает остальные ДОЛЖЕН в файле.
Отсюда следствие: правило, машинная проверка которого невозможна в принципе (вкус формулировки, выбор границы, суждение о ситуации), не может быть ДОЛЖЕН — его модальность СЛЕДУЕТ по построению, а не по слабости.
META-25. Высшая модальность выбирается, только когда назван вред
СЛЕДУЕТ. Правило получает ДОЛЖЕН или НЕ ДОЛЖЕН, если в обосновании сказано, что́ ломается при нарушении.
ПОЧЕМУ. Машинная проверка — условие необходимое (META-6), но не достаточное: проверяемых мелочей больше, чем важных вещей, и без второго условия единственным фильтром остаётся удобство проверки. Шкала наполняется опрятностью, читатель перестаёт отличать «уронит прод» от «неаккуратно» — и обесцениваются все ДОЛЖЕН в файле, ровно то, от чего META-6 защищает с другой стороны. Само это правило машиной не проверяется: «вред назван» устанавливается чтением, поэтому его собственная модальность по META-6 — СЛЕДУЕТ.
META-7. Факт механизации фиксируется в копии со ссылкой на правило
ДОЛЖЕН. Запись о механизации называет идентификатор правила и конкретную проверку.
ПОЧЕМУ. Механизация — состояние конкретного репозитория, канон о ней не знает, а без записи следующий автор либо заведёт вторую проверку того же, либо будет вычитывать глазами уже проверенное машиной. Без идентификатора читатель догадывается сам, к какому утверждению относится проверка, — и догадывается по-разному.
META-8. Формулировка не удаляется из канона, пока механизирована не у всех
НЕ ДОЛЖЕН. Норма остаётся в каноне, пока хотя бы у одного потребителя машинной проверки нет.
ПОЧЕМУ. У кого линтера нет, тот после удаления остаётся без правила вообще: ни проверки, ни текста. Механизация у одного потребителя ничего не говорит о прочих, поэтому удалять по факту «у нас уже проверяется» — значит чинить свой файл за чужой счёт.
Списка подписчиков канон по построению не знает, поэтому факт «механизировано
у всех» устанавливается обходом репозиториев вручную — это часть работы по
удалению нормы, а не то, что можно проверить машиной (см. LANGUAGE.md,
состояние МЕХАНИЗИРОВАНО).
META-9. Общая механизация разрешает удалить норму из канона
ДОПУСКАЕТСЯ. Правило, уехавшее в общий конфиг линтера или в общую роль, удаляется из канона.
ПОЧЕМУ. Формулировка, дублирующая работающую у всех проверку, размазывает внимание: файл на несколько сотен строк заставляет человека и агента добросовестно вычитывать тривиальное именование и не доходить до формы решения. Явное разрешение нужно, чтобы META-8 не читался как запрет удалять вообще.
META-10. Обоснование не удаляется никогда
НЕ ДОЛЖЕН. Блок ПОЧЕМУ остаётся и после того, как норма уехала в линтер.
ПОЧЕМУ. Линтер сообщает, что нарушено, но не сообщает, зачем правило существует. Без обоснования не видно, когда причина отпала, — проверка продолжает работать по инерции, и возразить ей нечем, кроме как отключив.
META-11. У трудноизменяемого слоя область действия пишется явно
ДОЛЖЕН. Конвенция о схеме БД, формате хранения или раскладке директорий называет, к чему применяется: к новым таблицам и миграциям, а не к состоянию схемы.
ПОЧЕМУ. Здесь не работает привычное «новое пишем правильно, старое переезжает по мере касания»: таблица не переезжает от того, что её потрогали. Без явной рамки правило читается как требование к текущему состоянию, и оба исхода плохи — миграция живых данных ради опрятности либо молчаливый вывод, что конвенция не соблюдается совсем.
META-12. Механизируется граница изменения, а не состояние
ДОЛЖЕН. Проверка запрещает нарушение в новых миграциях, а не в уже существующей схеме.
ПОЧЕМУ. Проверка состояния краснеет на легаси с первого дня: её отключают или обвешивают вечным списком исключений — и она перестаёт ловить новое, ради чего заводилась. Проверка границы оставляет старое в покое и делает новую ошибку невозможной.
META-13. Список отступлений трудноизменяемого слоя — постоянный
ДОЛЖЕН. Перечисленные старые таблицы и раскладки живут как есть, а не как задачи на дочистку.
ПОЧЕМУ. Список, записанный долгом, требует либо мигрировать живые данные без выгоды, либо год за годом объяснять невыполненный план. Второе кончается тем, что список перестают вести, — и пропадает единственное место, где видно, где именно правило не действует.
META-14. Отступления перечисляются поимённо, со ссылкой на правила
ДОЛЖЕН. В локальной части копии перечислены отступления, которые уже есть в коде, с идентификатором правила и причиной.
ПОЧЕМУ. Иначе репозиторий выглядит соблюдающим конвенцию, а проверить это можно только чтением всего кода. Со ссылками отступления счётны: видно, сколько правил конвенции репозиторий реально не соблюдает. Пустой список при этом почти всегда означает не отсутствие отступлений, а то, что их не искали.
META-15. Запись об отступлении разбирается по масштабу
ДОЛЖЕН. Судьба записи зависит от того, что в ней сказано:
| № | Что записано | Куда идёт |
|---|---|---|
| META-15.1 | правилу не следуем в перечисленных местах, причина названа | остаётся отступлением |
| META-15.2 | правило не применяется в репозитории целиком | чинится условие применимости — в каноне |
| META-15.3 | конвенция репозиторию не нужна | копия удаляется, подписки нет |
ПОЧЕМУ. Отступление описывает исключение, и по нему видно, какая часть правила нарушена. Запись «мы это правило вообще не применяем» такой информации не несёт и маскирует одну из двух чинимых причин: неверную рамку правила в каноне, которую чинят один раз для всех, или лишнюю подписку, где файл просто не нужен. Оставленная отступлением, она прячет обе.
META-17. Ссылки на код репозитория стоят в локальной части, а не в «Связано»
ДОЛЖЕН. Раздел «Связано» канона содержит только ссылки, верные у всех потребителей; ссылки на ADR, код и файлы конкретного репозитория — в локальной части копии.
ПОЧЕМУ. Текст канона приезжает ко всем потребителям, и ссылка на чужой файл у них битая с первого дня. Ниже маркера та же ссылка никого не задевает и переживает обновление, потому что обновление её не трогает.
META-22. Репозиторное в копии пишется ниже маркера локальной части
ДОЛЖЕН. Правки репозитория вносятся ниже маркера, а не в текст, пришедший из канона.
ПОЧЕМУ. Обновление перезаписывает всё, что выше маркера, поэтому правка
там живёт до первого pull. Заметить пропажу можно, только вычитав
git diff целиком — а он в этот момент и без того полон изменений канона,
и своя строка теряется среди чужих.
META-23. Документ, переставший быть копией, не носит origin:
НЕ ДОЛЖЕН. Файл, который развели с каноном намеренно, шапку origin:
не сохраняет.
ПОЧЕМУ. По origin: решается, какие файлы пересобирать из канона. Форк,
оставивший шапку, при первом же обновлении теряет ровно то, ради чего его
заводили. Происхождение такого документа остаётся в истории коммита, где оно
никого не вводит в заблуждение.
META-18. README директории перечисляет конвенции с однострочным описанием
СЛЕДУЕТ. Одна плоская таблица: файл и строка о том, про что он.
ПОЧЕМУ. Подписка — это набор лежащих файлов, и без описаний вопрос «какая из них про мой случай» решается открыванием каждой. Ценой в десяток файлов это означает, что не открывают ни одной.
META-19. Короткие инварианты дублируются в точку входа агента
ДОЛЖЕН. В AGENTS.md / CLAUDE.md едет одна строка на правило с его
идентификатором; детали остаются в конвенции.
ПОЧЕМУ. Сама по себе конвенция агенту не видна: он дойдёт до неё, только если его туда отправили, — а безусловно он читает точку входа. Строка с идентификатором служит и напоминанием, и адресом, по которому за подробностями идут; перенос деталей туда же вернул бы задачу поддержки двух текстов.
Освободившиеся номера
Номер удалённого правила не переиспользуется, поэтому дыры в нумерации — норма. Здесь перечислено, что́ под ними было: без этого упоминание номера в прозе не отличить от ссылки на исчезнувшее правило.
| Номер | Что было | Почему снято |
|---|---|---|
| META-16 | имя файла — kebab-case | вреда от нарушения нет (META-25); осталось прозой в «Оформлении» |
| META-26 | запрет слов обязательства в обосновании | правило о заглавных уже делает строчное слово ненормативным, а форму обоснования рамками не ограничивают |