4.5 Измерение технического долга
Обзор и мотивация
Технический долг, метафора, придуманная Уордом Каннингемом, описывает накопленную стоимость прошлых сокращений пути, целесообразных решений, позволивших отгрузить что-то раньше, но оставивших кодовую базу труднее для изменения впоследствии, точно так же как финансовый долг позволяет тратить сейчас за счёт процентов позже. Каждая кодовая база несёт некоторый технический долг, и это не автоматически провал; подлинная ценность метафоры в том, что она представляет долг как управляемый компромисс, а не постыдный секрет или неизбежное, постоянное бремя. Эта тема о том, как сделать этот компромисс видимым и управляемым через измерение, а не оставлять его смутным, вечно деприоритизируемым беспокойством, которое чувствует каждый инженер, но на которое никто не может действовать с доказательством.
Темы, предшествующие этой, сложность (4.1), покрытие (4.2), объём изменений и горячие точки (4.3) и статический анализ (4.4), каждая выявляет одну грань технического долга. Задача этой темы синтез: превращение этих отдельных сигналов, плюс пунктов, никогда не появляющихся ни в каком автоматизированном сканировании (недокументированное архитектурное сокращение пути, сознательно отложенная миграция), в единый, приоритизированный, видимый бэклог, честно конкурирующий за инвестицию против работы над функциями, а не проигрывающий эту конкуренцию по умолчанию просто потому, что у него нет прикреплённой метрики и защитника на планёрках.
Для крупных команд неуправляемый технический долг накапливается подлинно опасным и легко недооцениваемым образом: каждое новое сокращение пути делает следующее изменение чуть труднее, что создаёт давление для ещё большего числа сокращений пути, что накапливается дальше. Корпоративные и государственные организации, поддерживающие системы много лет, особенно подвержены этому накапливающемуся эффекту, а центральная рекомендация этой темы, видимый, количественно измеренный, приоритизированный бэклог долга, механизм, позволяющий организации фактически управлять компромиссом сознательно, а не сползать в кризис.
Ключевые принципы
- Технический долг сознательная метафора для управляемого компромисса, а не постыдный секрет. Некоторый долг, принятый сознательно, разумное бизнес-решение.
- Неизмеренный долг проигрывает конкуренцию приоритизации против работы над функциями по умолчанию, не потому что он менее важен, а потому что у него нет видимого защитника.
- Количественно измеряйте долг в терминах, которые могут взвесить лица, принимающие решения: стоимость исправления против стоимости его несения. Смутное заявление «код грязный» редко хорошо конкурирует против конкретного запроса на функцию.
- Долг накапливается. Каждое новое сокращение пути делает будущие изменения незначительно труднее, и этот эффект ускоряется, если им не управлять.
- Не весь долг нужно погашать. Некоторый стоит нести бесконечно, если стоимость его исправления превышает стоимость жизни с ним.
Рекомендации
Постройте видимый, единый бэклог технического долга
Консолидируйте сигналы из предыдущих тем этой части, выбросы сложности, области с низкой долей убитых мутантов, горячие точки, нерешённые находки статического анализа, наряду с пунктами долга, которые может определить только человек (архитектурное сокращение пути, отложенное обновление зависимости, недокументированный обходной путь), в один видимый бэклог, отслеживаемый с той же строгостью и видимостью, что и ваш бэклог функций. Долг, живущий только в памяти отдельных инженеров или в разрозненных комментариях к коду, фактически не существует для целей приоритизации.
Количественно измеряйте стоимость каждого пункта долга и стоимость его несения
Для каждого пункта оцените две цифры: стоимость его исправления (инженерное время, риск самого исправления) и стоимость его несения неисправленным (насколько медленнее идёт связанная работа, насколько дополнительный риск дефектов он несёт, насколько он блокирует другую работу). Это формулирование, заимствованное напрямую из логики самой метафоры финансового долга, даёт лицам, принимающим решения, реальную основу для сравнения со стоимостью и ожидаемой ценностью работы над функциями, а не абстрактную, неколичественную жалобу.
Приоритизируйте по воздействию, а не по возрасту или самому громкому защитнику
Ранжируйте пункты долга по их сочетанию стоимости несения и того, как часто затронутый код трогают (данные объёма изменений темы 4.3 напрямую полезны здесь): пункт в редко изменяемом уголке кодовой базы, каким бы неприятным он ни был, имеет гораздо меньшее значение, чем тот, что сидит прямо на пути вашей самой активной разработки. Сопротивляйтесь приоритизации по тому, какой пункт дольше всего находится в бэклоге или за какой инженер наиболее настойчиво выступает, ни одно из этого надёжно не коррелирует с фактическим бизнес-воздействием.
Выделяйте выделенную, защищённую мощность на устранение долга
Бэклог долга, вынужденный конкурировать пункт за пунктом против каждого входящего запроса на функцию в каждом цикле планирования, имеет тенденцию последовательно проигрывать, поскольку работа над функциями обычно имеет более ясного, более немедленного бизнес-защитника. Выделите защищённый процент инженерной мощности, распространённый паттерн где-то между 10% и 20%, именно на устранение долга, решённый заранее, а не пересматриваемый заново каждый спринт, так что погашение долга происходит как само собой разумеющееся, а не только в последствии кризиса.
Принимайте некоторый долг как постоянный и явно это заявляйте
Не каждый пункт принадлежит активному плану устранения. Там, где стоимость исправления подлинно превышает стоимость несения пункта бесконечно, особенно для кода в стабильной, редко трогаемой, скоро выводимой из эксплуатации системе, задокументируйте это решение явно и переместите пункт в сознательно деприоритизированную категорию, а не позволяйте ему бесконечно сидеть в активном бэклоге, где его постоянное присутствие тихо подразумевает работу, которая фактически никогда не произойдёт.
Компромиссы: плюсы и минусы
| Подход | Плюсы | Минусы |
|---|---|---|
| Никакого формального отслеживания долга | Никаких накладных расходов | Долг проигрывает конкуренцию приоритизации по умолчанию; накапливается невидимо |
| Неформальная, стихийная осведомлённость о долге | Низкие накладные расходы, некоторая видимость | Непоследовательно; полагается на индивидуальную память и защиту |
| Формальный, количественно измеренный бэклог долга | Честно конкурирует за инвестицию; обеспечивает информированные компромиссы | Требует постоянного обслуживания и дисциплины количественного измерения |
| Защищённая, выделенная мощность устранения | Обеспечивает последовательное погашение, а не только реактивное | Сокращает мощность, доступную для работы над функциями в краткосрочной перспективе |
Центральное напряжение: немедленное давление поставки против долгосрочной сопровождаемости. Работа над функциями почти всегда имеет более ясного, более немедленного бизнес-защитника, чем устранение долга, что создаёт структурное давление, заставляющее долг проигрывать каждое отдельное решение приоритизации, даже когда его кумулятивная стоимость высока. Разрешайте напряжение, полностью удаляя устранение долга из конкуренции пункт за пунктом через защищённую, заранее выделенную мощность, так что компромисс решается сознательно и заранее, а не пересматривается, и обычно проигрывается, в каждом отдельном цикле планирования.
Вопросы для обсуждения в команде
Есть ли у нас единый, видимый бэклог технического долга, или осведомлённость о долге живёт в основном в головах отдельных инженеров? Если честный ответ второе, это единственный самый большой пробел, который эта тема рекомендует закрыть в первую очередь.
Могли бы мы для нашего главного пункта долга сформулировать стоимость его исправления и стоимость его несения в терминах, достаточно конкретных, чтобы честно сравнить с запросом на функцию? Если нет, отработайте это количественное измерение вместе как групповое упражнение, используя реальный, текущий пункт.
Какой процент нашей инженерной мощности фактически идёт на устранение долга, и был ли этот процент решён сознательно, или это просто то, что случайно выживает после того, как распределена работа над функциями? Посмотрите на ваши фактические недавние спринты и вычислите реальное число, а не полагайтесь на впечатление.
Приоритизирован ли наш бэклог долга по подлинному бизнес-воздействию, или по тому, какой пункт поднимался наиболее настойчиво или сидит там дольше всего? Сверьте вашу текущую приоритизацию с данными объёма изменений (тема 4.3) и посмотрите, совпадают ли они.
Какие пункты долга нам следует явно принять как постоянные, а не позволять им бесконечно сидеть в активном бэклоге? Определите хотя бы один реальный пункт, где стоимость исправления подлинно превышает стоимость несения, и обсудите перемещение его в явно деприоритизированный статус.
Как изменился наш бэклог долга за последний год, растущий, сокращающийся или остающийся плоским, и совпадает ли этот тренд с нашей интуицией? Отслеживайте это со временем, а не смотрите только на единый снимок; тренд часто более информативен, чем абсолютный размер в любой данный момент.
Отраслевой взгляд
Стартап. Сознательный, информированный долг часто разумная стратегия на этой стадии: быстрая отгрузка для проверки гипотезы, с ясным планом вернуться к конкретным сокращениям пути, если продукт докажет свою состоятельность, законная сделка, а не провал. Риск в потере отслеживания того, какие сокращения пути были сознательными и обратимыми, а какие тихо стали постоянными, непроверяемыми обязательствами по мере роста кодовой базы.
Малый бизнес. Простой, общий список, даже неформальный, называющий ваши известные сокращения пути и их примерную стоимость исправления, обычно достаточен в этом масштабе. Главная дисциплина, стоящая принятия, периодический пересмотр этого списка, а не позволение ему тихо накапливаться и становиться невидимым через привычность.
Корпорация. Защищённая, заранее выделенная мощность устранения важнее всего здесь, поскольку конкуренция приоритизации между долгом и работой над функциями надёжно благоприятствует функциям по десяткам команд одновременно без структурного противовеса. Стандартизируйте практику количественного измерения долга по всей организации, чтобы пункты долга можно было честно сравнивать между командами для решений об инвестициях на уровне портфеля.
Государство. Долгоживущие системы накапливают долг годами или десятилетиями постепенных, по отдельности разумных изменений требований, часто вообще без какого-либо формального отслеживания долга, пока кризис не вынудит решить проблему. Количественно измеренный, видимый бэклог долга подлинно убедительный инструмент для обоснования бюджета модернизации перед надзорными органами, поскольку он превращает смутное заявление «система старая» в конкретный, просчитанный кейс для инвестиции.
Примеры
Корпорация. Платформа выставления счетов телекоммуникационной компании накопила более десятилетия неформально признаваемого, но никогда формально не отслеживаемого технического долга, причём инженеры регулярно упоминали на ретроспективах, что «биллинговый движок это беспорядок», без какого-либо продолжения. Новый директор по инженерии потребовал от каждой команды построить количественно измеренный бэклог долга, оценивая стоимость исправления и стоимость несения для каждого пункта, и выделил фиксированные 15% инженерной мощности на устранение долга на будущее. В течение года пять главных пунктов с наивысшей стоимостью несения, представлявших небольшую долю общего бэклога по количеству, были решены, а доля неудачных изменений (тема 2.10) для развёртываний, связанных с биллингом, измеримо улучшилась, демонстрируя непропорциональное воздействие нацеливания на пункты с наивысшей стоимостью несения в первую очередь, а не прохождения через бэклог в произвольном порядке.
Государство. Основная система обработки данных национального статистического агентства, изначально построенная более двадцати лет назад, никогда не имела формальной оценки долга, несмотря на широко распространённое неформальное признание среди персонала, что значительные части хрупкие и плохо понятые. Структурированная оценка долга, сочетающая находки статического анализа, данные горячих точек и интервью с немногими оставшимися инженерами, понимавшими самые старые компоненты, произвела количественно измеренный, приоритизированный бэклог, напрямую поддержавший многолетний запрос бюджета модернизации. Критически важно, что оценка также явно определила несколько стабильных, редко трогаемых унаследованных компонентов как разумные для оставления без изменений, избежав излишне широкой и дорогой полной переписки системы в пользу целевой инвестиции в конкретные области, где данные показали наивысшую постоянную стоимость.
Бизнес-кейс: мотивация, ROI и TCO
Отдача от сознательного управления техническим долгом это избегание накапливающейся стоимости: каждое неадресованное сокращение пути делает будущие изменения незначительно труднее, и этот эффект ускоряется без вмешательства, в конечном итоге производя кодовую базу настолько хрупкую, что даже простые изменения становятся медленными и рискованными. Телекоммуникационный пример выше конкретно показывает отдачу: нацеливание на небольшое число пунктов с наивысшей стоимостью несения произвело измеримое улучшение поставки и качества, непропорциональное скромной доле общего бэклога, которую эти пункты представляли.
Полная стоимость владения это защищённая мощность, выделенная на устранение, типично от 10% до 20% инженерного времени, что реальная, видимая стоимость, конкурирующая со скоростью функций в краткосрочной перспективе. Эта стоимость стоит того, чтобы её платить, потому что альтернатива, неуправляемый, накапливающийся долг, в конечном итоге обходится гораздо дороже в замедленной поставке и повышенной частоте дефектов по всей кодовой базе, а не только в конкретных неадресованных пунктах.
Антипаттерны и ловушки
- Отсутствие видимого, отслеживаемого бэклога долга: долг проигрывает конкуренцию приоритизации по умолчанию и накапливается невидимо.
- Смутные, неколичественные заявления о долге: редко хорошо конкурируют против конкретных, количественно измеренных запросов на функции при планировании.
- Приоритизация долга по возрасту или объёму защиты, а не воздействию: неправильно направляет ограниченную мощность устранения.
- Отсутствие защищённой мощности для устранения: погашение долга происходит только реактивно, после кризиса, а не как рутинная, сознательная практика.
- Отношение ко всему долгу как к одинаково стоящему исправления: тратит усилия на пункты с низким воздействием, пока пункты с высокой стоимостью несения остаются неадресованными.
- Позволение долгу бесконечно сидеть в активном бэклоге без решения, что он постоянный: подразумевает будущую работу, которая фактически никогда не произойдёт, и засоряет подлинную приоритизацию.
Модель зрелости
- Уровень 1, Инициация: Технический долг обсуждается неформально, без отслеживаемого бэклога и количественного измерения; он последовательно проигрывает работе над функциями.
- Уровень 2, Развитие: Некоторые команды отслеживают долг неформально, но нет последовательного количественного измерения, видимости между командами или защищённой мощности устранения.
- Уровень 3, Стандартизация: Видимый, количественно измеренный бэклог долга существует по всей организации, с последовательно выделяемой защищённой мощностью устранения.
- Уровень 4, Управление: Пункты долга приоритизированы по измеренному воздействию (стоимость несения в сочетании с объёмом изменений), а постоянно принятый долг явно задокументирован, а не оставлен неоднозначным.
- Уровень 5, Оркестрация: Организация может указать на конкретные, измеримые улучшения поставки или качества, прослеженные до целевого устранения долга, а управление долгом является рутинным, доверенным входом в решения об инженерных инвестициях наряду с работой над функциями.
Идеи для обсуждения
- Каков наш единственный пункт долга с наивысшей стоимостью несения прямо сейчас, и могли бы мы его количественно измерить?
- Какой процент нашей мощности фактически сегодня идёт на устранение долга?
- Какой пункт долга нам следует явно принять как постоянный, а не оставлять неоднозначно в нашем бэклоге?
- Вырос ли наш бэклог долга, сократился или остался плоским за последний год?
- Что раскрыла бы количественно измеренная оценка долга, что упускает наша текущая неформальная осведомлённость?
Основные выводы
- Технический долг это управляемый компромисс, а не постыдный секрет; количественно измеряйте его, а не оставляйте смутной, вечно деприоритизируемой заботой.
- Количественно измеряйте стоимость исправления против стоимости несения для каждого пункта, чтобы он честно конкурировал против работы над функциями.
- Приоритизируйте по воздействию (стоимость несения в сочетании с объёмом изменений), а не по возрасту или объёму защиты.
- Выделяйте защищённую, выделенную мощность устранения, решённую заранее, поскольку иначе долг надёжно проигрывает конкуренцию пункт за пунктом против работы над функциями.
- Явно принимайте некоторый долг как постоянный, где стоимость исправления превышает стоимость несения, а не оставляйте его неоднозначно в активном бэклоге.
Источники и дальнейшее чтение
- Cunningham, Ward, “The WyCash Portfolio Management System” (отчёт об опыте OOPSLA, 1992): происхождение метафоры технического долга.
- Managing Technical Debt: Reducing Friction in Software Development, Филипп Крюхтен, Роберт Норд и Ипек Озкая (всеобъемлющее рассмотрение измерения и управления техническим долгом).
- Refactoring: Improving the Design of Existing Code, Мартин Фаулер (техники устранения, на которые в конечном итоге опирается бэклог долга).
- Your Code as a Crime Scene, Адам Торнхилл (анализ горячих точек как вход для приоритизации долга, тема 4.3).