Добавить в корзинуПозвонить
Найти в Дзене

Почему старый код иногда страшнее нового бага

Новый баг — это неприятно. Ты его видишь, ругаешься, открываешь логи, пьёшь кофе, ищешь причину и в какой-то момент понимаешь: “Ага, вот он, гадёныш”. Старый код — другое дело. Старый код не нападает сразу. Он просто лежит в проекте годами. Тихо. Спокойно. Делает вид, что он часть системы. Иногда даже работает. И вот однажды тебе говорят: “Там нужно просто немного поправить старый модуль.” В этот момент опытный программист не задаёт вопрос “что именно поправить?” Он задаёт вопрос: “А завещание уже писать?” У нового бага есть одно хорошее качество: он свежий. Ты примерно знаешь, после чего он появился. Вчера работало, сегодня сломалось. Значит, где-то между “вчера” и “сегодня” кто-то сделал что-то интересное. Обычно можно открыть последние изменения и начать расследование. Кто менял?
Что менял?
Зачем менял?
Почему тесты молчали?
Почему опять в пятницу? Новый баг — это как свежий след на снегу. Неприятно, но понятно, куда идти. А старый код — это как подвал в доме, куда никто не спускал
Оглавление

Новый баг — это неприятно.

Ты его видишь, ругаешься, открываешь логи, пьёшь кофе, ищешь причину и в какой-то момент понимаешь: “Ага, вот он, гадёныш”.

Старый код — другое дело.

Старый код не нападает сразу. Он просто лежит в проекте годами. Тихо. Спокойно. Делает вид, что он часть системы. Иногда даже работает.

И вот однажды тебе говорят:

“Там нужно просто немного поправить старый модуль.”

В этот момент опытный программист не задаёт вопрос “что именно поправить?”

Он задаёт вопрос:

“А завещание уже писать?”

Новый баг хотя бы честный

У нового бага есть одно хорошее качество: он свежий.

Ты примерно знаешь, после чего он появился. Вчера работало, сегодня сломалось. Значит, где-то между “вчера” и “сегодня” кто-то сделал что-то интересное.

Обычно можно открыть последние изменения и начать расследование.

Кто менял?
Что менял?
Зачем менял?
Почему тесты молчали?
Почему опять в пятницу?

Новый баг — это как свежий след на снегу. Неприятно, но понятно, куда идти.

А старый код — это как подвал в доме, куда никто не спускался с 2016 года. Там может быть что угодно: старая проводка, коробки без подписей, странный запах и надпись на стене:

“Не трогать. Работает.”

И самое страшное — оно действительно работает.

Старый код держится на магии и страхе

В любом большом проекте есть места, которые никто не любит открывать.

Они обычно называются как-то невинно:

utils
common
legacy
old
new2
final_final_fixed

Если вы не программист, поясню: когда файл называется final_final_fixed, это почти никогда не означает, что он финальный, исправленный и хороший.

Это означает, что где-то рядом плакал человек.

Старый код часто выглядит так, будто его писали ночью, под давлением, с мыслью:

“Сейчас главное, чтобы заработало. Потом нормально переделаем.”

И вот прошло шесть лет.

“Потом” так и не наступило.

Зато код стал важной частью системы.

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

Может быть, на логике.

Может быть, на удаче.

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

Самая опасная фраза: “оно же давно работает”

Когда программист слышит:

“Да оно же давно работает”

он не успокаивается.

Он напрягается.

Потому что “давно работает” в IT может означать две разные вещи.

Первый вариант:

код хороший, проверенный временем, надёжный.

Второй вариант:

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

И отличить первое от второго иногда можно только после аварии.

Это как старый лифт в доме. Он вроде ездит. Каждый день. Люди привыкли. Но когда он начинает странно скрипеть, никто не говорит:

“Прекрасно, он же давно работает.”

Все говорят:

“Может, пешком?”

Со старым кодом так же.

Он может годами выполнять свою задачу, но при этом внутри быть таким хрупким, что одна маленькая правка превращается в квест:

“Найди, почему после изменения текста кнопки, перестала отправляться почта.”

Старый код знает то, чего не знает документация

Документация обычно говорит:

“Этот модуль отвечает за обработку заявок.”

Старый код говорит:

“Я отвечаю за обработку заявок, отправку писем, пересчёт скидок, генерацию отчёта, проверку прав доступа и маленькую секретную проверку, без которой всё падает, но никто не знает почему.”

И вот программист открывает файл, чтобы добавить одну проверку.

А там функция на 600 строк.

Для обычного человека 600 строк — это просто много текста.

Для программиста функция на 600 строк — это как встретить медведя в коридоре офиса. Вроде теоретически можно договориться, но лучше не делать резких движений.

Ты начинаешь читать.

Первые 100 строк — подготовка данных.
Следующие 100 — проверки.
Потом внезапно работа с датами.
Потом отправка уведомления.
Потом комментарий:

“Костыль для старого клиента. Не удалять.”

И всё.

Ты уже не разработчик.

Ты археолог.

Комментарии в старом коде — отдельный жанр литературы

Есть обычные комментарии.

Например:

“Проверяем, что пользователь существует.”

Нормально. Понятно.

Есть бесполезные комментарии:

“Увеличиваем счётчик.”

Спасибо. Мы видим. Он увеличивается.

А есть комментарии из старого кода, которые надо читать голосом ведущего мистической передачи:

“Временно.”

Дата: 2018 год.

Или:

“Не трогать.”

Без объяснений.

Или:

“Так надо.”

Кому надо? Почему надо? Что будет, если не надо?

Неизвестно.

Иногда комментарий выглядит так:

“TODO: переделать нормально.”

И ты смотришь на дату.

2015 год.

Сидишь, пьёшь кофе и думаешь:
“Интересно, этот человек ещё верит в светлое будущее?”

Самый страшный комментарий:

“Работает, но не знаю почему.”

Потому что это уже не комментарий. Это признание.

Новый баг можно победить. Старый код надо уважать

С новым багом всё понятно: нашёл, исправил, проверил.

Со старым кодом нельзя так грубо.

Старый код похож на старую проводку в квартире. Можно, конечно, сказать:

“Да что там, сейчас быстренько поменяем один провод.”

А через час у вас не работает свет в ванной, холодильник, домофон и почему-то телевизор у соседей.

Поэтому опытный программист со старым кодом ведёт себя осторожно.

Он не заходит туда с криком:

“Сейчас я тут всё красиво перепишу!”

Он заходит тихо.

Смотрит.

Пытается понять.

Не делает резких движений.

Иногда даже здоровается.

Потому что старый код может быть некрасивым, но он уже пережил боевые условия: реальные пользователи, срочные правки, странные требования, ночные релизы, праздники, отчёты, скидки, акции и “а можно ещё одну маленькую доработку?”

Новый красивый код пока ничего этого не пережил.

Он как белые кроссовки в первый день.

Красиво, но страшно выйти на улицу.

Почему старый код нельзя просто переписать

Это любимый вопрос нормальных людей:

“Если код такой страшный, почему его просто не переписать?”

Вопрос хороший.

Ответ грустный.

Потому что переписать старый код — это не как переписать школьное сочинение.

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

“Через 15 минут будем подавать кофе, вы успеете?”

Старый код часто связан с десятками других частей системы. Его используют разные модули, сервисы, отчёты, клиенты, автоматические процессы и кто-то из бухгалтерии, кто просто нажимает одну кнопку раз в месяц, но если эта кнопка сломается — узнают все.

Переписать можно.

Но нужно понимать:

что именно он делает;
кто от него зависит;
какие странные случаи он обрабатывает;
какие ошибки он уже научился обходить;
какие пользователи привыкли к его поведению;
что сломается, если сделать “правильно”.

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

Иногда он выглядит плохо, потому что жизнь была сильнее.

Старый код пугает не видом, а неизвестностью

Новый баг обычно кричит:

“Я здесь!”

Старый код молчит.

Он может выглядеть спокойно.

А потом ты меняешь одну строчку — и внезапно падает тест, который называется test_old_behavior_2.

Ты открываешь его.

Там проверяется поведение, которое никто не может объяснить.

Ты спрашиваешь коллег:

— А зачем это нужно?

Один говорит:

— Кажется, для старой версии.

Второй говорит:

— По-моему, это просил клиент.

Третий говорит:

— Не знаю, я тогда ещё не работал.

Четвёртый молчит, потому что он писал этот код, но уже сделал вид, что занят.

И вот ты сидишь перед выбором:

исправить красиво и рискнуть сломать старое поведение;
оставить как есть и добавить ещё один маленький костыль;
уйти пить чай и надеяться, что задача сама передумает.

Чаще всего побеждает чай.

Старый код умеет притворяться понятным

Самое коварное в старом коде — он может начинаться нормально.

Ты открываешь файл и думаешь:

“О, всё не так плохо.”

Названия понятные.
Структура вроде есть.
Комментарии встречаются.
Функции не слишком большие.

А потом доходишь до середины.

И видишь условие:

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

И ты понимаешь: это не код.

Это договор с древним злом.

Самое смешное, что такое условие могло появиться вполне логично.

Сначала добавили одну проверку.

Потом вторую.

Потом “быструю правку”.

Потом исключение для важного клиента.

Потом временный флаг.

Потом ещё один флаг, потому что первый работал не так.

Через три года это уже не бизнес-логика.

Это салат.

Причём салат, который приносит деньги, поэтому трогать его страшно.

Почему программисты иногда защищают страшный код

Иногда программист сам говорит:

“Да, код ужасный. Но не трогайте его.”

Со стороны звучит странно.

Если ужасный — надо исправить.

Но разработчик знает: есть разница между плохим кодом и опасным кодом.

Плохой код можно постепенно улучшать.

Опасный код сначала надо понять.

Иначе попытка “навести порядок” может закончиться так:

было некрасиво, но работало;
стало красиво, но не работает;
пользователи недовольны;
менеджер грустит;
разработчик объясняет, что “зато архитектурно стало лучше”;
никто не радуется.

Поэтому старый код часто чинят маленькими шагами.

Не потому что программисты ленивые.

А потому что они уже видели, как “давайте быстро перепишем” превращается в “почему третий месяц ничего не готово?”

Старый код — это память проекта

Есть ещё один важный момент.

Старый код — это не просто набор строк.

Это история проекта.

В нём спрятаны решения, которые когда-то принимались не от хорошей жизни.

Вот здесь обошли ограничение старой системы.
Вот здесь срочно спасали релиз.
Вот здесь клиент попросил “маленькую особенность”.
Вот здесь была акция, которую забыли удалить.
Вот здесь пытались сделать правильно, но срок был вчера.
Вот здесь кто-то написал “временно” и ушёл в отпуск. Возможно, навсегда.

Поэтому старый код нельзя оценивать только словами:

“Фу, некрасиво.”

Иногда он некрасивый, потому что честно пережил реальность.

Это как старый рабочий стол у мастера. Да, там царапины, пятна, кривые ящики и непонятная коробочка с гвоздями. Но мастер знает, где что лежит, и всё работает.

Проблема начинается, когда мастер ушёл, а коробочка осталась.

И теперь никто не знает, почему её нельзя выбрасывать.

Что делать, если пришлось трогать старый код

Первое — не геройствовать.

Если код старый, странный и важный, не надо начинать с глобальной уборки.

Нужно сначала понять, что он делает.

Второе — проверять поведение.

Не только “код выглядит правильно”, а “система ведёт себя так же, как раньше, кроме нужного изменения”.

Третье — писать тесты хотя бы вокруг того места, которое трогаешь.

Тесты для старого кода — это как страховочная верёвка. Может, она не делает поход приятным, но помогает не улететь в пропасть.

Четвёртое — оставлять нормальные комментарии.

Не:

“Костыль.”

А:

“Эта проверка нужна для старого сценария, иначе ломается такой-то случай.”

Будущий программист скажет спасибо.

Или хотя бы не проклянёт.

Пятое — улучшать маленькими шагами.

Старый код не всегда надо побеждать одним большим ударом. Иногда его надо аккуратно приручать.

Почему новый баг иногда даже приятнее

Новый баг раздражает, но он честный.

Он появился.
Он мешает.
Его надо убрать.

Старый код сложнее.

Он может быть одновременно плохим, важным, рабочим, опасным и никому не понятным.

Новый баг — это таракан на кухне.

Неприятно, но ты его видишь.

Старый код — это подозрительный шум в стене.

Вроде ничего не происходит.

Но ты уже не спишь спокойно.

Итог

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

А потому что в нём слишком много неизвестного.

Новый баг можно поймать.
Старый код нужно расшифровывать.

Новый баг появился недавно.
Старый код мог копить странности годами.

Новый баг обычно ломает что-то одно.
Старый код может держать на себе половину проекта, и никто уже не помнит как.

Поэтому, когда программист говорит:

“Мне нужно сначала разобраться, прежде чем это менять”

он не тянет время.

Он просто пытается понять, это обычная правка или вход в древний храм, где на двери написано:

“Не трогать. Работает.”

А у вас было такое: хотели поправить одну мелочь, а в итоге нашли целый музей старых решений?