Files
crank/docs/development-rules.md
T
2026-03-28 00:58:56 +03:00

12 KiB
Raw Blame History

Правила разработки

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
  • YAML import/export
  • versioning logic

5.2. Что допускается делать сначала каркасом, потом тестами

  • frontend layout;
  • wiring приложений;
  • пустые axum handlers;
  • начальный scaffold cargo workspace.

Но как только появляется логика, она должна переходить под тесты.

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 реализуют контракты, заданные ближе к домену.

8. Git workflow

8.1. Remote

Удаленный репозиторий проекта:

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. 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 только на английском;
  • стараемся вообще обходиться без комментариев в коде за счет самоописывающегося дизайна;
  • не допускаем временных архитектурных компромиссов, которые потом невозможно разгрести.