Дорога в ад

Как прекрасен проект в самом начале, правда? Чистый лист. Разработчик чувствует себя свободным, ничто его не ограничивает (в том числе уже созданная кодовая база), бизнес доволен, потому что все делается быстро. Идиллия. Отдача от вложенных усилий огромна.

Но это длится недолго. Постепенно в коде накапливается технический долг. Разработчику все теснее в рамках существующей системы, а бизнес замечает, что каждая новая функция обходится все дороже. Разработка замедляется, тогда как усилий для достижения результата требуется все больше.

Если ситуацию не взять под контроль, наступит момент, когда «проценты» по техническому долгу станут неподъемными. То, что раньше делалось за часы, может растянуться на месяцы. Качество будет падать, с каждым изменением будут множиться ошибки, а окупаемость новых функций будет становиться все ниже.

И будет это продолжаться до тех пор, пока разработчик, уже не в силах работать с текущим кодом, не предложит полностью переписать систему. Бизнес же, тоскующий по временам «чистого листа» и отчаянно пытающийся двигаться вперед, на это согласится.

Кто должен выполнять рефакторинг

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

Сосредоточимся на другом: кто должен выполнять этот рефакторинг?

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

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

И это решение кажется очевидным.

Во-первых, это та самая команда, которая предлагает переписать проект: она изо дня в день сталкивается с проблемами. Видит, как каждое изменение дается все тяжелее. Знает: тронешь одно — нарушишь другое. И просто понимает, что любое добавление функционала настолько сложно, что легко упустить шаг или увязнуть в рутине из-за пустяковой задачи.

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

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

И наконец, эта команда уже доказала свою состоятельность. Создавая продукт с нуля, она показала, что при благоприятных условиях может добиваться неплохих результатов. Она это уже делала и проявила свой профессионализм!

Так почему бы и нет?

Что-то не сходится

Кто-то удачно подметил:

«Глупо делать одно и то же снова и снова в ожидании другого результата«.

Что гарантирует иной результат на этот раз?

В самом начале команда работала отлично. Все было продуктивно, все шло как по маслу. Но на каком-то этапе что-то пошло не так. Постепенно код накапливал технический долг, пока не настал момент, когда потребовалось полностью его переписать.

Но ничто не мешает этому повториться. Я встречался с командами, переделывающими одно и то же программное обеспечение до трех раз. Хотя, насколько мне известно, если вторая попытка снова завершается провалом, команда уже вряд ли попросит о третьем переписывании. Либо им откажут, либо им будет просто стыдно просить об этом.

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

И тем не менее, история повторяется.

Почему? Что делает эти, казалось бы, железные аргументы недостаточными?

Суть проблемы

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

Первое, что приходит в голову — свалить все на команду, обвинив ее в непродуктивности. Да, на старте они справились, но затем не смогли поддерживать проект. Как если бы для создания компании нужен был один генеральный директор, а для ее роста — другой. Но все не так просто. Эта команда действительно знала, как выполнять свою работу, понимала предметную область и достигала результатов.

Более того, я уверен, что многие другие команды в той же организации пойдут по тому же пути.

Тогда может возникнуть соблазн обвинить во всем бизнес или руководство. Это же бизнес требует невозможного, верно? Или руководство устанавливает нереальные сроки, верно? Но именно для этого и нужны технические специалисты — чтобы находить баланс между желаемым и возможным.

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

Мелочи

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

Одна из мелочей, которые я часто наблюдаю в таких ситуациях, — приоритеты команды. Не руководство навязывает эти приоритеты. Это собственное представление команды о том, что значит «задача выполнена». Сама команда зациклена на сроках сдачи. Она радуется, когда укладывается в дедлайны, и ищет оправдания и виноватых, когда не успевает закончить работу в срок. Но вы никогда не увидите, чтобы она радовалась оттого, что почистила код или и устранила препятствия для внедрения новых функций. И она уверена, что это правильно. Более того, она уверена, что по-другому и нельзя. Так копится технический долг.

Я также видел другую крайность — чрезмерное техническое усложнение системы. Планирование 20 функций наперед, перегруженность системы новым паттерном или архитектурой. Архитектурой, которая будет мешать, которая к моменту реализации окажется уже неактуальной и сама станет техническим долгом.

А тесты? Тесты, которые пишутся только для галочки в SonarQube. Нужно покрытие кода тестами, и все? Они считают эффективные тесты пустой тратой времени. Они не рассматривают тесты как инструмент для поддержания гибкости кода и, следовательно, не проводят их с этой целью.

Вот так, незаметно, накапливаются мелкие погрешности. Отложенные на «потом» рефакторинги, забытые в коде ярлыки, проведенные для галочки тесты.

И команда этого не видит. Она слишком занята. Ее собственные приоритеты и установки — «сдать любой ценой», «тесты для метрик», «рефакторинг потом» — именно то, что и приводит ее в тупик.

Технический долг в чистом виде.

Резкое торможение

Проблема технического долга не только в плохо написанном коде, который однажды придется исправлять. Проблема в накоплении процентов по этому долгу. И эти проценты капитализируются — начисляются на уже накопленную сумму. Чем больше технический долг, тем больше процентов вы платите за каждую новую функцию, тем дороже обходится ее реализация.

Идеально вписывается в историю «чистого листа»: в начале нет ни долга, ни процентов, каждая функция дается легко, а потом — по нарастающей.

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

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

Нам ведь не хочется, чтобы они возвращались.

А вот и главное

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

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

Но я ошибался.

Ранее я упоминал цитату: «Глупо делать одно и то же снова и снова в ожидании другого результата». Многие приписывают ее Эйнштейну, хотя его авторство не подтверждено. И именно так я смотрел на проблему — искал виноватых в команде, бизнесе или руководстве.

А вот что Эйнштейн действительно сказал в 1946 году:

«Если человечество хочет выжить, ему необходим новый образ мышления».

Это высказывание — может, не в таком драматичном звучании — именно то, что применимо в данной ситуации.

Если посмотреть с другой стороны, то провалился не подход, а образ мышления. Или корпоративная культура команды, как сказали бы многие. Писать качественный код — не пустая трата времени. Готовить код для гипотетической функции — не профессионализм архитектора, а избыточное усложнение. Тесты — рычаги для рефакторинга кода. Именно такие мелочи определяют изменение образа мышления или корпоративной культуры.

Работа с чистого листа кажется нам идеальной. Слишком идеальной. Быть может, те самые свобода и скорость, что нас так восхищают, покупаются ценой пренебрежения к «мелочам»? Может, стоит взглянуть на ситуацию иначе? Забыть про «чистый лист». Задаться вопросом: когда все идет как по маслу — что отходит на второй план? И не придется ли отдавать долг с процентами — день за днем, начиная с сегодняшнего?

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи David Rodenas PhD: Software Rewrites Need More Than New Code

Предыдущая статья7 методов работы со строками в JavaScript, о которых знают всего 2% разработчиков