Rain Lag

Привычка предварительного просмотра коммита: как мысленные «dry-run» ловят баги раньше CI

Узнайте, как мысленно прогонять свои коммиты, использовать git diff как связный рассказ и сочетать аккуратную ментальную симуляцию с быстрым CI, чтобы раньше ловить баги и отправлять более чистый код.

Введение

Большинство разработчиков относятся к CI как к основному детектору багов: запушил код, подождал пайплайн, поправил то, что упало. Это работает — пока не перестаёт. Нестабильные тесты, медленные пайплайны и тонкие логические ошибки легко проскальзывают, а сломанный main очень быстро становится проблемой всей команды.

Есть простая привычка, которая радикально меняет эту картину: привычка предварительного просмотра коммита.

Вместо того чтобы полагаться на CI как на индикатор безопасности изменений, вы мысленно прогоняете каждый коммит перед пушем. Вы проходите по diff построчно, симулируете выполнение кода и задаёте себе вопрос: «Что это может сломать?»

Речь не о паранойе, а об осознанности. Когда вы относитесь к каждому коммиту как к чему-то, что вы должны суметь обосновать и мысленно исполнить, ваш код становится чище, прогоны CI — предсказуемее, а доверие команды к основной ветке — выше.


Что такое привычка предварительного просмотра коммита?

Привычка предварительного просмотра коммита — это простая, повторяемая практика:

  1. Сделайте небольшое, сфокусированное изменение.
  2. Просмотрите diff так, будто это чужой код.
  3. Мысленно симулируйте выполнение нового или изменённого кода.
  4. Для каждого фрагмента спросите: что это может сломать?
  5. Доработайте, пока diff не станет чистым и вы не перестанете находить проблемы.
  6. Только после этого коммитьте и пушьте, используя CI для подтверждения, а не для обнаружения проблем.

Вы не просто «пробегаетесь взглядом» по изменениям. Вы делаете ментальный dry-run коммита: представляете реальные входные данные, реальные пути исполнения, существующие зависимости и странные граничные случаи.

Эта привычка превращает ваш git diff в мощный «quality gate», который живёт в вашей голове, а не только в CI-пайплайне.


Мысленно прогоняйте код построчно

Суть привычки — намеренная ментальная симуляция.

Смотря на diff, не просто читайте его — запускайте его у себя в голове:

  • «Какие значения могут прийти на эту строку?»
  • «Если это условие ложно, куда мы пойдём дальше?»
  • «Что будет для первого элемента? Для последнего? Для пустого списка?»
  • «Что если этот API вернёт null / бросит исключение / будет долго отвечать?»

Сфокусируйтесь на типичных паттернах багов

Во время ментального прогона целенаправленно ищите:

  • Логические ошибки
    Не перепутаны ли условия? Не спутаны ли AND/OR? Не переиспользуются ли переменные неправильно?

  • Ошибки на единицу (off-by-one)
    Циклы с индексацией с 0 против 1, включительные и исключительные границы, срезы массивов — это классические случаи, которые отлично ловятся ментальной симуляцией.

  • Скрытые допущения
    Не предполагаете ли вы, что вход не пустой, список отсортирован, поля не равны null, а внешний API стабилен? Что происходит, когда эти предположения нарушаются?

  • Изменения состояния
    Не мутируете ли вы общие объекты, глобальное состояние или кэши так, что это может дать побочный эффект в других местах?

Простой пример

Предположим, ваш diff выглядит так:

- for (int i = 0; i < items.Count; i++) { - Process(items[i]); - } + for (int i = 1; i <= items.Count; i++) { + Process(items[i]); + }

Быстрый взгляд может сказать: «Цикл всё ещё крутится, ничего страшного». Мысленный dry-run говорит другое:

  • На первой итерации i = 1items[0] пропускается.
  • На последней итерации i = items.Countitems[i] даёт ошибку выхода за границы.

Быстрый прогон CI может поймать это, если у вас хорошие тесты. Ваш ментальный dry-run ловит это до того, как вы вообще сделали коммит.


Смотрите на diff как на рассказ, а не просто на патч

Один из самых полезных сдвигов в мышлении — читать diff как историю:

  • Кто главные персонажи? (функции, модули, внешние системы)
  • Что изменилось в их поведении?
  • Какие другие части системы зависят от этого поведения?

Читайте diff так, будто вы делаете code review чужого коммита. Эта дистанция помогает легче оспаривать допущения:

  • «Почему мы убрали эту проверку на null?»
  • «Раньше функция возвращала пустой список, теперь может вернуть null. Кто её вызывает?»
  • «Мы поменяли таймаут с 3 секунд на 30 — как это скажется на опыте пользователя?»

Задавайте «Что может сломаться?» при каждом изменении:

  • На границах функций: типы возвращаемых значений, обработка ошибок, nullability.
  • На границах данных: парсинг, сериализация, изменения схемы.
  • На границах поведения: таймауты, ретраи, конкурентность, кэширование.

В конце diff вы должны суметь пересказать его «сюжет» в одном-двух предложениях:

Этот коммит меняет логин пользователя так, чтобы логировать дополнительные метрики, не затрагивая логику аутентификации и обработку ошибок.

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


Избегайте «ой»-коммитов: доводите изменения локально

Распространённый антипаттерн: закоммитил, запушил, CI упал, дальше идёт серия коммитов вида «oops», «fix build», «ещё раз починил».

Это симптом того, что вы используете CI как первую линию защиты, а не как последнюю.

Вместо этого:

  1. Сделайте ментальный dry-run.
  2. Подправьте код так, чтобы diff выглядел намеренным и цельным.
  3. Запустите тесты локально (даже небольшой, целевой набор, если полный тяжёлый).
  4. И только потом коммитьте и пушьте.

Плюсы такого подхода:

  • История коммитов рассказывает чистую историю, а не документирует ваш метод тыка.
  • Code review становится быстрее и приятнее.
  • CI-инфраструктура используется для валидации, а не как «редактор с юнит-тестами».

Цель — не безошибочность. Цель в том, чтобы большинство падений CI вас удивляло — и заставляло улучшать свою ментальную модель.


CI как подтверждение, а не как открытие

Когда вы сочетаете привычку предварительного просмотра коммита с CI, характер взаимодействия меняется:

  • Ваш ментальный dry-run — первый фильтр.
  • Ваши локальные тесты — второй фильтр.
  • Ваш CI-пайплайн — третий фильтр: независимое подтверждение.

Такое мышление создаёт мощный цикл обратной связи:

  • CI чаще зелёный, потому что вы уже поймали очевидные баги.
  • Когда CI падает, вы учитесь: ваша ментальная модель чего-то не увидела. Вы её дорабатываете.
  • Со временем ваш внутренний «симулятор» всё точнее предсказывает реальное поведение.

Практическое правило:

Относитесь к зелёному CI как к «я правильно предсказал поведение своего кода», а не просто «похоже, всё работает».

Этот лёгкий сдвиг стимулирует заботиться об понимании системы, а не только о прохождении тестов.


Не мёрджите, пока CI красный

Здесь есть и культурный аспект: целостность сборки.

Введи́те и соблюдайте простое правило:

Никаких merge, пока CI красный. Никогда.

Это подкрепляет:

  • Идею, что зелёная сборка + ментальный preview = определение готовности.
  • Уважение к времени коллег: никто не должен разбираться с вашим сломанным main.
  • То, что красная сборка — исключение, которое надо чинить сразу, а не фоновый шум.

Если команда считает красный билд нормой, мозг перестаёт доверять CI, и привычка предварительного просмотра теряет один из ключевых источников обратной связи.


Держите тесты быстрыми и надёжными

Привычка предварительного просмотра коммита лучше всего работает вместе с быстрыми и надёжными тестами. Иначе возникает соблазн игнорировать CI или относиться к падениям равнодушно.

Стремитесь к тому, чтобы:

  • Обратная связь была быстрой: юнит- и интеграционные тесты должны выполняться за минуты, а не часы.
  • Сигнал был качественным: минимум флаки-тестов, которые падают случайным образом.
  • Ответственность была прозрачной: при падении теста должно быть понятно, где искать причину и кто за это отвечает.

Когда тесты быстрые и надёжные, ваш ежедневный ритм выглядит так:

  1. Реализовать изменение.
  2. Мысленно прогнать и просмотреть diff.
  3. Запустить локальные тесты (или целевые наборы).
  4. Запушить и дать CI подтвердить.

Со временем это становится автоматизмом — привычка уходит в «мышечную память». Ваш мозг и ваш CI начинают работать не наперекор, а в паре.


Как закрепить привычку

Чтобы выработать привычку предварительного просмотра коммита:

  • Начните с малого. Выберите один коммит сегодня и осознанно сделайте его ментальный dry-run перед пушем.
  • Используйте чек-листы. Перед коммитом быстро пробегитесь: логические ошибки? off-by-one? null? зависимости?
  • Давайте себе жёсткий лимит по времени. Тратьте 1–3 минуты на коммит для ментальной симуляции. Это дешёвая страховка.
  • Разбирайте падения CI. Когда CI что-то ловит, спрашивайте: «Мог ли я увидеть это в diff?» Если да — добавьте новый пункт в свой ментальный чек-лист.

С повторением мозг начинает выполнять эти симуляции автоматически. Цена привычки падает, а польза накапливается.


Заключение

Привычка предварительного просмотра коммита — не замена тестам или CI. Это недостающий промежуточный слой: осознанный ментальный проход, который превращает ваш git diff в историю, которую вы понимаете и можете защитить.

Мысленно прогоняя каждый коммит, относась к diff как к рассказу, избегая «ой»-коммитов, используя CI как подтверждение и настаивая на зелёных сборках, вы:

  • Раньше ловите логические баги и ошибки на единицу.
  • Отправляете более чистые и намеренные коммиты.
  • Строите больше доверия к кодовой базе и командному процессу.

Вы и так смотрите на свои diff. Вопрос в том, пролистываете ли вы их или симулируете.

В следующий раз, когда потянетесь к git commit, на секунду остановитесь и запустите код у себя в голове. Пусть CI просто подтвердит то, что вы уже знаете: это изменение готово.

Привычка предварительного просмотра коммита: как мысленные «dry-run» ловят баги раньше CI | Rain Lag