Эта статья про небольшую идею, которуая была опробована в open-source проекте: добавление отметки «риск» в обычные коммиты. Всего несколько символов помогают быстро понять, какие коммиты безопасные, какие требуют тестирования, а какие — рискованные. Началось это как эксперимент, но действительно изменило то, как мы думаем о тестировании и релизах.

Эта статья написана после моего доклада Commit Notations for Quality and Testability на конференции ProQuality 2025.

Контекст

Эту нотацию разработали Clare Macrae и я во время парного программирования проекта obsidian-tasks — плагине для Obsidian для управления задачами. Obsidian — это редактор на Electron, который рендерит локальные Markdown файлы и поддерживает JavaScript плагины.

Наш плагин имеет движок запросов с множеством фильтров, опций рендеринга и возможностей группировки, плюс модальное окно для создания и редактирования задач, написанное на Svelte. На 1 сентября 2025 года у него было более 2.6M скачиваний. Я присоединился к проекту в конце 2022 года, а Clare тогда уже активно разработовала этот плагин. Мы разрабатываем используя TDD (Test-Driven Development) и парное программирование.

Важно отметить, что мы работаем в почти идеальных условиях: у нас нет клиентов, которые платят денбги, мы сами выбираем, чем заниматься, и сами используем продукт. Мы любим наш продукт, но у нас крайне ограничены ресурсы (2-4 часа в неделю для меня), и поскольку проект open-source, мы не можем позволить себе отдельную QA роль.

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

Почему я делюсь этим?

Хотя Clare была главным двигателем этого подхода в нашем сотрудничестве, я начал применять его вне нашей совместной работы. Некоторые коллеги спрашивали меня об этом, поэтому я подумал, что будет полезно поделиться с более широкой аудиторией. Надеюсь, вы найдете это как максимум нужным для вашей среды, а как минимум - у вас появятся новые идеи.

Я считаю, что наша работа как программистов — работать умнее. Когда мне приходится вручную тестировать плагин, я не чувствую себя умным: мне нужно следовать набору действий точно, сложно сосредоточиться, я нервничаю, и в целом опыт этот неприятен. Наверное, потому что я не QA инженер, и у меня нет нужного мышления.

Поэтому мы попробовали использовать нотацию коммитов, чтобы определить релизы, где можно уменьшить — или даже пропустить — ручное тестирование.

Разработка нотации

Я знаком с Conventional Commits, которые мне нравятся своей ясностью и простотой. Там всего два поля: <type>: <description>. Например: refactor: rename variables. Но там нет никакой нотации риска. Насколько я уверен, что этот коммит может что-то сломать? Это просто переименование переменных в три строки, сделанное автоматическим инструментом? Есть ли unit тест, который это покрывает? Или мне нужно ручное тестирование в beta-среде? Что, если я не знаю полного scope этого изменения?

Нотация коммитов Arlo (ACN) решает это с помощью поля риска: <risk> <type + visibility> <message>. Например: ^ r rename variables. Не очень легко читается, но предоставляет фактор риска для каждого коммита. Вот четыре уровня риска из спецификации:

Уровень риска Код Пример Значение
(Доказано) Безопасно . . r Extract method Покрывает все известные и неизвестные риски
Проверено ^ ^ r Extract method Покрывает все известные риски
Рискованно ! ! r Extract method Некоторые известные риски непокрыты
(Вероятно) Сломано @ @ r Start extracting method with no name Нет аттестации риска.

Важное здесь — уровень риска, мы взяли его из этой нотации и адаптировали в Conventional Commits как: <type>: <risk> <description>

Здесь risk — опциональное поле, похожее на ACN:

Уровень риска Код Значение
Автоматическое действие . Сделано с инструментами IDE, которым мы доверяем, не нужно тестировать (например, VSCode Abracadabra, рефакторинги JetBrains)
Покрыто unit тестами - Есть unit тест, который упадет, если код изменен неверно
Проверено вручную или интеграционно ! Изменение можно проверить только ручными действиями или деплоем
Невозможно протестировать @ Изменение нельзя протестировать никаким способом
Ломает unit тесты ** Изменение ломает хотя бы один unit тест (иногда нужно во время разработки)
Не нужно /none/ Оценка риска не имеет смысла для этого коммита

Анализ коммитов

Вот коммиты, которые я сделал с декабря 2022 по май 2025, в основном во время парных сессий с Clare в моем форке obsidian-tasks. Большинство из них позже были смержены:

  • 1539 коммитов
  • 1530 обычных коммитов
  • 1259 обычных коммитов с нотацией риска
    • 40% автоматические
    • 47% покрыты unit тестами
    • 11% проверены вручную
    • 1% ломали unit тесты
    • 1% невозможно было протестировать

Это в основном означает, что нам нужно ручное тестирование только для 1 из 10 коммитов, что сокращает ручное тестирование в 10 раз.

Ветки

Conventional Commits также описывают типы веток. Но теперь, с оценкой риска для каждого коммита, мы можем говорить и о риске ветки в целом.

Например, эта ветка:

* refactor: - remove comments
|
* feat: - better explanation and error messages from include instructions
|
* test: - check error message for includes
|
* test: - text explanation of nested includes
|
* test: - test nested include instructions
|
* feat: - teach query to parse multi-line include instructions
|
* feat: - give a meaningful error for non-existent includes
|
* test: - test layout instruction
|
* test: - test query source
|
* feat: - accept any single-line include instruction
|
* feat: - accept `include not_done` instruction
|
* test: - add failing test for include instruction
|
* docs: document includes

Смотря на все маркеры -, ее максимальный риск — «покрыто unit тестами». Это означает, что ручное тестирование измененного кода не требуется. Однако, поскольку это feature ветка, все еще нужно exploratory testing для проверки самой фичи, но ее кода.

Другой пример:

* refactor: . rename variable
|
* refactor: - remove unused part of an object
|
* refactor: . convert parameters to object
|
* refactor: - remove unused parameter and code
|
* refactor: ! use local anonymous client
|
* refactor: . move function to dedicated file
|
* refactor: reuse queryAsAnonymousUser()
|
* refactor: ! add resolver parameter
|
* refactor: ! add type assertion and generic parameter
|
* refactor: ! get property with a string value
|
* refactor: . add query parameter
|
* refactor: - add TInput generic parameter
|
* refactor: ! extract queryAsAnonymousUser()
|
* refactor: . rename variable
|
* refactor: - remove unused interface

Это чистая рефакторинговая ветка. Ей все еще нужна ручная проверка (из-за коммитов !), но преимущество в том, что мы можем точно определить, какой код нужно проверить, и извлечь тестовые сценарии соответственно.

Qulity gate для CI/CD

Поскольку риск ветки можно вывести из риска коммитов, эта нотация может также служить как quality gate для CI/CD. Пример правил:

  • Только коммиты .
    • Релиз напрямую
  • Хотя бы один коммит -
    • Исследовательское тестирование → Релиз
  • Хотя бы один коммит !
    • Ручное + интеграционное тестирование → Релиз

Мы не внедряли это как процесс в нашем проекте, потому что нас двое и это выглядело как ненужная бюрократия, так что мы просто реализуем это quality gate вручную.

Плюсы и минусы

Эта нотация коммитов требует дисциплины в создании маленьких, изолированных коммитов — что не очень распространено даже без таких нотаций. Для нас это легко из-за парного программирования и маленького размера команды. Но внедрять это в большой команде или компании было бы большим шагом. Могут быть ошибки: излишняя уверенность (отметка рискованных коммитов как безопасных) или чрезмерная осторожность (отметка безопасных коммитов как рискованных, что ведет к большей ручной работе). При текучке кадров также понадобится онбординг новичков в этот процесс. Это может также увеличить общее количество коммитов, что в некоторых культурах может восприниматься негативно.

Тем не менее, преимущества очевидны:

  • Ручного тестирования меньше — иногда вообще не нужно
  • Ручное тестирование короче — изолируя рискованные коммиты, нужно перепроверять только затронутые фичи
  • Лучшее планирование релизов — мержить более безопасные ветки сначала, оставлять рискованные на потом, и даже планировать релизы на основе риска веток

Надеюсь, этот подход будет для вас полезен =)