Files
crank/docs/development-rules.md
T
2026-05-03 19:48:04 +00:00

298 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Правила разработки
## 1. Назначение документа
Этот документ фиксирует, как именно должен разрабатываться проект:
- в каком стиле писать код;
- как применять `TDD`;
- как вести git;
- как принимать архитектурные решения во время реализации.
Цель документа - сделать процесс разработки предсказуемым и не дать проекту расползтись по качеству.
## 2. Базовые принципы
- сначала проектирование, потом код;
- сначала тест, потом реализация;
- идти по циклу `RGR + commit`;
- сначала маленький модуль, потом интеграция;
- одна ответственность на один модуль;
- никаких "временных" god-struct и "потом распилим".
## 3. Основной процесс разработки
Рекомендуемый цикл для каждой фичи:
1. Зафиксировать контракт в документации или тесте.
2. Написать failing test.
3. Реализовать минимальный код, который проходит тест.
4. Выполнить refactor без изменения поведения.
5. Сделать атомарный commit.
6. Если логически завершена часть фичи, сделать push.
7. Добавить integration test, если фича выходит за границы одного модуля.
8. Обновить документацию, если изменился контракт.
Это и есть базовый `TDD`-процесс проекта в форме `Red -> Green -> Refactor -> Commit`.
## 4. RGR + commit
Для проекта принимается классический цикл:
1. `Red`
2. `Green`
3. `Refactor`
4. `Commit`
Правила:
- без commit после завершенного `RGR`-цикла шаг не считается завершенным;
- commit должен фиксировать одну логическую единицу изменения;
- если несколько `RGR + commit` логично закрывают часть фичи, после этого делается push;
- не нужно ждать полного завершения всей feature branch, чтобы отправить изменения в удаленный репозиторий.
## 5. TDD-правила
### 5.1. Что пишется через TDD обязательно
- `crank-schema`
- `crank-mapping`
- `crank-registry`
- `crank-runtime`
- `admin-api`
- `mcp-server`
- YAML import/export
- versioning logic
- любая backend-логика, меняющая доменный контракт, поведение runtime, storage, auth, execution или transport
### 5.2. Что допускается делать сначала каркасом, потом тестами
- frontend layout;
- frontend copy, UX cleanup и визуальная реструктуризация;
- wiring приложений;
- пустые `axum` handlers;
- начальный scaffold `cargo workspace`.
Но как только появляется логика, она должна переходить под тесты.
Практическое правило проекта:
- для backend `TDD` обязателен;
- для frontend строгий `TDD` не требуется на уровне верстки, копирайта и UX-правок;
- frontend-изменения все равно должны подтверждаться проверками, smoke-тестами или e2e там, где это уместно.
### 5.3. Правило минимального шага
Нельзя писать сразу большую "умную" реализацию на сотни строк без промежуточных тестов.
Особенно это запрещено для:
- mapping engine;
- protobuf normalization;
- publish flow;
- YAML import pipeline.
## 6. Правила по коду
### 6.1. Стиль модулей
- модуль должен иметь одну четкую ответственность;
- публичный API модуля должен быть минимальным;
- если модуль начинает решать две разные задачи, он делится;
- `utils`, `common`, `helpers` допускаются только в очень редких случаях и с узким смыслом.
### 6.2. Стиль структур
- маленькие `struct`;
- явные типы вместо "универсальных" JSON-объектов там, где контракт уже известен;
- protocol-specific поля не смешиваются в одной структуре без discriminated union;
- методы на `impl` не должны тащить инфраструктурные зависимости.
### 6.3. Самоописывающийся код
Для проекта принимается подход self-documenting code:
- названия функций, переменных, типов и модулей должны быть достаточно точными, чтобы код читался как текст;
- комментарии в коде считаются исключением, а не нормой;
- если код хочется "объяснить" комментарием, сначала нужно попытаться упростить названия и декомпозицию;
- комментарии в коде по умолчанию не пишутся.
Допустимое исключение:
- редкий комментарий для неочевидного инварианта или ограничения внешнего протокола.
Но базовое правило проекта:
- комментарии в коде исключаем.
### 6.4. Язык кода и git
Для проекта фиксируется:
- commit messages только на английском языке;
- комментарии в коде только на английском языке, если они все-таки неизбежны;
- имена типов, функций, переменных, модулей и тестов только на английском языке.
### 6.5. Стиль ошибок
- использовать типизированные ошибки;
- ошибка должна сохранять стадию отказа: schema, mapping, adapter, external, persistence;
- нельзя сваливать все в строковый `anyhow` на границах домена.
### 6.6. Стиль async
- `async` использовать только там, где есть реальная I/O или async boundaries;
- не превращать чистую доменную логику в `async` без причины;
- не смешивать чистую валидацию и сетевые вызовы в одном методе.
## 7. Правила проектирования
Проект разрабатывается с опорой на `Clean Architecture`.
### 7.1. Что нельзя делать
- один большой `OperationService` на весь проект;
- один `AppState` со всеми зависимостями мира;
- один adapter с `match protocol` на сотни строк;
- доменные методы, которые знают про SQL, HTTP и файлы одновременно;
- скрытую магию в mapping generation.
### 7.2. Что нужно делать
- использовать `trait` на инфраструктурных границах;
- использовать `service/use case` для orchestration;
- держать доменные типы отдельно от DTO;
- создавать explicit runtime view для исполнения;
- держать published flow отдельно от draft editing.
### 7.3. Dependency rule
Для проекта фиксируется dependency rule:
- внешние слои могут зависеть от внутренних;
- внутренние слои не зависят от внешних;
- домен не знает про HTTP, SQL, storage и transport;
- adapters и repositories реализуют контракты, заданные ближе к домену.
## 7.4. Open-core правило
Для проекта фиксируется дополнительное правило:
- код `Community` в целевой split-модели живет в `crank-community`;
- коммерческий код не должен попадать в public repository "на будущее";
- в public code допустимы только extension seams, capability flags и контракты для private implementations;
- edition gating должно проверяться на серверной стороне, а не только в UI.
## 8. Git workflow
## 8.1. Remote
Удаленный репозиторий проекта:
```text
git@github.com:bsodfather/crank.git
```
### 8.2. Ветки
Фиксируем такой workflow:
- `main` - стабильная ветка;
- крупные фичи делаются в отдельной ветке `feat/<feature-name>`;
- после merge feature-ветка удаляется и в `origin`, и локально.
Примеры:
- `feat/workspace-scaffold`
- `feat/schema-model`
- `feat/mapping-engine`
- `feat/admin-api-v1`
### 8.3. Коммиты
Коммит должен:
- быть маленьким;
- содержать одну логическую единицу;
- по возможности включать тесты вместе с реализацией;
- не смешивать refactor и новую фичу без причины.
Коммиты пишутся только на английском языке.
Хороший порядок:
1. `test: add failing tests for schema validation`
2. `feat: implement schema validator`
3. `refactor: simplify schema field traversal`
### 8.4. Push policy
Фиксируем такую политику push:
- push делается периодически;
- не нужно ждать полного закрытия feature branch;
- push делается после одного или нескольких логически связанных `RGR + commit`;
- push должен оставлять ветку в консистентном состоянии.
### 8.5. Current delivery mode
Для текущего этапа проекта фиксируется отдельное правило доставки:
- рефакторинг;
- небольшие исправления;
- UX/copy cleanup;
- documentation-driven remediation
по умолчанию вливаются напрямую в `main` в GitHub без обязательного PR.
PR остается допустимым, если:
- изменение большое;
- меняется публичный контракт;
- нужен отдельный review gate;
- работа идет рискованным или спорным срезом.
### 8.6. Merge cleanup
После merge в `main` обязательно:
- удалить remote branch;
- удалить локальную branch;
- не оставлять merged feature branches висеть в репозитории.
## 9. Definition of Done
Фича считается законченной, если:
- код реализован;
- unit/integration tests добавлены и проходят;
- документация обновлена, если изменился контракт;
- нет явного архитектурного долга "починим потом";
- фича вписывается в принятые границы слоев.
При этом для каждой конкретной фичи должен существовать свой локальный `DoD`, описанный в плане реализации.
## 10. Порядок принятия решений
Если в ходе реализации возникает спорное решение:
1. Проверяется текущая документация.
2. Если решение уже зафиксировано, следуем ему.
3. Если решение не зафиксировано, сначала обновляется документация.
4. Только после этого пишется код.
Это важно, чтобы код не начал определять архитектуру задним числом.
## 11. Практический итог
Для этого проекта правильный режим разработки такой:
- проектируем заранее;
- пишем через `TDD` в форме `RGR + commit` там, где есть логика;
- двигаемся маленькими этапами;
- ведем каждую фичу в отдельной ветке `feat/<feature-name>`;
- пушим атомарно и периодически;
- пишем commit messages и неизбежные code comments только на английском;
- стараемся вообще обходиться без комментариев в коде за счет самоописывающегося дизайна;
- не допускаем временных архитектурных компромиссов, которые потом невозможно разгрести.