Канон 5 объявил «каждый документ docs/ — тема ревью». Правило верно ровно наполовину и потому вредно целиком. Паспорт и схему хранилища ревью читает, но темами они не являются: по ним нельзя сказать «в этом изменении сделано не так», они задают границу, по которой судит чужая тема. Журнал решений и журнал наблюдений ревью изменения не нужны вовсе — ADR объясняет прошлое, а не предъявляет требование. Разметчик, применявший правило буквально, обязан был либо завести фантомные темы passport, adr, database, research и продублировать ими работу architecture и operations, либо потерять четыре документа молча; случались обе ветки, и в собственном образце плана docs/passport.md не попадал ни строкой, а обязательная арифметика покрытия при этом не сходилась. Категорий теперь три, разрез проверяемый. Тема — да, прямо: conventions, security, architecture и любой свой документ проекта. Источник темы — нет, но он задаёт границу для чужой: passport, database, CLAUDE.md, openspec/specs. Процессный — нет, он про то, как мы работаем: tasks, review, adr, research, .pm.json. Открыта одна категория из трёх, две другие перечислены поимённо, так что документ вне раскладки — однозначно своя тема. adr и research прогон больше не открывает ни одним проходом; docs/review остаётся читаемым, но как настройка конвейера, а не критерий. Цена записана и стала обязательной строкой границ покрытия: расхождение с записанным решением ловит теперь только сверка документации, а число под находкой обязано быть снято на этом прогоне, с приложенной командой. Классификация выдаёт задаче метку — small, medium, large. Прежние quick, standard и wide назывались ступенью и описывали ревью: как глубоко смотрим. Классифицируется же задача, и пока величина называлась свойством прогона, её естественно было пересчитывать на каждом прогоне — что конвейер и делал. Слово «ступень» удалено, а не оставлено синонимом: два имени одной вещи расходятся. Выводится метка из двух разведённых осей — размер (малое, среднее, крупное) и сложность (знакомое, незнакомое), — и равна максимуму по ним. Метка не синоним размера: малое незнакомое изменение получает large, трогая один узел, поэтому план печатает три строки с обоснованием каждая и выводить одну из другой запрещено. Оси остались русскими словами — это суждение прозой; метка английская — это идентификатор, который проходы сравнивают. Разметка переехала из ревью кода в шаг 4 пайплайна, сразу после propose. Она шла первым проходом каждого ревью кода, а перед ревью дизайна ту же величину называл сам пайплайн — то есть оркестратор, который только что довёл предложение до propose. Одно и то же измерялось дважды, и один из двух раз без разведённости с автором, ровно в той точке, ради которой разметчик заведён. Теперь запуск один на задачу, диффа он не видит, план обслуживает обе стадии, и метка после кода не пересматривается: расхождение факта с разметкой ловит журнал дефектов постфактум, как и всякую другую ошибку выбора. На диск план не пишется — четвёртый артефакт рядом с proposal, tasks и design пережил бы задачу и разошёлся бы с ней молча. Ревью дизайна тоже растёт меткой: small — specs, medium — плюс rubric, large — плюс architecture и вопрос автору о трёх формах решения. Раньше rubric и architecture включались одним условием, и medium получал ровно один проход, то есть не отличался от quick ничем. Разведены они потому, что зарабатывают на разном: рубрика порождает свойства узла и окупается уже на среднем изменении, её выход уезжает приёмочными критериями в tasks.md; архитектура отвечает на вопрос про второй способ, а он на среднем знакомом изменении отвечается «нет» ещё до запуска. small подешевел тремя способами сразу. Составом: приёмник тем не запускается, три темы ядра переходят к code сверкой по записанным инвариантам CLAUDE.md с потолком в одну находку, и это не «глубина ниже», а другой дом темы. Входом: specs читает только дельта-спеку, code — только индекс конвенций. Потолком: он появился у каждого опиниативного прохода, а не у одного basics, и у половин code он раздельный, потому что конвенционных находок больше по построению и в общем списке они вытеснили бы техническую половину. Сработавший потолок обязан быть объявлен строкой — молчащий срез неотличим от «больше не нашлось». Отрицательный тест small от этого стал жёстче, а не мягче: вопросы про обратимость миграции задавал приёмник тем, и на этой метке их не задаст никто. Пайплайн задачи вырос до двенадцати шагов. Тривиальность перестала решать состав ревью — она влияет только на explore; глубину обеих стадий называет метка. Проверено прогоном ревьюверов по готовому результату: девять расхождений найдено и починено — контракт находок печатал старый перечень проходов вместо плана по темам, три ссылки в task-batch указывали на шаг коммита вместо закрытия, запись changelog не переводила вопросы, адресованные passport и database, ops и adversary утверждали, что на нижних метках их вопросы задаёт basics, шаблон покрытия в review-code зашивал потолки small намертво, триггеры метки рассыпались на два списка против трёх, тема из директивы CLAUDE.md могла остаться без запуска исполнителя. Гейт зелёный: фронтматтеры, копии, одиннадцать диаграмм, ruff, pyrefly; docs.py прогнан на живом фикстуре и печатает категорию в отказе. Канон повышен до версии 6 с записью, выполнимой upgrade. Решения — 40–44. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
209 lines
16 KiB
Markdown
209 lines
16 KiB
Markdown
# Язык проектных текстов
|
||
|
||
Правила для всего, что пишется словами: задачи и цели, документы канона,
|
||
решения ADR, записки разведки, сообщения коммитов. Не для кода и не для
|
||
сообщений программы пользователю — там свои конвенции проекта.
|
||
|
||
Основа — **информационный стиль** Максима Ильяхова ([учебник
|
||
бюро](https://bureau.ru/projects/book-text/), книга «Пиши, сокращай»). Он
|
||
написан для рекламы, статей и писем, поэтому взят не целиком: ниже сказано, что
|
||
взято и что отброшено намеренно.
|
||
|
||
## Зачем он здесь
|
||
|
||
Проектный текст читают в двух положениях, и оба неудобные: **выбирают, брать ли
|
||
задачу**, глядя в строку индекса и один экран тела; и **возвращаются через
|
||
квартал**, не помня контекста. Оба положения наказывают одно и то же — слова, не
|
||
несущие сведений. Информационный стиль ровно про это, и его польза здесь не
|
||
эстетическая: текст, из которого нельзя достать факт, заставляет открывать код,
|
||
а это и есть цена, которой мы избегаем.
|
||
|
||
## Что взято
|
||
|
||
**Полезное действие.** У каждого текста есть вопрос, на который он отвечает, и
|
||
читатель, который этот вопрос задаёт. Не отвечает — не пишется. У задачи это
|
||
«зачем она нужна» и «что станет наблюдаемо иначе»; у документа канона — его
|
||
собственный вопрос («что это за система», «как сложено», «почему так решили»).
|
||
Текст, который не отвечает ни на чей вопрос, сокращается до нуля — это законный
|
||
исход правки.
|
||
|
||
**Глагол вместо отглагольного существительного, действие вместо состояния.**
|
||
«Обработчик не проверяет владельца», а не «проверка владельца не
|
||
осуществляется»; «сопоставляет по имени», а не «осуществляет сопоставление по
|
||
имени». Отглагольное существительное прячет того, кто действует, — а в
|
||
техническом тексте именно он и важен.
|
||
|
||
**Активный залог.** «Скрипт переписывает индекс», а не «индекс переписывается
|
||
скриптом». Страдательный залог остаётся там, где деятель неизвестен или
|
||
неважен, и это не поблажка: «файл удаляется» верно, когда удаляет любая из трёх
|
||
команд.
|
||
|
||
**Конкретика вместо оценок.** Факты, имена, цифры: «время ответа доходит до
|
||
800 мс», а не «работает медленно»; «тело 40 МиБ держит блокировку 5 секунд», а
|
||
не «большие тела тормозят». Оценка допустима, когда за ней в той же фразе стоит
|
||
факт. Без факта оценка — не сведение, а настроение.
|
||
|
||
**Стоп-слова.** Убирается то, что можно убрать без потери смысла:
|
||
|
||
| Что | Примеры |
|
||
| --- | --- |
|
||
| канцелярит | является, осуществляется, в целях, в рамках, данный, вышеуказанный, необходимо отметить |
|
||
| вводные-паразиты | в общем, как известно, стоит отметить, не секрет, что |
|
||
| усилители | очень, крайне, достаточно, абсолютно, максимально, полностью |
|
||
| синонимы одного качества | «понятный и простой», «быстрый и производительный» |
|
||
| неопределённое | какой-то, некоторый, соответствующий, определённый |
|
||
|
||
Проверка одна: **вычеркни слово. Смысл изменился — оставляй.**
|
||
|
||
**Одна мысль — одно предложение.** Предложение, в котором два независимых
|
||
утверждения, делится. Придаточное, которое можно вынести в отдельную фразу,
|
||
выносится.
|
||
|
||
Исключение — **поля, которым формат отвёл одно предложение**. «Зачем» в мете
|
||
задачи именно такое: оно повторяется строкой индекса, и второе предложение там
|
||
просто не поместится. Такое поле либо укладывается в одну фразу, либо
|
||
сокращается, но не делится.
|
||
|
||
**Параллельность.** Однородное пишется одинаково: пункты списка — одной
|
||
грамматической формой, разделы одного вида — одним порядком, заголовки одного
|
||
уровня — одним типом фразы. Разнобой читатель принимает за разницу по существу и
|
||
ищет её.
|
||
|
||
**Заголовок работает.** Заголовок называет содержание раздела, а не тему
|
||
вообще: «Что проверяет `check`», а не «О проверках». Заголовков ставится
|
||
столько, чтобы длинный текст можно было просматривать, а не только читать
|
||
подряд.
|
||
|
||
## Что отброшено намеренно
|
||
|
||
Инфостиль написан для текстов, где читателя надо удержать. Проектный текст
|
||
читают потому, что надо, и держать его нечем. Отсюда три расхождения:
|
||
|
||
- **Парцелляция и рубленые фразы — нет.** Приём «Коротко. Ещё короче. Вот так»
|
||
ломает причинную связь, а в решении и в задаче ценность именно в ней:
|
||
«поэтому», «иначе», «раз так» несут смысл и остаются.
|
||
- **Не всякое вводное — мусор.** «Если», «иначе», «при таком-то условии»,
|
||
«в отличие от» — это условия и противопоставления, то есть сведения. Режутся
|
||
вводные, которые не меняют смысл предложения.
|
||
- **Скобки и точка с запятой остаются.** В технической записи скобки несут
|
||
уточнение — имя команды, единицы, слаг, — и запрет на них удлинил бы текст, а
|
||
не сократил. Запрет на многоточие принимаем: в проектном тексте оно значит
|
||
«дописать позже», и такой текст лучше не публиковать.
|
||
|
||
И общее: инфостиль призывает «снять корону с себя и надеть на читателя». Здесь
|
||
читатель — **ты сам через квартал** и тот, кто возьмёт задачу. Писать для них
|
||
значит называть состояние и остаток, а не пересказывать, как было интересно
|
||
разбираться.
|
||
|
||
## Англицизмы
|
||
|
||
Англицизм-калька заменяется, когда у него есть естественный русский аналог.
|
||
|
||
<!-- дом: язык-англицизмы -->
|
||
|
||
| Калька | Русский аналог |
|
||
| --- | --- |
|
||
| флоу | поток, процесс, сценарий |
|
||
| фикс, зафиксить | исправление, исправить, починить |
|
||
| чекать | проверять |
|
||
| апрув, заапрувить | согласование, согласовать |
|
||
| best-effort | по возможности |
|
||
| кейс | случай, сценарий |
|
||
| перформанс | производительность |
|
||
| матчинг, смэтчить | сопоставление, сопоставить |
|
||
| зарелизить | выпустить, выложить |
|
||
| отрефакторить | переписать, разделить, убрать второй путь |
|
||
|
||
Насильно не переводится то, что является **именем вещи**: термины технологий и
|
||
протоколов (`SQL`, `API`, `CSV`, `N+1`, `IDOR`), имена классов, методов, полей,
|
||
таблиц и команд, слаг, а также термин, у которого нет точного русского
|
||
эквивалента и который в команде уже прижился.
|
||
|
||
Цель — простой и точный текст, а не пуризм. Русский аналог звучит коряво или
|
||
искажает смысл — остаётся термин.
|
||
|
||
<!-- /дом: язык-англицизмы -->
|
||
|
||
## Свой словарь — закрытый список
|
||
|
||
Слово, не переводимое потому, что оно **имя вещи этого процесса**, а не украшение.
|
||
Оговорка «термин прижился» без списка проверяема на глаз и потому не проверяема:
|
||
прижившимся выглядит любое слово, встреченное трижды.
|
||
|
||
<!-- дом: язык-словарь -->
|
||
| Термин | Что называет |
|
||
| --- | --- |
|
||
| интейк | заведение записи с фильтром и дедупом: «заведение» называет создание файла, слить их — смешать две операции |
|
||
| триаж | стадия конвейера, сводящая находки в решение |
|
||
| провенанс | обязательное свойство числа: чем и при каких условиях получено. «Источник» рядом называет саму запись, а не свойство |
|
||
| дедуп, дедупликация | сверка нового против уже лежащего |
|
||
| чек-лист | перечень, по которому идут сверху вниз, называя исход каждой строки |
|
||
| дифф, `--base` | разница между состояниями в git |
|
||
| промпт | текст, которым зовут модель |
|
||
| change, capability, spec | сущности OpenSpec, имена вещей чужого инструмента |
|
||
| generative, applicative | роды проходов ревью, вводятся определением по месту |
|
||
|
||
**Список закрыт.** Слово не отсюда и не из таблицы имён вещей выше — находка, а
|
||
не «принятый стиль»: у него либо есть живой русский аналог, либо оно требует
|
||
ввода одной строкой при первом употреблении.
|
||
|
||
Отсюда же читается снятое. Эти слова из текстов убраны, и возвращать их не надо:
|
||
**конфляция** (смешение), **декорреляция** (разведённость, разведён с кем-то),
|
||
**непоймание** (почему не поймали), **эвал-сет** (проверочный набор), **гайд**
|
||
(руководство). Каждое было латинизмом или калькой при живом русском слове, и
|
||
каждое к моменту снятия жило в трёх-шести файлах разом — то есть выглядело
|
||
словарём, не будучи им.
|
||
|
||
<!-- /дом: язык-словарь -->
|
||
|
||
## Жаргон и метафоры
|
||
|
||
Система не описывается внутренними метафорами и образными ярлыками: автору они
|
||
понятны, читателю — нет. Вещь называется прямо.
|
||
|
||
<!-- дом: язык-жаргон -->
|
||
|
||
| Метафора-жаргон | Прямо |
|
||
| --- | --- |
|
||
| рычаг (кэша, отбора) | условие отбора, параметр |
|
||
| навешен не на тот счётчик | завязан не на тот счётчик |
|
||
| переширокий матчинг по имени | слишком грубое сопоставление по имени, слишком много слабых совпадений |
|
||
| костыль | временное решение, обходной путь — и в чём именно |
|
||
| просело, отвалилось | стало медленнее на столько-то, перестало отвечать |
|
||
|
||
Проверка: **фраза требует, чтобы читатель додумал образ, — заменяется буквальным
|
||
описанием того, что происходит.**
|
||
|
||
<!-- /дом: язык-жаргон -->
|
||
|
||
## Термин, которого нет в проекте
|
||
|
||
Термин, не встречающийся ни в паспорте, ни в архитектуре, ни в конвенциях,
|
||
**вводится одной строкой или не употребляется**. Свой словарь у отдельной записи
|
||
— самый дешёвый способ сделать беклог нечитаемым для того, кто вернётся к нему
|
||
через квартал.
|
||
|
||
Заменять незнакомый термин догадкой нельзя: догадка о предметной области дороже
|
||
непонятного слова, потому что выглядит понятной.
|
||
|
||
## Порог правки
|
||
|
||
<!-- дом: порог-правки -->
|
||
|
||
**Правка без нарушенного правила не делается.** Текст, переписанный «чтобы
|
||
звучало лучше», обесценивает список замечаний: когда половина из них вкусовая,
|
||
перестают читать весь список, и вместе с ним пропадают настоящие находки.
|
||
Сомневаешься — не правь. Формулировка, которая просто **не твоя**, — не находка.
|
||
|
||
**Систематичность нарушения — не довод в его пользу.** Одна и та же ошибка в
|
||
пяти файлах не становится «принятым стилем»: чаще это значит, что правило не
|
||
применялось вовсе, — и находка тем важнее. «Так сделано везде» годится как
|
||
основание для **одной находки на весь набор** («правило N нарушено в пяти
|
||
записях, перечень: …»), но не как основание промолчать. Принятым считается
|
||
только то, что назвал зовущий или что записано в конвенциях проекта.
|
||
|
||
<!-- /дом: порог-правки -->
|
||
|
||
И обратное: язык правится **по ходу той операции, которая записи касается**.
|
||
Беклог не переписывают ради языка.
|