TEMPLATE.md 14,2 КБ
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# TEMPLATE — переиспользуемый набор решений

Свод практик, отработанных на `kg2cytoscape` и пригодных для любого нового
проекта (в первую очередь — CLI/утилиты на Node.js). В памяти MCP-сервера
`memory` этот набор хранится под слагом **`template`** (сущности
`template:*`, корень `project:template`).

> Это **не** документация kg2cytoscape. Здесь — то, что переносится в другие
> проекты целиком. Специфика kg2cytoscape остаётся в [**AGENTS.md**](AGENTS.md)
> и [**SCHEMA.md**](SCHEMA.md).

## Что переносится

| Решение | Суть | Куда смотреть в этом репо |
|---|---|---|
| **Слои L0–L5** | разбиение по уровням абстракции, чистые функции | [REFACTORING.md](REFACTORING.md) |
| **Порядок TDD** | тесты → RED → код → GREEN | [AGENTS.md](AGENTS.md) |
| **Покрытие сценариев** | тест сценария с фейковым адаптером, `deps` | [AGENTS.md](AGENTS.md) |
| **Без runtime-зависимостей** | stdlib + встроенный `fetch`; инструменты в devDeps | [package.json](package.json) |
| **Статический анализ** | ESLint + Prettier + `tsc --checkJs`, `npm run check` | [eslint.config.mjs](eslint.config.mjs), [prettier.config.mjs](prettier.config.mjs), [jsconfig.json](jsconfig.json) |
| **CI** | джоба `check` на push и MR | [.gitlab-ci.yml](.gitlab-ci.yml) |
| **Карта документации** | README / GUIDE / AGENTS / SCHEMA / CHANGELOG / ROADMAP | [README.md](README.md) |
| **Разбор аргументов** | вручную, без зависимостей, `--dry-run` | [src/cli/args.mjs](src/cli/args.mjs) |
| **Навык Agent Skills** | переносимый `.agents/skills/<name>/` | [.agents/skills/memory-curator/](.agents/skills/memory-curator/SKILL.md) |

## Слои L0–L5

Код делится по **уровням абстракции**: сверху сценарии, снизу примитивы.
Каждый модуль решает одну задачу и по возможности состоит из **чистых
функций** (без ввода-вывода и сети) — их легко покрыть юнит-тестами.

```
L5  cli/        точка входа, разбор аргументов
L4  usecases/   сценарии (сборка, обновление, слежение)
L3  adapter/    транспорт к внешнему сервису
L2  model/      модель и чистые вычисления
L1  parse/      разбор входа
L0  core/       примитивы (текст, экранирование, логи)
```

Поток данных однонаправленный: `parse → model → usecases → adapter`.
Имена каталогов меняются под домен, принцип — нет.

chainreaction's avatar
chainreaction включено в состав коммита
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
### Число уровней — не догма

**Догма — не количество, а два правила:**

1. **Слой абстракции.** Каждый уровень делает одно: примитивы, разбор, модель,
   транспорт, сценарии, точка входа.
2. **Зависимости только сверху вниз.** L4 может звать L3, но L3 никогда не
   зовёт L4. Именно это даёт тестируемость и заменяемость (фейковый адаптер
   вместо живого сервиса).

Число уровней — производная от проекта:

| Проект | Уровней | Как выглядит |
|---|---|---|
| Маленькая библиотека | 2–3 | `core` + `api` |
| CLI-утилита (как kg2cytoscape) | 6 | L0–L5 |
| Сервис с БД, кэшем, авторизацией | 7–9 | + репозитории, + домен, + HTTP-транспорт |

Практические следствия:

- **Пустой слой не создаём.** Нет транспорта — нет каталога. Уровень без кода = шум.
- **Индексы (L0, L1…) — удобство ссылок, а не суть.** При сжатии/растяжении их
  либо перенумеровывают, либо отказываются от номеров и называют слои по смыслу
  (`core`, `domain`, `adapter`).
- **Новый слой вводится, когда появляется новый вид ответственности**, а не
  когда «стало много файлов».

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
### Стиль проектирования

Схема `L0…L5` со стрелками сверху вниз — это **функциональный** (процедурный)
стиль: слой = уровень абстракции вычисления, данные отделены от поведения,
зависимости передаются аргументами. Он не единственный, и правило «строго
сверху вниз» в других стилях не работает.

| Стиль | Как ложатся слои | Направление зависимостей |
|---|---|---|
| Функциональный (пример kg2cytoscape) | L0…L5 по уровню абстракции | сверху вниз, к примитивам |
| ООП / DDD | domain / application / infrastructure / presentation | внутрь, к домену; инфраструктура знает домен, домен об инфраструктуре — нет (через интерфейсы) |
| Гексагональная | ядро + порты + адаптеры | адаптеры зависят от портов, не наоборот |
| Акторы / event-driven | иерархии слоёв может не быть | обмен сообщениями, а не вызовы вниз |

**Универсально** лишь то, что не зависит от стиля:

- **единственная ответственность** — модуль делает одно;
- **зависимости однонаправлены** — нет циклов между слоями (в ООП они идут
  *к домену*, в функциональном — *вниз к примитивам*).

Выбор стиля — до проекта. Прежде чем переносить схему слоёв, проверьте, что
стиль совпадает: функциональная нумерация L0–L5 в ООП-проекте введёт в
заблуждение.

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
## Порядок разработки: тесты → код

**RED обязателен.** Сначала тест, потом падение, потом код. Даже для уже
написанного кода шаг RED не пропускается (временно убрать модуль — убедиться,
что тесты падают).

Причина: тест, написанный после кода, легко оказывается тавтологичным —
проверяет то, что код и так делает, а не то, что должен.

## Покрытие сценариев

- У **каждого** сценария (L4) есть тест с **фейковым адаптером** — без живого
  внешнего сервиса.
- Зависимости (`sleep`, `stamp`, `sync`, `shouldStop`) передаются последним
  аргументом `deps` и подменяются в тестах; продакшен берёт значения по умолчанию.
- Логику, которую нужно проверить в отрыве, выносят в **чистую функцию** —
  инлайн-код внутри цикла непроверяем.
- Юнит-тесты не ловят стыки «кто кого вызывает» — на границах модулей нужны
  **контрактные проверки** (например, сценарий отвергает нефинализированную
  модель с понятной ошибкой).

Признак незакрытой задачи — у сценария нет теста.

## Без runtime-зависимостей

Проект использует только стандартную библиотеку Node.js (включая встроенный
`fetch`). Инструменты качества живут в `devDependencies` и нужны лишь для
разработки и CI.

Плюсы: простой деплой, нет уязвимостей транзитивных зависимостей, быстрый запуск.

## Статический анализ уровня 1

| Инструмент | Задача | Команда |
|---|---|---|
| ESLint | логические ошибки, неиспользуемые переменные | `npm run lint` |
| Prettier | единый формат | `npm run format:check` |
| `tsc --checkJs` | типы из JSDoc, без перехода на TypeScript | `npm run typecheck` |
| `node --test` | юнит-тесты | `npm test` |

Сводная команда — **`npm run check`** = lint → format:check → typecheck → test.

> **Грабли Prettier:** он переформатирует Markdown-таблицы (шум в diff).
> Настраивайте `format`/`format:check` **только на код** (`*.mjs`, `*.js`),
> markdown правьте точечно вручную.

## CI (GitLab)

Джоба `check` повторяет `npm run check`; запускается на push в основную ветку и
на merge request; красный пайплайн блокирует слияние. Шаблон —
[.gitlab-ci.yml](.gitlab-ci.yml).

Особенности hub.mos.ru (при переносе на другую площадку — проверить заново):

- раннеры помечены тегом и не берут джобы без тега (`run_untagged=false`) —
  **без тега задание навсегда в pending**;
- блок `default:` / `cache:` в конфиге валит CI lint (HTTP 500) — не использовать.

## Карта документации

Разделяйте документацию **по читателю**:

| Файл | Для кого | О чём |
|---|---|---|
| `README.md` | все | обзор, быстрый старт, возможности |
| `GUIDE.md` | пользователь | что делать мышкой, без внутренностей |
| `AGENTS.md` | разработчик/агент | техника, поведение внешних сервисов, подводные камни |
| `SCHEMA.md` | разработчик | формат данных, поля, поток данных |
163
| `REFACTORING.md` | разработчик | архитектура, уровни модулей, рефакторинг таксономии |
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
| `CHANGELOG.md` | все | история изменений по датам |
| `ROADMAP.md` | все | планы: сделано / в фокусе / отменено |
| `LICENSE` | все | лицензия |

В каждом файле — шапка со ссылками на остальные (навигационная сетка).
Ссылки делайте **относительными** и **жирным** текстом.

> **Грабли mermaid на hub.mos.ru:** версия 9.1.3 нестабильна — диаграмма может
> не отрисоваться («Syntax error in graph») там, где та же схема в другом файле
> работает. Если диаграмма не критична — надёжнее список; если нужна — держите
> консервативный синтаксис и проверяйте в живом UI.

## Разбор аргументов CLI

Ручной разбор без внешних зависимостей: наборы `VALUE_OPTS` (опции со
значением) и флагов, поддержка повторяемых опций. Порядок аргументов свободный.
Значения по умолчанию — в одном месте, покрыты тестами разбора.

Обязательна опция **`--dry-run`**: разбор и валидация входа без обращения к
внешнему сервису (позволяет тестировать и отлаживать офлайн).

## Навык в формате Agent Skills

Переносимый навык живёт в репозитории: `.agents/skills/<name>/SKILL.md` плюс
скрипты рядом. Агенты с поддержкой формата подхватывают его автоматически; для
клиента с другой раскладкой каталог достаточно скопировать.

Принцип переносимости: инструкции — обычный Markdown, **без ссылок на API
конкретного агента**; скрипты автономны (не импортируют код проекта).

Пример — [.agents/skills/memory-curator/SKILL.md](.agents/skills/memory-curator/SKILL.md).

## Связь с памятью проекта

В MCP-памяти этот набор хранится под слагом `template`:

- корень — `project:template`;
- сущности — `template:decision:*`, `template:toolchain:*`, `template:file:*`,
  `template:feature:*`, `template:issue:*`;
- связи `affects` / `uses` / `defined_in` указывают на корень, ключевые решения
  помечены `derived_from` к их источникам.

При старте нового проекта достаточно сослаться на `project:template` и забрать
нужные решения. Набор пополняется по ходу работы.