В статье «Публичное описание как проверка инженерного решения» я писал о том, что для утверждения «решение работает» нужен наблюдаемый факт. Но есть ещё один вопрос: когда определить, какой именно факт будет достаточным?
Если придумывать проверку после реализации, ответ легко начинает зависеть от того, что уже получилось.
Разработчик написал код, увидел его устройство и затем выбирает удобный способ показать, что задача выполнена. Проверка перестаёт быть независимым критерием и частично превращается в подтверждение собственного решения.
Поэтому реализацию и проверку полезно разделять ещё до первого изменения кода.
Готовность не должна определяться реализацией
У задачи обычно есть ожидаемый результат. После реализации появляется конкретный способ его получить.
Это разные вещи.
Допустим, нужно изменить конфигурацию сервиса. После работы легко сказать: новый параметр читается, тест функции разбора конфигурации проходит, значит задача готова.
Но исходная задача могла требовать большего. Значение должно не только читаться, но и фактически влиять на работу сервиса. Старые конфигурации должны продолжать работать. Некорректное значение должно отклоняться. Другие параметры не должны изменить поведение.
Если эти условия формулируются только после написания кода, появляется пространство для подгонки понятия «готово» под реализованный вариант.
Это обычная форма предвзятости подтверждения: после выбора решения проще искать факты в его пользу, чем условия, при которых оно окажется неправильным.
Проблема не решается обещанием «потом хорошо протестировать». Нужно заранее определить, что будет считаться доказательством результата.
Сначала результат, потом способ его достижения
До реализации полезно зафиксировать три вещи:
что должно измениться
→ что не должно измениться
→ чем это можно доказать
Здесь ещё не нужно знать устройство будущего кода.
Например, для изменения конфигурации можно заранее определить:
новое значение меняет требуемое поведение
конфигурация без нового параметра
сохраняет прежнее поведение
некорректное значение отклоняется
остальная конфигурация работает как раньше
После этого можно выбирать реализацию.
Возможно, потребуется изменить схему конфигурации. Возможно, добавить преобразование значения или передать его в другой компонент. Это уже техническое решение.
Критерий готовности от выбранного устройства кода зависеть не должен.
Разделение не требует разных людей или команд. Один инженер может сформулировать критерии, реализовать изменение и проверить его. Важна другая граница: критерии появились до того, как результат реализации стал известен.
Три уровня проверки отвечают на разные вопросы
Одного вида проверки обычно недостаточно.
Первый уровень — критерии приёмки. Они описывают наблюдаемое поведение системы и границы изменения. Это контракт задачи: что должно стать истинным после реализации.
Второй уровень — автоматические проверки. Они превращают часть критериев в воспроизводимое доказательство. Тест можно повторить после следующего изменения и проверить, что ранее подтверждённое свойство сохранилось.
Третий уровень — ручной сценарий. Он нужен там, где важно увидеть работу нескольких частей вместе или проверить реальное окружение. Для изменения конфигурации это может быть запуск сервиса с новым значением и проверка фактического поведения.
Эти уровни не заменяют друг друга.
Тест функции разбора конфигурации может доказать, что значение прочитано правильно, но не доказать, что сервис его использует. Ручной запуск с одним новым значением покажет основной сценарий, но ничего не скажет о совместимости со старой конфигурацией.
Поэтому хороший план проверки строится не от доступных тестов, а от свойств, которые нужно подтвердить.
Проверка должна уметь опровергнуть решение
Полезный критерий качества проверки — способна ли она показать, что реализация неправильная.
Если заранее известно, что любая реализация почти гарантированно пройдёт выбранную проверку, доказательство слабое.
Например, после добавления нового параметра можно проверить только успешный запуск с этим параметром. Такая проверка подтвердит основной сценарий, но пропустит несколько классов ошибок: значение может игнорироваться, старые конфигурации могут перестать работать, а некорректные значения — приниматься без ошибки.
Проверка становится сильнее, когда включает не только ожидаемый положительный результат, но и границы изменения.
Поэтому вопрос «что не должно измениться?» не менее важен, чем «что должно заработать?».
Это особенно полезно для небольших изменений. У них часто есть очевидный положительный сценарий и менее заметный риск регрессии в соседнем поведении.
Code review начинается не с diff
При ревью легко начать с реализации: открыть diff, посмотреть структуру кода и решить, выглядит ли изменение разумным.
Но тогда проверка снова строится вокруг уже выбранного решения.
Полезнее сначала восстановить контракт задачи: что должно измениться, что должно остаться прежним и какие доказательства автор считает достаточными.
После этого diff отвечает только на один из вопросов: как получен требуемый результат.
Тесты и другие проверки отвечают на другой: откуда известно, что результат действительно получен.
Так ревью меньше зависит от убедительности самого решения. Хорошо написанный код ещё не доказывает выполнение задачи, а необычная реализация не обязательно неправильна, если она удовлетворяет зафиксированному контракту и не нарушает ограничения.
Для ИИ-агентов эта граница ещё важнее
ИИ-агенту легко поручить:
реализуй изменение и проверь, что всё работает
Но в таком задании один исполнитель одновременно выбирает решение и определяет достаточную проверку уже после своих изменений.
Агент может написать код, добавить тест на собственную реализацию, запустить его и получить полностью согласованный, но слишком узкий набор доказательств.
Поэтому для агентной работы полезнее другой порядок:
задача
→ критерии приёмки
→ план проверки
→ реализация
→ выполнение заранее определённых проверок
→ сопоставление каждого критерия с результатом
Это не означает, что план проверки нельзя менять.
Во время реализации может обнаружиться новое ограничение или ошибочное исходное предположение. Тогда критерии действительно нужно пересмотреть. Но такое изменение должно быть отдельным решением, а не незаметным упрощением проверки после того, как первоначальный вариант оказался неудобным.
Та же схема помогает при передаче результата другому агенту или человеку на ревью. Проверяющему не приходится угадывать намерение автора по diff: ожидаемый результат и способы его подтверждения уже зафиксированы.
Простой шаблон
Перед реализацией небольшой инженерной задачи достаточно записать:
Что должно измениться:
<наблюдаемый результат>
Что не должно измениться:
<существенные инварианты и обратная совместимость>
Чем это доказать:
<автоматические проверки>
<ручной сценарий, если он нужен>
После реализации остаётся сравнить фактический результат с этим контрактом.
Если решение приходится защищать изменением самого критерия готовности, это повод сначала пересмотреть критерий или реализацию.
Проверка полезна именно тогда, когда она существует отдельно от решения, которое должна проверять.
