Технический долг: что это такое и как с ним работать, не разрушая продукт
«У нас много технического долга» — фраза, которую произносят почти в каждой команде, но вкладывают в неё разный смысл. Для кого-то это старая версия фреймворка, для кого-то — модуль без единого теста, для кого-то — просто код, который стыдно показывать. Из-за такой размытости технический долг легко превращается в отговорку: любое неудобство в кодовой базе списывают на него, и разговор о приоритетах превращается в спор о терминах. Разберёмся, что это понятие значит на самом деле и как с ним обращаться так, чтобы это помогало продукту, а не превращалось в бесконечный рефакторинг ради рефакторинга.
Технический долг — это метафора о выборе, а не о качестве кода
Термин ввёл Уорд Каннингем, и изначальная метафора была точнее, чем то, во что она превратилась в обиходе. Идея в следующем: когда команда выбирает быстрое решение вместо более основательного, чтобы выпустить фичу раньше, она берёт «кредит». Этот кредит можно отдать позже — переписав код аккуратнее, — но пока он не отдан, на него «начисляются проценты» в виде более медленной разработки, более частых багов и более высокой цены на добавление новых фич в этом месте системы.
Ключевая часть метафоры, которую часто теряют: долг — это результат осознанного решения, а не синоним плохого кода. Если разработчик просто не умел писать код лучше, это не технический долг, это низкое качество работы. Разница важна, потому что с ней связаны разные способы решения проблемы.
Четыре вида долга, и почему их стоит различать
Удобно делить технический долг по двум осям: осознанность решения и его обоснованность на момент принятия. Получается четыре комбинации:
- Осознанный и обоснованный. Команда понимала, что делает временное решение, и приняла это ради скорости выхода на рынок или проверки гипотезы. Это здоровый долг — если его действительно потом обслуживают.
- Осознанный и необоснованный. Решение принято второпях, без реальной необходимости — просто было лень спроектировать нормально. Такой долг обычно и накапливается быстрее всего.
- Неосознанный и обоснованный. На момент написания кода решение было хорошим при доступных знаниях и требованиях, но со временем требования изменились, а архитектура — нет. Это естественная часть жизни любой системы.
- Неосознанный и необоснованный. Команда просто не знала, как сделать лучше, и не подозревала, что создаёт проблему. Это ближе к пробелам в опыте, чем к стратегическому выбору.
Если в команде принято валить всё в одну кучу под ярлыком «технический долг», приоритизировать его почти невозможно — потому что осознанный компромисс ради дедлайна и обычная недоработка требуют совершенно разного отношения.
Как отличить технический долг от просто плохого кода
Практический тест простой: если бы вы могли вернуться в момент принятия решения, приняли бы вы его снова с той информацией, что была тогда? Если да — это, вероятно, обоснованный долг, часть нормальной инженерной работы. Если нет — перед вами скорее ошибка или недостаток квалификации, и решать её нужно не «графиком погашения долга», а изменением процесса: код-ревью, обучением, более чётким описанием требований.
Ещё один полезный признак — можно ли объяснить компромисс в одном предложении с понятной причиной («мы захардкодили конфиг, чтобы успеть к демо, и договорились вынести его в переменные окружения после релиза»). Если объяснение сводится к «так исторически сложилось» без какой-либо причины — это, скорее всего, не стратегический долг, а просто накопившаяся энтропия.
Как работать с долгом на практике
Несколько подходов, которые реально приживаются в командах, а не остаются красивой идеей на одном созвоне:
- Фиксируйте долг в момент его создания. Один комментарий в коде или тикет с коротким описанием компромисса стоит дешевле, чем потом заново разбираться, почему что-то сделано именно так.
- Считайте долг активом с процентной ставкой, а не общим злом. Не весь долг одинаково опасен — модуль, который трогают раз в год, может спокойно жить с компромиссами, а код в самом горячем пути стоит обслуживать в первую очередь.
- Выделяйте постоянную, но небольшую долю времени на погашение. Регулярный небольшой процент спринта работает надёжнее, чем редкие «недели рефакторинга», которые постоянно переносятся из-за более срочных задач.
- Связывайте погашение долга с реальными фичами. Легче обосновать рефакторинг модуля, если он прямо сейчас блокирует нужную бизнесу возможность, а не потому что «код некрасивый».
- Не превращайте разговор о долге в разговор о вине. Если обсуждение компромиссов прошлого превращается в поиск виноватого, команда быстро перестанет их фиксировать вслух — а значит, долг просто станет невидимым.
Технический долг опасен не сам по себе, а тогда, когда о нём никто не знает и никто не считает нужным его обслуживать.
Итог
Технический долг — это инструмент управления компромиссами, а не диагноз кодовой базы. Полезно относиться к нему так же, как к финансовому долгу: иногда он оправдан и помогает двигаться быстрее, но требует, чтобы кто-то помнил о нём и планировал выплату. Если в вашей команде это слово используют как универсальное объяснение любых проблем с кодом — возможно, стоит для начала разделить долг и обычные недоработки, а уже потом решать, что и в каком порядке чинить.
← Все статьи