Steven
Steven6 мин. чтения

Анатомия доведения ПО до совершенства: как код-ревью поймало то, что не смогли тесты

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

Инженерия
Процесс
Код-ревью
Релизы GeekBye
Анатомия доведения ПО до совершенства: как код-ревью поймало то, что не смогли тесты

За пару недель GeekBye выпустило девять релизов — с v2.0.0 по v2.0.11 — и эта серия рассказала историю каждого из них. Прочитайте их вместе, и всплывает паттерн интереснее любого отдельного бага: снова и снова исправление проходило каждый тест на машине разработчика, а код-ревью доказывало, что оно бы не сработало почти у всех остальных.

Этот зазор — между «у меня работает» и «работает» — и есть то место, где на самом деле живёт надёжность. Вот рабочий процесс, который его закрывает, и указатель на каждый релиз, который он произвёл.

Паттерн: зелёные тесты, неправильный ответ

Вот три самых наглядных случая из серии, потому что они делают абстрактное конкретным.

  • В исправлении захвата на нескольких мониторах (v2.0.10) первая реализация привязывала захват экрана к окну-оверлею приложения. Оно прошло тестирование — на машине разработчика с одним монитором. Ревью рассудило, где этот оверлей на самом деле живёт (на основном дисплее, всегда, если только вы физически его не перетащите) и доказало, что «исправление» разрешилось бы обратно на неправильный монитор почти у каждого реального пользователя. Правильный якорь — курсор — вышел из этого рассуждения, а не из прогона теста.
  • В релизе с резервным каналом при блокировке WebSocket (v2.0.8) ревью обнаружило, что именно тот 403, который возвращает блокирующий прокси, классифицировался как фатальная ошибка аутентификации — так что резервный канал, ради запуска которого функция и существовала, никогда не мог сработать. Функция бы отгрузилась, прошла тесты счастливого пути и не сделала ничего для своей настоящей аудитории.
  • В исправлении тайм-аута простоя (v2.0.9) первая версия ставила отметку часов «ещё жив» внутри пути кода, который часть транскриптов законно пропускает — реплики другого собеседника. Ревью поймало, что будущее изменение могло бы тихо вновь ввести ровно тот баг, который чинили, и отметку перенесли в безусловное место, с тестом, который её там удержит.

Ни один из них не был пойман запуском кода. Все они были пойманы рецензентом, рассуждающим о том, почему код работает — и находящим случай, где он не работает.

Три части ворот

Рабочий процесс за серией не замысловат. Это три привычки, применяемые без исключений.

1. Ревью рассуждает о корректности, а не просто запускает код. Проходящий тест доказывает, что код работает для случая, о котором вы подумали. Ревью — это вторая, состязательная модель системы, спрашивающая о каком случае вы не подумали? — второй монитор, корпоративный прокси, транскрипт, пропускающий ветку, клиент на одну версию позади. Шаг ревью в этой серии часто был независимым рецензентом-агентом, которому поручали опровергнуть исправление, а не благословить его. В этой рамке весь смысл: рецензент, пытающийся сломать ваше рассуждение, находит дыру, мимо которой рецензент, пытающийся его одобрить, проскальзывает взглядом.

2. Каждое исправление поведения отгружается с тестом, пришпиливающим точный сбой. Не тестом, что функция работает — тестом, что этот конкретный баг мёртв. 403 от заблокированного прокси должен провалиться в резервный канал; настоящий 403 аутентификации — нет. Часы активности должны поставить отметку на транскрипте, который пропускает атрибуцию. Эти тесты существуют, чтобы баг не смог тихо вернуться через полгода, когда кто-то будет рефакторить рядом — сбой прибит к полу.

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

Почему для AI-приложения это важнее

Есть причина, по которой эта дисциплина не подлежит обсуждению именно для инструмента вроде GeekBye. Несколько самых мерзких багов в серии были тихо-неправильными, а не громкими падениями: скриншот, который скормил ИИ неправильный монитор (v2.0.10), транскрипция, смещённая к мусорным терминам, так что «speak» вышло как имя (v2.0.11), ассистент, отвечающий в неправильном режиме без способа это увидеть (v2.0.3 + v2.0.5). Когда ваше приложение скармливает контекст модели, неправильный вход выдаёт уверенно неправильный выход и нигде никакой ошибки. Нельзя вытестировать выход из сбоев, которые не бросают исключений. Из них нужно вырассуждать — а ровно для этого и нужны ворота ревью.

Серия, по порядку

Каждый из них — самодостаточный разбор одного релиза. Прочитанные от начала до конца, они — анатомия перевода продукта из «работает» в «заслуживает доверия».

  1. Чего на самом деле стоит версия 2: 206 коммитов честных состояний — v2.0.0. Фундамент: никогда не показывай состояние, которое неправда.
  2. День, когда наше приложение задудосило само себя — v2.0.1 + v2.0.4. Стартовый затор аплоадов, растоптавший наш собственный бэкенд, и лестница живучести, которую он вынудил.
  3. Спокойное ПО: исправление мерцания и чип режима ответа — v2.0.3 + v2.0.5. Релизы без функций, покупавшие доверие по одной детали за раз.
  4. Ваше Mac-приложение забывает доступ к микрофону при каждом запуске — v2.0.6. macOS App Translocation и отгрузка диагностики до исправления.
  5. Одна CSS-переменная, пять раундов ревью и тулчейн Swift, который солгал — v2.0.7. Равномерная полупрозрачность и бинарник, сменивший размер, потому что документация разошлась со скриптом-энфорсером.
  6. Живая транскрипция, когда файрвол блокирует WebSocket — v2.0.8. Резервный канал на чистом HTTPS и 403, который спрятал бы его от него самого.
  7. Почему ваш AI-нотетейкер перестаёт записывать посреди встречи — v2.0.9. Таймер простоя, который слышал только вас, и падение, которое могло заблокировать ваш рабочий стол.
  8. Почему запись экрана захватывает не тот монитор — v2.0.10. Баг неправильного дисплея и исправление, которое прошло на одном мониторе и провалилось бы на двух.
  9. Почему AI-транскрипция ослышивается на технических терминах — v2.0.11. Смещение речи к вашему словарю — и регрессия, которая сделала хуже, прежде чем стало лучше.

Вывод

Совершенство — не состояние, которого достигают; это ворота, которые держат. Девять релизов и одни и те же три вопроса при каждом: о каком случае ты не подумал, пришпилен ли точный сбой тестом и вышла ли на самом деле настоящая подписанная сборка? Ничего из этого не гламурно. Всё это — причина, по которой GeekBye v2 ощущается спокойным. Если ты строишь ПО — AI или нет — переносимая часть не в каком-то одном исправлении. Она в привычке относиться к зелёному набору тестов как к началу спора, а не его концу.

Каждый релиз выше доступен через автообновление. О продукте, в который складываются эти исправления, смотри что нового в GeekBye v2.

Похожие статьи

Тишина была несущей
Steven
Steven7 мин. чтения

Тишина была несущей

Два последних релиза GeekBye v1 — об одной и той же неудобной правде: транскрипция в реальном времени по настоящей сети не бесстратна, и честный ход — перестать притворяться, что это так. v1.8.20 хранил копию каждого фрагмента звука на диске, прежде чем отбросить его при переподключении, и начал вслух отмечать пропуски в транскрипте. v1.9.0 перестал отправлять тишину, чтобы сэкономить трафик — и обнаружил, что тишина была ровно тем сигналом, по которому транскрайбер понимал, что предложение закончилось. Два релиза о цене выбрасывания вещей.

Инженерия
Аудио
Надёжность
Три глагола, что держат Web Audio живым
Steven
Steven8 мин. чтения

Три глагола, что держат Web Audio живым

Два точечных релиза GeekBye, разделённые двумя месяцами и в двух разных файлах, преподали нашему аудиокоду один и тот же урок с противоположных концов: перестань обращаться с браузерным AudioContext как с одноразовым. Один релиз научился делать resume() контексту, который macOS тихо приостановил посреди записи; другой научился suspend() вместо close(), чтобы идущие подряд сессии перестали врезаться в навязанный Chromium потолок примерно в шесть контекстов. Resume, suspend, close — вот и весь сюжет.

Инженерия
Аудио
Десктоп
Отличить звонок от открытого приложения
Steven
Steven8 мин. чтения

Отличить звонок от открытого приложения

GeekBye умеет заметить, что ты присоединился к видеовстрече, и предложить её записать. Обнаружение оказывается лёгкой половиной — нативный Swift-бинарник читает заголовки окон каждые десять секунд. Трудная половина — точность: не срабатывать, когда Zoom просто открыт, не предлагать записать встречу, которую ты уже записываешь, и не заглушать микрофон в звонке, в котором ты на самом деле сидишь. Три релиза, и каждый из них — предохранитель, которому пришлось научиться не побеждать самого себя.

Инженерия
macOS
Десктоп