Технические долги

4 декабря 2008 г.

Этот термин впервые ввел Ward Cunningham:

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

Обсуждение нюансов технических долгов в подкасте Podlodka https://soundcloud.com/podlodka/podlodka-77-tekhnicheskiy-dolg

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

  • Игнорировать дизайн — брать деньги в долг
  • Рефакторинг — способ возврата долга
  • Замедление разработки из-за запутанности системы — выплата процентов
  • Провал проекта — приезд приставов и конец бизнеса.

Типы долгов

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

Неумышленные

Это самый простой и очевидный тип долгов. Они накапливаются, если программист делает ошибки при разработке проекта, неверно применяя шаблоны проектирования или неправильно используя принципы ООП.

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

Умышленные

Это долги, которые характерны для более «матерых» программистов.

Кратковременные

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

Долговременные

Эти долги лежат у самого основания нашего проекта. С ними мы миримся и договариваемся, что они являются нормой. К примеру, мы не будем поддерживать Oracle ни в какой версии нашей системы. С таким утверждением можно вполне спокойно развивать проект. Или например, система будет иметь пользовательский интерфейс на ASP.NET. Если приходится платить по этим долгам (например, переход с MS SQL на Oracle), то в конечном счете это означает создание качественно нового приложения.

«Запах» кода с долгами

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

  1. Любое изменение системы приводит к ряду новых дефектов. Запутанность в коде, сильное связывание всех частей проекта, отсутствие тестов приводит к эффекту бабочки. Когда, к примеру, изменение способа отправки электронных писем влияет на работу слоя отображения. В таком проекте трудно двигаться вперед. При интенсивной разработке постоянно будут вылезать недоработки или поломки в некогда работающем коде.
  2. Команда разработчиков постоянно встречается с непредвиденными проблемами. Это могут проблемы разного характера. Например, невозможность расширения иерархии объектов, проблемы с переходом на другой провайдер по передаче SMS сообщений. Если дизайн системы не предполагает ее изменения в дальнейшем (сильное связывание компонентов, раскрытие внутренностей объектов, глобальные переменные и т.п.), то это всегда будет приводить разработчиков к неожиданным затруднениям.
  3. Уже исправленные дефекты снова появляются. Обычно это происходит, когда нет модульных тестов. Причины вполне очевидны. Если мы нашли ошибку в программе, например, отсутствие проверки на граничные значения, и написали на эту ошибку тест, то теперь на протяжении жизни проекта этот тест будет гарантировать, что такая ошибка вновь не появится. Неверное исправление кода приведет к падению теста. Если же такого теста нет и ваш коллега поправил код так, как ему этого хочется, то ошибка может вернуться опять. Ему ведь никто не сообщил, что в таком-то модуле надо обязательно проверять значение на верхнюю границу.

Когда начинаем платить?

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

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

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

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

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

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

Отсюда можно сделать вывод, что если команде нужно сделать «быстрый» продукт (например, промо-версию своего продукта для демонстрации и получения инвестиций на основной проект), то вполне подойдет тактика синей команды. Однако, с такой тактикой не стоит рассчитывать на длительные проекты.

Динамика нарастания долгов

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

Рисунок показывает на сколько больше денег было потрачено на проект из-за долгов в коде.

Интересно отметить тенденции:

  • До первого релиза проекта идет интенсивное наращивание функциональности. Работа кипит.
  • В какой-то момент (первая красная точка) программисты понимают, что без улучшения качества кода будет трудно двигаться вперед. Этот момент показывает спад долгов в коде (до первой зеленой точки).
  • Перед релизом приходит руководитель проекта и начинает подгонять команду, напоминать о приближающихся сроках или, что еще хуже, эти сроки урезать. Здесь мы видим резкий скачок. В этот момент увеличивается как само количество долгов в коде, так и выплаты по уже существующим.

Эта тенденция повторяется от релиза к релизу. Чем больше мы работаем с проектом, тем больше мы платим за оставленные в коде долги.

Почему руководители допускают тех. долг

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

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

Программисты видят причину

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

Руководители видят следствия

Невозможно объяснить человеку, который не разбирается в программировании, почему мы в данный момент не можем позволить себе расширить нашу систему? Или почему вдруг стоимость поддержки системы стала расти? И почему нам требуется все больше и больше времени на добавление функций, которые раньше довольно быстро добавлялись? Попробуйте объяснить это в технических терминах и вас попросят вернуться к работе и впредь не допускать подобных ситуаций. В этот момент время уже проиграно. Теперь, чтобы догнать конкурентов, нужно сменить тактику!

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

Сравнение подходов

Теперь рассмотрим различные подходы к разработке в ещё более длительном промежутке времени.

Для сравнения у нас есть 3 подхода:

  1. Команда не заботится о качестве кода. Как уже было показано, этот способ вести проект ведет только к его полной остановке. Наступает момент, когда проект проще выкинуть в окно и написать заново.
  2. Руководители, зная как важно улучшать код, раз в год выделяют пару недель на рефакторинг. Слишком редкие возможности действительно улучшить код в проекте не дадут практически никаких результатов. Долги растут постоянно. Если оплачивать их только иногда, мы никогда не добьемся их уменьшения.
  3. Команда заботится о постоянном улучшении качества кода. Только постоянная забота о качестве кода может на долгое время сохранить систему в рабочем состоянии.

Метрики технического долга

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

Считают долг с помощью таких инструментов как SonarQube. Кроме этого, в системы CI бывают встроены метрики кода. Например, в TeamCity есть анализаторы кода, счетчики модульных тестов и покрытия тестами.

Если разработчики берут задачу по снижению технического долга, то логично, что после реализации задачи, снижение станет заметным на графиках и в цифрах.

Как правильно относится к техническим долгам

Итак, из всего сказанного можно подытожить, что технические долги == финансовые долги.

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

Ссылки:

12 комментариев:

  1. Респект!
    Занимательно... Думаю что каждый увидит как минимум один из своих проектов в другом свете...

    ОтветитьУдалить
  2. В неумышленных долгах ошибка "при разработкЕ".
    И еще в предложениях: "При разработке проекта, мы всегда стараемся оставить ее в положении наиболее выгодном для будущих изменений. Сделать ее более гибкой.", наверное нужно "его" вместо "ее".

    ОтветитьУдалить
  3. Андрей Максимов18 сентября 2012 г. в 09:37

    Хорошая статья, но непонятно, что делать в случаях, когда долги растут. Начинать с нуля? А что если результат и изменения нужны постоянно?
    Как понятно по вопросам, я спрашиваю в роли руководителя проекта.

    ОтветитьУдалить
  4. Андрей,


    Начинать с нуля, конечно, не нужно :) Вы можете давать результат постоянно, если программисты научатся правильно делать рефакторинг.


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


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

    ОтветитьУдалить
  5. Андрей Максимов30 ноября 2012 г. в 19:14

    Я думаю, что такого не бывает - когда проект - сплошной долг. По крайней мере, никто не признается...
    Тут каждый наверное сам должен определять, потому что со стороны возможно давать лишь абстрактные советы.
    Где-то есть принципы, где-то нет... В общем, мы делаем изменения в старом для клиентов и развиваем новые части. Клиенты используют часть старого + новый функционал, не замечая разницы. Мы сокращаем число долгов, убивая старое...
    Наверное, как раз под прошлое подпадает, что он сам - это долг. Но прикол в том, что работает-то намного лучше, потому что без "принципов проектирования" созданный, работает, там нечему ломаться.

    ОтветитьУдалить
  6. Для инвесторов я сформулировал заклинание "Отсутствие внутреннего качества исходного кода (технический долг) - это мера потерь инвестиций в долгосрочный софтверный проект". С приложением ссылки на этот пост дает эффект ;-)

    ОтветитьУдалить
  7. Короткие посты по теме https://plus.google.com/u/0/114590540937311233959/posts/iMDtR5wxR8V, https://plus.google.com/u/0/114590540937311233959/posts/PwE1oygYBqa, https://plus.google.com/u/0/114590540937311233959/posts/7Eg76KXqmUi

    ОтветитьУдалить
  8. Леонид, а как инвесторы на это реагируют? Они ведь вряд ли могут оценить качество кода. Для них это не абстракция?

    ОтветитьУдалить
  9. А откуда картинки с такой занимательной статистикой? В самом деле, сложно поверить, что кто-то научился так скурпулезно считать стоимость технических долгов.

    ОтветитьУдалить
  10. Антон, на картинках написаны примерные цифры, но методика оценки тех. долга не сложная.
    Нужно мониторить задачи, которые являются тех. долгом оценивать их по объему работы и отсюда брать конечную стоимость.
    Да, она будет примерная, но обычно достаточно узнать порядок цифр, чтобы принимать решение о рефакторинге.

    ОтветитьУдалить
  11. Спасибо, очень познавательно! Вероятно, вы не заметили опечатку, скачок следует написать через букву О, а не Ё

    ОтветитьУдалить
  12. Рад, что вам понравилось. Да, это опечатка, поправил.

    ОтветитьУдалить

Моя книга «Антихрупкость в IT»

Как достигать результатов в IT-проектах в условиях неопределённости. Подробнее...