
Спокойный софт: как мы убили мигающий переключатель и научили чат сообщать, в каком он режиме
Два небольших релиза GeekBye без громких фич — просто переключатель в настройках перестал мигать, а чат-ассистент наконец сообщает, ответил ли он в режиме встречи или в режиме кодинга. Вот сколько на самом деле стоит «спокойный софт» — по одной детали за раз.
Не каждый релиз — это история о битве. Иногда это просто список мелких, почти невидимых вещей, которые тихо работали неправильно — из тех, что ничего не ломают, но заставляют приложение казаться чуть менее надёжным, чуть более дёрганым, чуть-чуть чужим. GeekBye v2.0.3 и v2.0.5 были именно такими. Ни одной новой фичи. Просто спокойствие.
«Спокойный софт» звучит как настроение. На самом деле это груда конкретных решений. Вот три из них.
Переключатель, который не мог определиться
Был один переключатель в настройках — тот, что управляет восстановлением аудио, — и он мигал, когда вы на него нажимали. Включаешь его, и на долю секунды он показывает включено, потом отскакивает обратно на выключено, а потом успокаивается. Крошечное визуальное подёргивание, но глаз его ловит, и оно читается как приложение само не уверено, что делает.
Причина — классическая гонка интерфейса под названием оптимистичное обновление. Когда вы нажимаете на переключатель, у приложения есть два варианта: дождаться, пока настройка действительно сохранится, и только потом обновить тумблер (правильно, но ощущается как задержка) или переключить тумблер сразу, а сохранение выполнить в фоне (ощущается мгновенным). GeekBye делал второе — переключал сразу, — но ещё перечитывал сохранённое значение, когда оно возвращалось. Так что последовательность была такой: вы нажимаете, тумблер оптимистично переключается на «включено», реальное сохранённое значение приходит на такт позже, и на один кадр эти два значения расходятся, и тумблер заметно отскакивает.
Исправление в том, чтобы оптимистичное значение и подтверждённое значение согласованно совпадали — тумблер фиксируется в выбранном вами состоянии и перестаёт сомневаться в себе, когда сохранение подтверждается. Заодно v2.0.3 выполнил неброский проход по текстам: описание восстановления аудио было подрезано, чтобы выровняться с соседними строками, а формулировки настроек стали человечнее. Ничто из этого не фича. Но всё это и есть разница между панелью настроек, которая ощущается сконструированной, и той, что ощущается выхоленной.
Тур, который не хотел уходить
Туры для новых пользователей полезны ровно один раз. Проблема именно в этой одноразовости: после того как вы его увидели, обучающий оверлей, который нельзя закрыть, превращается в мусор, сигнализирующий это приложение всё ещё считает вас новичком. v2.0.3 исправил оба конца: продуктовый тур теперь можно скрыть, а если он вам действительно нужен обратно, есть кнопка Повторить тур. Показывать, когда это помогает, уходить с дороги, когда нет, и давать пользователю вызывать его на своих условиях. Уважение к тому, что пользователь больше не новичок, — это своя маленькая форма спокойствия.
Ассистент, который не хотел говорить, как он думает
Вот это было по-настоящему важно, и оно связано с более глубокой проблемой, которую мы преследовали.
Ассистент GeekBye отвечает по-разному в зависимости от контекста. Во встрече на вопрос «что ты об этом думаешь?» должен приходить разговорный ответ, учитывающий контекст встречи. Во время сессии кодинга те же слова должны получать технический ответ. Поэтому бэкенд прогоняет вопрос через нужную рамку — назовём её режимом встречи или режимом кодинга, — и эта рамка действительно меняет ответ, который вы получаете.
Беда в том, что приложение никогда не сообщало, какой режим ответил. Поэтому когда ассистент выдавал ответ с привкусом кода на разговорный вопрос — или отвечал на вопрос по коду так, будто вы просто болтаете, — казалось, что ИИ просто ошибается. Он не ошибался; он был в другом режиме, а у вас не было возможности это увидеть. Скрытое состояние заставляло правильное поведение выглядеть сломанным. (Сама логика режимов — это работа посерьёзнее: оркестратор, который решает, как отвечать на некодинговые вопросы во время сессии кодинга, — но всё это бесполезно для вас, если вы не можете увидеть принятое им решение.)
v2.0.5 добавил в чат плашку режима только для чтения: небольшую метку, показывающую, ответил ли ассистент в режиме встречи или в режиме кодинга. «Только для чтения» — в этом весь смысл: это не элемент управления, который вы задаёте, это окно в решение, которое система уже приняла. Вы перестаёте гадать, почему ответ ощущается странным; вы видите рамку, из которой он пришёл.
Деталь, которая делает плашку честной
Вот инженерное решение, которое стоит передать дальше, потому что это как раз то, что отличает прикрученный сбоку индикатор от того, которому можно доверять.
Информация о режиме приходит с бэкенда как часть потокового ответа — небольшой кадр mode в потоке server-sent events. Но более старый клиент, появившийся до этой фичи, не знал бы, что такое кадр mode; в лучшем случае он его игнорирует, в худшем — отрисовывает что-то искажённое. Поэтому клиент объявляет о своей возможности: он отправляет заголовок запроса, говорящий я умею показывать плашку режима, и бэкенд отправляет кадр mode только тем клиентам, которые его прислали. Старые клиенты никогда не получают сигнал, который не могут обработать; новые клиенты получают ровно тот кадр, который запросили.
Это рукопожатие в один заголовок, и в нём вся разница между «мы добавили фичу» и «мы добавили фичу, не сломав никого, кто ещё не обновился». Тот же проход по коду подтянул и остальное поведение: плашка очищается при сбросе и при смене контекста разговора (устаревшая метка режима — это своя маленькая ложь), и показывается только в чате, где ей и место.
Чему нас научили два релиза «без фич»
- Дрожание — это сигнал доверия. Мигающий переключатель, отскакивающий тумблер, метка, задержавшаяся на кадр дольше нужного — ни одно из этого не баг в смысле краша, но каждое шепчет это приложение не вполне себя контролирует. Спокойствие — это отсутствие этого шёпота, и вы зарабатываете его по одной гонке за раз.
- Скрытый режим заставляет правильное поведение выглядеть багом. Ассистент делал правильную вещь и получал за это претензии — исключительно потому, что пользователь не видел рамку. Когда ваша система принимает невидимое решение, которое меняет вывод, покажите это решение — плашка только для чтения нередко и есть всё исправление целиком.
- Новые фичи должны быть невидимы для клиентов, которые не могут ими воспользоваться. Рукопожатие через заголовок возможностей означает, что сигнал режима доходит только до клиентов, способных его отрисовать. Обратная совместимость — это не проверка версии, прикрученная позже; это клиент, говорящий, что он понимает, и сервер, уважающий этот ответ.
Это те релизы, о которых никто не пишет заголовков в чейнджлоге, и именно они во многом объясняют, почему GeekBye v2 ощущается так, как ощущается. О релизе, на котором было построено это спокойствие, читайте в статье чего на самом деле стоит версия два (v2.0.0). О работе над надёжностью рядом с ним — день, когда наше приложение задидосило само себя (v2.0.1) и почему ваш ИИ для заметок перестаёт записывать посреди встречи (v2.0.9).