компоненты как адресат сборки и плоский набор
- компонент — область репозитория, где выбранные слои действуют одновременно; сборка идёт по разу на компонент, у каждого своя директория копий, подписка и локальная часть, секции [components.<имя>] в манифесте - плоский набор описан как низкий конец модели, а не отдельный режим: тема с одним слоем собирается копированием, ключи оси и lang/stack не пишутся - в TODO заведён вопрос о реестре значений осей и судьбе extends:
This commit is contained in:
@@ -53,13 +53,27 @@ conventions/
|
||||
stack/<стек>/ привязка к инструменту, хранилищу, транспорту
|
||||
```
|
||||
|
||||
Оси — раскладка **канона**; в репозитории копия лежит плоско, файлом на
|
||||
тему. Пути файлов даются относительно `conventions/`
|
||||
(`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии.
|
||||
На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс
|
||||
уникален по всему канону (он перечислен в манифесте набора), поэтому
|
||||
идентификатор не зависит ни от оси, ни от того, как собран файл у
|
||||
потребителя.
|
||||
Ось файл **объявляет в шапке**, а не наследует от директории (META-38):
|
||||
|
||||
```yaml
|
||||
topic: logging
|
||||
prefix: SLOG
|
||||
lang: go
|
||||
```
|
||||
|
||||
Ключей оси нет — базовый слой темы. Слова те же, что в подписке потребителя
|
||||
(`lang`, `stack`), так что переводить между двумя сторонами нечего. Дерево
|
||||
директорий повторяет объявленное для человека и остаётся раскладкой
|
||||
**канона**: в репозитории копия лежит плоско, файлом на тему. Пути файлов
|
||||
даются относительно `conventions/` (`arch/db-identifiers.md`) и адресуют
|
||||
исходник канона, а не место в копии. На **правила** ссылаются идентификатором
|
||||
без пути: `KEYS-5`. Префикс уникален по всему канону (он перечислен в
|
||||
манифесте набора), поэтому идентификатор не зависит ни от оси, ни от того, как
|
||||
собран файл у потребителя.
|
||||
|
||||
Объявление вдобавок выражает то, чего дерево не умеет: слой, осмысленный
|
||||
только при совпадении языка и инструмента сразу (`lang: go` и `stack: slog` в
|
||||
одной шапке).
|
||||
|
||||
Тест — по тому, замена чего убивает правило:
|
||||
|
||||
@@ -84,6 +98,31 @@ conventions/
|
||||
пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая
|
||||
работа.
|
||||
|
||||
## Плоский набор
|
||||
|
||||
Осей может не быть вовсе. Набор, где у каждой темы ровно один слой, — не
|
||||
особый режим, а низкий конец той же модели: сборка «база → язык → стек»
|
||||
на нём даёт просто копию файла.
|
||||
|
||||
```
|
||||
conventions/
|
||||
logging.md topic: logging, prefix: LOGS
|
||||
errors.md topic: errors, prefix: ERRS
|
||||
time.md topic: time, prefix: TIME
|
||||
```
|
||||
|
||||
Ключей оси в шапках нет, `lang` и `stack` в подписке не пишутся — выбирать
|
||||
не из чего. Так дешевле начинать и так выглядит чужой набор, которому три оси
|
||||
объяснять незачем, чтобы записать пять правил.
|
||||
|
||||
Цена платится при росте, и она не в инструменте: когда плоская тема
|
||||
расслаивается, уехавшие в новый файл правила получают новый префикс и новую
|
||||
нумерацию. Смягчается это тем, что уехавшее правило остаётся на месте
|
||||
заглушкой СНЯТО с новым адресом в причине (META-31, META-32), и тем, что
|
||||
резать нужно правильной стороной: база остаётся в исходном файле со своими
|
||||
идентификаторами, а наружу уезжает специфичное. Если второй язык виден
|
||||
заранее, дешевле сразу разложить по осям.
|
||||
|
||||
## Темы
|
||||
|
||||
**Тема — набор правил об одном фокусе разработки:** время, конфигурация,
|
||||
@@ -109,6 +148,13 @@ prefix: KEYS
|
||||
репозиториях — в шапке `origin:` каждой копии, в подписке манифеста, в тексте
|
||||
ссылок, — и выданное второй теме начинает указывать на другой набор правил.
|
||||
|
||||
Раз имя вечно, называют тему **решением и его адресатом**, а не ролью части
|
||||
конкретного проекта (META-37). Логи сервера и логи браузера — это `logging` и
|
||||
`client-logging`, а не `logging-backend` и `logging-frontend`: роль
|
||||
принадлежит сегодняшнему устройству одного репозитория и молча начинает врать,
|
||||
а суффиксная пара вдобавок навязывает чтение «две разновидности одного», хотя
|
||||
по границе темы это разные решения — общего у них три правила из сорока.
|
||||
|
||||
## Префиксы
|
||||
|
||||
Каждый файл канона объявляет в шапке свой префикс правил:
|
||||
@@ -143,24 +189,60 @@ extends: arch/db-identifiers.md
|
||||
репозиторий на базу просто не подписан.
|
||||
|
||||
`extends` — документация связи, а не механизм: за тем, чтобы база лежала
|
||||
рядом, никто не следит.
|
||||
рядом, никто не следит. С объявленной осью база к тому же находится сама —
|
||||
это слой той же темы без ключей `lang` и `stack`, — так что ключ остаётся
|
||||
подсказкой человеку и ничего не выбирает.
|
||||
|
||||
## Компонент — адресат сборки
|
||||
|
||||
Подписка принадлежит репозиторию, а собранный документ адресован не
|
||||
репозиторию, а куску кода. Пока проект однороден, разницы нет; два языка её
|
||||
проявляют: `lang = ["go", "javascript"]` склеили бы в один файл го-слой и
|
||||
js-слой, из которых к правимому коду относится ровно половина.
|
||||
|
||||
**Компонент — область репозитория, где все выбранные слои действуют
|
||||
одновременно.** `sqlite` и `postgres` в теме схемы действуют вместе — разные
|
||||
таблицы одного сервиса; го-слой и js-слой не действуют вместе никогда, потому
|
||||
что строка кода написана на чём-то одном. Компонент поэтому совпадает с тем,
|
||||
у чего один язык, один набор инструментов и один вид приложения (META-36).
|
||||
|
||||
Уровней в модели становится три: набор → проект → компонент. Сборка не
|
||||
меняется — та же линейка «база → язык → стек», прогнанная по разу на
|
||||
компонент.
|
||||
|
||||
## Копия в репозитории
|
||||
|
||||
Копия плоская: **один файл на тему**, слои осей идут внутри него секциями в
|
||||
порядке `arch` → язык → стек. Пути канона в копии не воспроизводятся.
|
||||
порядке база → язык → стек. Пути канона в копии не воспроизводятся. Каждый
|
||||
компонент получает свою директорию:
|
||||
|
||||
```
|
||||
docs/conventions/
|
||||
.conventions.toml
|
||||
backend/docs/conventions/
|
||||
README.md собственный, не собирается
|
||||
READING.md как читать конвенцию — приезжает из канона
|
||||
logging.md база + lang/go + stack/slog
|
||||
time.md arch/time.md + lang/go/time.md
|
||||
db-identifiers.md arch/db-identifiers.md + lang/go/db-identifiers.md
|
||||
app-directories.md arch/… + stack/ansible/…
|
||||
web/docs/conventions/
|
||||
READING.md
|
||||
client-logging.md база + lang/javascript + stack/express
|
||||
```
|
||||
|
||||
Так конвенция остаётся самодостаточным документом: тот, кто проверяет по ней
|
||||
код — человек или агент, — читает один файл и не собирает тему из трёх мест.
|
||||
При одном компоненте это ровно прежняя раскладка — `docs/conventions/` в
|
||||
корне.
|
||||
|
||||
Директории компонентов различны, и это единственное, что разводит копии:
|
||||
`logging.md` двух компонентов — разные файлы с одинаковым `origin: logging`,
|
||||
и какой из них какой, сборщик знает по манифесту, а читатель — по пути.
|
||||
Локальные части у них независимы, ради чего всё и затевается: правило,
|
||||
механизированное линтером в go-компоненте, в js-компоненте не механизировано,
|
||||
и один общий файл этого не записал бы.
|
||||
|
||||
`READING.md` лежит рядом с копиями, то есть по одному на компонент. Файл
|
||||
генерируемый, а директория с правилами обязана объяснять себя тому, кто в неё
|
||||
попал.
|
||||
|
||||
Имена в директории делятся на три вида: `README.md` принадлежит репозиторию и
|
||||
сборщик его не трогает, `READING.md` принадлежит канону и перезаписывается
|
||||
@@ -230,7 +312,7 @@ MIGR-6 не соблюдается в `show_history`, `queue`: составны
|
||||
| Файл | Где лежит | Что описывает |
|
||||
|---|---|---|
|
||||
| `suite.toml` | в наборе | сам набор: язык, темы, префиксы правил |
|
||||
| `.conventions.toml` | в проекте | подключение: откуда копии, какие темы, язык, стек |
|
||||
| `.conventions.toml` | в проекте | подключение: откуда копии, компоненты и их подписки |
|
||||
|
||||
Манифест набора — единственное место, где перечислены оба идентификатора
|
||||
канона; правила у них общие, поэтому и файл один. Манифест подключения
|
||||
@@ -239,17 +321,29 @@ MIGR-6 не соблюдается в `show_history`, `queue`: составны
|
||||
```toml
|
||||
source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git"
|
||||
|
||||
[components.backend]
|
||||
dir = "backend/docs/conventions"
|
||||
lang = ["go"]
|
||||
stack = ["sqlite", "htmx"]
|
||||
stack = ["slog", "sqlite"]
|
||||
topics = ["logging", "errors", "time"]
|
||||
|
||||
topics = ["time", "config", "db-identifiers"]
|
||||
[components.web]
|
||||
dir = "web/docs/conventions"
|
||||
lang = ["javascript"]
|
||||
stack = ["express"]
|
||||
topics = ["client-logging"]
|
||||
```
|
||||
|
||||
`lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает
|
||||
только те слои, которые репозиторию подходят. `topics` — подписка, именами из
|
||||
манифеста набора; списка подписчиков у канона по-прежнему нет, список подписок
|
||||
есть
|
||||
только у потребителя.
|
||||
только те слои, которые компоненту подходят, и совпадают со словами, которыми
|
||||
слой объявил свою ось. `topics` — подписка, именами из манифеста набора;
|
||||
списка подписчиков у канона по-прежнему нет, список подписок есть только у
|
||||
потребителя.
|
||||
|
||||
Компонент пишется всегда, даже когда он один: сокращённая плоская форма
|
||||
сэкономила бы три строки и завела бы второй способ сказать то же самое.
|
||||
Имя компонента при этом не служебное — им сборщик отвечает, что и куда
|
||||
собрал. У плоского набора `lang` и `stack` в компоненте просто отсутствуют.
|
||||
|
||||
Как именно инструмент добирается до канона — путь на диске, git, HTTP —
|
||||
дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это
|
||||
@@ -265,20 +359,25 @@ topics = ["time", "config", "db-identifiers"]
|
||||
любого другого документа. Это главный канал тихого дрейфа, поэтому
|
||||
`AGENTS.md` каждого потребителя должен явно говорить:
|
||||
|
||||
> Файлы в `docs/conventions/` с шапкой `origin:` — копии из канона
|
||||
> `dev-conventions`. Репозиторное пишется только ниже `<!-- conv:local -->`;
|
||||
> всё выше маркера перезаписывается при обновлении. Своё правило — с
|
||||
> префиксом на `X`.
|
||||
> Файлы с шапкой `origin:` в директориях конвенций (пути — в
|
||||
> `.conventions.toml`) — копии из канона `dev-conventions`. Репозиторное
|
||||
> пишется только ниже `<!-- conv:local -->`; всё выше маркера
|
||||
> перезаписывается при обновлении. Своё правило — с префиксом на `X`.
|
||||
|
||||
## Команды
|
||||
|
||||
```bash
|
||||
conv list # какие темы есть в каноне
|
||||
conv list # какие темы есть в каноне и что подключено
|
||||
conv add time # добавить тему в манифест и собрать файл
|
||||
conv add time --for backend # то же, когда компонентов несколько
|
||||
conv pull # пересобрать всё, что перечислено в манифесте
|
||||
# (и обновить READING.md рядом с копиями)
|
||||
conv pull --for web # только один компонент
|
||||
```
|
||||
|
||||
При одном компоненте `--for` не нужен. При нескольких команда без него не
|
||||
угадывает, а отказывает и перечисляет имена.
|
||||
|
||||
Отчёт о том, что изменилось, отдельной командой не выдаётся: после `pull`
|
||||
его показывает `git diff`, а решение — принять, поправить или откатить —
|
||||
принимает человек перед коммитом.
|
||||
@@ -315,6 +414,7 @@ conv pull # пересобрать всё, что переч
|
||||
прежнюю: зеркальное дерево копий вместо плоского, именованные регионы
|
||||
`<!-- local:имя -->` вместо одного маркера, `origin_hash` в шапке и команды
|
||||
`status`, `diff`, `push`; `READING.md` рядом с копиями он тоже пока не
|
||||
кладёт. Сами конвенции уже приведены к новой модели — именованных регионов в
|
||||
каноне нет. Ни один репозиторий-потребитель не
|
||||
подключён, поэтому переход никого не ломает.
|
||||
кладёт, компонентов и объявленной оси не знает и выбирает слои по пути. Сами
|
||||
конвенции уже приведены к новой модели — именованных регионов в каноне нет,
|
||||
ось объявлена в шапках. Ни один репозиторий-потребитель не подключён, поэтому
|
||||
переход никого не ломает.
|
||||
|
||||
Reference in New Issue
Block a user