Инструкция, которая удалила не те двадцать шесть языков

Я поручил автоматизации собственного сайта сократить блог до четырёх языков. Через два дня выяснилось, что заодно она тихо стёрла ещё двадцать шесть языков и с главной страницы, и этого не заметил ни я, ни хотя бы один посетитель.
TL;DR
- Инструкция, нацеленная на раздел блога, применилась ко всему сайту.
- С главной страницы, страницы резюме и из всех строк навигации пропали 26 языков из 30.
- Ничего не упало и не выдало 404, поэтому два дня никто ничего не заметил.
- Решение нашлось в истории git, а не в памяти о том, как сайт выглядел раньше.
- Настоящий урок: прежде чем запускать автоматическое изменение, назови точный список файлов, которые оно затронет, и прочитай этот список до того, как что-то удалится.
Зачем вообще понадобилось меньше языков
За несколько месяцев мой сайт дорос до тридцати языков: главная страница, резюме и блог, который я обновляю чуть ли не через день. Я уже писал раньше, чем это опасно: машинный перевод достаточно гладкий, чтобы выглядеть прилично, и достаточно кривой, чтобы вас опозорить, причём на языке, который вы сами проверить не можете. Главная страница и резюме меняются редко, так что с этим риском там можно было мириться. С блогом всё иначе. Новые посты выходят часто, и я честно не могу поручиться за качество перевода свежей статьи на эстонский в день публикации.
Поэтому я решил сократить набор языков, на которые переводится блог, до четырёх, которые я действительно способен сам перепроверить: английский, русский, немецкий, чешский. Остальные остаются вне блога, пока не появится способ получше их проверять. С самой идеей всё было в порядке. Проблема была в том, как именно я её сформулировал.
Одна фраза, не тот охват
Я дал одну инструкцию: оставить в блоге четыре языка. Короткую и, как мне казалось, конкретную. А на деле она затронула сразу три разные вещи. Папки с контентом блога она сократила правильно, ровно до нужных четырёх языков. Но заодно переписала общий список языков сайта, тот самый конфиг, который определяет, какие языки вообще существуют, и удалила контент главной страницы и строки навигации для остальных двадцати шести.
Проблема в том, что «блог» и «список языков всего сайта» живут в одном и том же конфигурационном файле. В нём ничего не отделяет языки блога от языков сайта в целом. Убери язык из этого списка, и его разом теряют все разделы, которые из него читают, включая главную страницу. Моя инструкция называла раздел. А изменение, которое реально выполнилось, охватывало всё.
Вот что превратило это из простой ошибки в по-настоящему опасную ситуацию: ничего не сломалось шумно. Ни одной ошибки, ни 404, ни сбоя сборки. Сайт просто тихо перестал собирать страницы главной и резюме для двадцати шести языков, а переключатель языка перестал их предлагать. Посетитель, который раньше читал сайт на португальском, теперь молча попадал на английскую версию. «Удалено» и «никогда не существовало» выглядят абсолютно одинаково, и ни то, ни другое не выдаёт ошибку.
Я заметил это только через два дня, и то случайно, посреди работы над совершенно другой правкой, когда ссылка «Блог» в навигации повела куда-то не туда для одного из языков, которые я считал живыми. Эта единственная битая ссылка и оказалась единственной видимой ниточкой ко всей проблеме.
Что на самом деле показал diff
Настоящая ошибка тут не в неверном охвате как таковом. Она в том, что я ни разу не проверил список файлов, которые изменение собиралось затронуть, прежде чем дать ему запуститься. Я прочитал однострочное описание того, что оно должно было сделать, и решил, что это и есть описание того, что оно сделает. Не оказалось.
Исправление началось с одного вопроса: что изменилось и где. Я сравнил боевую версию сайта с последним коммитом до инструкции «сократить блог», и ответ оказался мгновенным и однозначным: общий конфиг языков, папка с контентом главной страницы и двадцать шесть файлов строк по языкам, ни один из которых даже близко не лежал в директории блога. Git хранил все эти файлы в точности такими, какими они были. Ничего на самом деле не пропало, просто поверх было задеплоено новое.
Я восстановил из истории главную страницу, резюме и строки навигации для всех тридцати языков, а папку блога оставил ровно такой урезанной, какой и хотел: четыре языка, осознанно. Остался один хвост. Ссылка «Блог» в навигации для восстановленного языка вела на языковую версию блога, которой больше не существует. Дублировать четыре поста ещё на двадцать шесть языков только ради одной ссылки не имело смысла, поэтому я настроил шаблон перенаправлять её на английский блог и на этом остановился.

Что я буду проверять иначе в следующий раз
Теперь, прежде чем дать автоматическому изменению коснуться живого многосекционного сайта, я вслух задаю один дополнительный вопрос: назови точный список файлов, которые это затронет, а не фичу, которую это должно починить. Если ответ расплывчатый, это сигнал остановиться и проверить, а не запустить и посмотреть. И перед тем как что-либо удалится, я хочу видеть перед собой реальный список файлов, а не однострочное резюме того, что инструкция якобы имела в виду. Слово, задающее охват в инструкции, «блог», «эта команда», «только фронтенд», автоматически не равно охвату изменения, которое эта инструкция запускает, и совпадают они только тогда, когда кто-то это реально проверил. Собственно, это тот же вопрос, который я задам вам: какая самая маленькая и, казалось бы, наверняка точно очерченная инструкция, которую вы недавно дали, ни разу не была проверена на то, что она реально затронула?
Нужно что-то похожее для вашего бизнеса? Посмотрите, как я могу помочь →
Заберите чек-лист «AI Audit Kickoff»
Пятнадцать вопросов, которые стоит задать про свои процессы, прежде чем тратить деньги на ИИ. Тот самый первый час, с которого я начинаю настоящий аудит, одностраничным PDF. Оставьте почту и получите его сразу, плюс изредка письмо, когда напишу что-то стоящее. Без спама, отписка в один клик.