Каждый разработчик мечтает о том, чтобы его код работал идеально. Но реальность такова, что любой проект — это поле, усеянное невидимыми минами в виде багов. Иногда эти мины оказываются настолько изощрёнными, что их поиск превращается в настоящий детектив. Сегодня расскажем историю именно о такой охоте за ошибкой, от которой хочется одновременно смеяться и плакать.
📌 Начало: внезапный сбой в Google Docs
Однажды утром команда Google Docs столкнулась со странной ситуацией: количество ошибок в приложении резко возросло, хотя явных жалоб от пользователей не поступало. Ошибка была критической и странной — она происходила только в Chrome, только начиная с определённой версии браузера и не была привязана к каким-либо изменениям в самом Google Docs.
Команде предстояло ответить на вопросы:
- 🧐 Почему ошибка проявляется так выборочно?
- 🤔 Почему её почти невозможно воспроизвести?
- 🔍 Почему стандартные методы поиска не работают?
⚙️ Технические детали: от простых догадок к безумию
Автор статьи, бывший сотрудник команды Google Docs Джейкоб Войтко, решил разобраться лично. Его первая мысль была о проблемах компиляции JavaScript-кода с помощью Closure Compiler (популярного инструмента, используемого Google Docs). Чтобы исключить эту версию, он начал тестировать проблему на некомпилированной версии кода — и всё равно получил ту же ошибку. Значит, дело не в компиляторе.
🔥 Первый успех: воспроизведение ошибки
Ошибка была непостоянной (недетерминированной), что усложняло задачу в десятки раз. Методом многочисленных экспериментов, Джейкоб обнаружил, что ошибка проявляется, если многократно изменять стиль большого текста (например, включать и выключать жирное начертание).
Тут важный нюанс: у текста в разных стилях менялась ширина строк, что могло косвенно влиять на внутреннюю логику рендера страниц. Это натолкнуло на мысль, что дело связано с подсчётами размеров и кешированием значений в специальном движке Google Docs, который отрисовывал всё на странице через абсолютное позиционирование элементов, а не через обычный HTML.
🚧 Кошмар отладки: логика и кеширование
Код Google Docs тех времён был невероятно сложным — каждое изменение приводило к перерасчёту всего документа. В результате любые ошибки в промежуточных данных постепенно накапливались и приводили к неожиданным завершением программы.
Проблема оказалась в вычислениях, связанных с подсчётом ширины элементов, где в коде была функция Math.abs(). И вот тут началась настоящая магия: оказалось, что именно эта функция иногда возвращала отрицательные значения (!). Если вы знаете JavaScript, вы понимаете, насколько это невозможно — ведь суть Math.abs() — всегда возвращать положительное значение.
🎩 Волшебство или баг браузера?
Команда долго не могла поверить в реальность происходящего. Была вызвана техлид, известная своей способностью буквально компилировать JavaScript-код «в голове». Даже она сначала не поверила, но спустя несколько минут анализа кода признала — Math.abs() реально возвращает отрицательные числа в Chrome.
Оказалось, что проблема была не в Google Docs, а в движке V8, на котором работает JavaScript в Chrome. Во время оптимизации разработчики V8 допустили невероятную ошибку: на супер-оптимизированном пути исполнения кода они случайно превратили функцию Math.abs() в функцию, возвращающую исходное значение, вместо абсолютного!
🚑 Как проблему решили?
Баг уже был исправлен в самом V8, но версия браузера с ошибкой ещё широко использовалась пользователями. Поэтому команда добавила временный костыль — ручную проверку версии браузера и альтернативную реализацию функции прямо в коде Google Docs. А также огромный комментарий в коде с объяснением и ссылками, чтобы в будущем этот костыль можно было спокойно убрать.
🤯 Уроки из невероятной истории
- 🎲 Баги бывают совершенно абсурдными. Иногда логика не поможет, и нужно проверять даже невозможное.
- 👥 Не стесняйтесь просить помощи коллег. Джейкоб справился лишь благодаря опыту и взгляду других сотрудников.
- 📚 Документируйте странные решения. Ваше будущее «я» скажет спасибо, когда наткнётся на костыль в коде.
Лично для меня эта история показывает главное — никакой баг не бывает слишком безумным. В мире программирования всё возможно, и даже самая проверенная функция может внезапно предать.
Такой баг — это своеобразный вызов судьбы, напоминающий, что программирование — искусство не только логики, но и творческого подхода к решению непредвиденных ситуаций.
📌 Источник: