Как найти управу на технический долг

Как найти управу на технический долг - 1

Привет, Хабр! Меня зовут Владислав Воячек, я работаю архитектором в ИТ‑холдинге Т1. Одна из моих задач — управление техническим долгом. И хочу поделиться с вами современными подходами к решению этой непростой задачи.

Не всегда следует любой ценой избегать технического долга, в некоторых случаях его разумное использование становится стратегическим инструментом для достижения целей проекта. Однако для того, чтобы технический долг перестал ощущаться как что‑то пугающее и неконтролируемое, важно научиться осознанно им управлять. Команда должна воспринимать обсуждение долга как часть рабочего процесса, а не как негативный аспект работы. Если долг рассматривается как управляемая часть системы, он становится менее тревожным. Вместо того, чтобы стремиться к его полному отсутствию — что часто невозможно, — следует поддерживать управляемый уровень долга, при котором система остаётся гибкой и производительной.

Вводная часть

Определение

Программные системы по мере своего развития склонны к накоплению недостатков во внутреннем качестве, которые затрудняют внесение изменений и дальнейшее развитие. Для краткого описания этого свойства была придумана метафора «Технический долг», предложенная Уордом Каннингемом в 1992 году. Она проводит аналогию с финансовым долгом: его можно «взять», чтобы быстрее достигнуть цели, но со временем нужно будет «выплатить проценты» в виде дополнительных усилий на исправление и улучшение.

Это приблизительная метафора, потому что, в отличие от финансового долга, довольно трудно измерить столь относительное понятие как «технический долг»: он зависит от многих факторов, включая контекст проекта, бизнес‑цели и видение команды. Но с помощью этой метафоры очень удобно объяснять различным участникам, в том числе без технического опыта, всем интуитивно понятно. Будем считать, что «тело» технического долга — это трудозатраты на исправление проблем или улучшение качества, а проценты по долгу — это дополнительные затраты, возникающие из‑за того, что проблемные части программных систем со временем замедляют разработку, усложняют поддержку и приводят к дефектам.

Как найти управу на технический долг - 2

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

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

Как найти управу на технический долг - 3

Элемент технического долга

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

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

  2. Причины. Каждый элемент технического долга имеет одну или несколько причин.

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

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

Развитие технического долга

Рассмотрим временную шкалу технического долга, которая показывает, как он развивается со временем:

  • T1: Возникновение — момент времени, когда элемент технического долга вводится в систему по каким‑либо причинам, для ускорения разработки или непреднамеренно.

  • T2: Осведомлённость — временная точка, когда разработчики или менеджеры замечают симптомы элемента технического долга. Если технический долг был принят сознательно и обосновано, то T2 = T1. Команда приняла явное решение и зафиксировала его.

  • T3: Критическая точка — это момент времени, когда стоимость технического долга начинает превышать его первоначальную ценность. Это приводит к ситуации, когда будет выгоднее погасить долг.

  • T4: Устранение — удаление элемента технического долга из системы. Стоимость устранения включает в себя как основную сумму долга, так и все накопленные проценты. В период с T3 до T4 проценты продолжают накапливаться.

  • …Или отсутствие устранения, если шаг T4 не выбрали. Если критическая точка T3 находится далеко в будущем, то стоимость устранения может быть непомерной, и поэтому решение откладывают на более поздний срок. Таким образом, может быть период с T2 и далее, когда вы просто живёте с техническим долгом и решаете оплачивать все повторяющиеся проценты по мере их накопления.

Как найти управу на технический долг - 4

Причины возникновения

Типы технического долга

В 2009 году Мартин Фаулер предложил классификацию на основе Квадранта Технического Долга. Он разделил технический долг на «осмотрительный или безрассудный» (prudent/reckless) и «преднамеренный или непреднамеренный» (deliberate/inadvertent) типы.

Как найти управу на технический долг - 5

В целом можно определить следующие типы технического долга:

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

  • Преднамеренный долг команда принимает осознанно, с пониманием причин и последствий. Чаще всего ради ускорения вывода продукта на рынок, раньше конкурентов. В этом случае все участники команды разработки, включая менеджеров, должны чётко понимать, что в какой‑то момент нужно будет «платить по долгам».

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

Что вызывает технический долг

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

  • бизнес — давление сроков и затрат, несогласованные бизнес‑цели, нечёткие бизнес‑требования;

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

  • разработка — недостатки в процессах, отсутствие автоматизации тестирования, отсутствие статической проверки кода;

  • команда — некомпетентность, отсутствие соответствующего опыта.

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

Выявление технического долга

Подготовка

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

Перед проведением анализа нужно провести следующие мероприятия:

  • Уточнить категорию «ТехДолг» в системе управления задачами. Указать конкретные программные артефакты, к которым относится долг: требования, код, архитектура, производственная инфраструктура и т. п.

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

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

Оценка артефактов

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

При при поиске элементов технического долга также следует обратить внимание на:

  • использование общепринятых практик, показавших свою эффективность;

  • соответствие чек‑листам, которые существуют в организации (их можно создать на стадии подготовки к анализу);

  • результаты интервью с участниками процесса разработки ПО.

Аналитика и сбор требований

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

При поиске элементов технического долга следует рассмотреть следующие симптомы:

  • Требования не задокументированы или изложены недостаточно ясно.

  • Разные участники процесса имеют противоречивое понимание требований.

  • Частые и неконтролируемые изменения на поздних стадиях разработки.

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

  • Участники проекта недостаточно активно участвуют в процессе согласования и уточнения требований.

Вопросы для исследования:

  • Насколько часто меняются требования и на каких этапах?

  • Сколько требований остаются неясными к моменту начала разработки?

  • Как часто функциональность не соответствует ожиданиям заказчика?

  • Сколько времени уходит на уточнение и согласование требований?

Архитектура

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

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

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

  • Рефлексивные вопросы и мысленные эксперименты. Люди мыслят по‑разному, когда решают проблемы и когда просто размышляют. Рефлексивные вопросы ставят под сомнение принятые решения и побуждают проверять собственные решения.

  • Анализ на основе сценариев — это краткое описание взаимодействия с системой с точки зрения одного из заинтересованных лиц. Например, заинтересованное лицо может предложить сценарий изменения, чтобы оценить, насколько дорого будет модифицировать систему с учётом её архитектуры.

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

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

Исходный код

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

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

  • Сколько времени мы потратили на устранение уязвимостей?

  • В каких частях кода увеличиваются затраты на обслуживание во время разработки?

  • Как дефекты связаны с областями кода, которые вызывают рост затрат на обслуживание?

  • Как часто разработчики вносят изменения в эти части системы?

  • Как много мест в коде, где разработчикам необходимо внести изменения для решения одной задачи?

  • Сколько запросов на изменение разработчики могут выполнить за один спринт или итерацию? Сколько времени занимает выполнение каждого, включая тестирование?

  • В каких частях кодовой базы разработчики проводят большую часть времени?

Процессы DevOps 

При анализе технического долга в DevOps следует обратить внимание на следующие вопросы:

  • Как быстро изменения проходят от кода до производства?

  • Сколько времени требуется для устранения сбоев?

  • Насколько часто происходят релизы?

  • Какова доля релизов, требующих отката?

  • Какая часть рутинных работ автоматизирована?

  • Существует ли документация по развёртыванию, обновлению и откату обновления системы.

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

  • Используются ли устаревшие скрипты или ручное управление?

  • Сложности в обновлении системы, невозможность легко обновить инфраструктуру или конфигурацию.

  • Неоптимальная структура конвейеров, слишком длинные, непрозрачные или сложные процессы CI/CD.

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

Управление

Классификация

После получения набора элементов технического долга следует их классифицировать. В начале статьи я приводил вариант от Мартина Фаулера, его классификацию на основе Квадранта, но, на мой взгляд, она скорее отражает природу технического долга и не очень удобна для управления его элементами.

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

  • Сложность устранения: от лёгкого (мелкие улучшения) до сложного (требующего изменения в архитектуре);

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

Как найти управу на технический долг - 6

Простые краткосрочные долги:

  • Пример: мелкие улучшения, временные решения или быстрые исправления, которые не влияют на архитектуру.

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

  • Рекомендации по устранению: их можно отложить на какое‑то время, поскольку они не требуют значительных усилий для устранения и не создают серьёзных рисков.

Простые долгосрочные долги:

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

  • Характеристики: такие долги могут привести к накоплению проблем и усложнению масштабирования в долгосрочной перспективе.

  • Рекомендации по устранению: они не являются критичными сейчас, но стоит отслеживать их и устранять, чтобы избежать накопления проблем в будущем.

Сложные краткосрочные долги:

  • Пример: проблемы, требующие значительных усилий для исправления в короткие сроки, например, ошибка в базовой архитектуре, которая приводит к немедленным проблемам.

  • Характеристики: эти долги могут быстро вызвать серьёзные сбои, но их устранение потребует значительных затрат.

  • Рекомендации по устранению: такие долги требуют немедленного внимания и исправления, так как их последствия могут быть разрушительными для проекта.

Сложные долгосрочные долги:

  • Пример: архитектурные проблемы или устаревшие технологии, которые затрудняют поддержку и развитие системы в будущем, требующие масштабных изменений.

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

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

Оценка

Технический долг в конечном итоге является экономическим вопросом. Стратегия управления им заключается в том, сколько ресурсов тратить и когда гасить (или не гасить) долг.

Вот рекомендуемые шаги для оценки технического долга и его «процентов»:

  • Выявить затронутые и связанные программные артефакты (код, тесты, сценарии сборки и так далее).

  • Использовать эти артефакты для расчёта стоимости исправления.

  • Использовать артефакты и последствия для расчёта повторяющихся затрат.

  • Рассчитать стоимость отказа от устранения этого технического долга (насколько это замедлит текущий прогресс и будут ли потери от симптомов технического долга?).

Планирование устранения

Для планирования устранения элементов технического долга можно проверить несколько сценариев «что, если»:

  • Что, если мы хотим избавиться от долга? Какова стоимость полного погашения сейчас? Или какова стоимость того, чтобы не позволить долгу увеличиваться, пока мы не разберёмся, как его погасить?

  • Что, если мы отложим «платеж»? Какова стоимость жизни с этим долгом, и как будет расти стоимость погашения с каждым последующим релизом?

Вот ещё набор практик по планированию работ над устранением технического долга:

  • Выделение определённой доли спринта на задачи по устранению технического долга (например, 15%). Возможно, в некоторых случаях, целесообразно выделить целый спринт.

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

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

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

Предотвращение

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

Аналитика и сбор требований

Эффективная аналитика и сбор требований — это основа успешной разработки программного обеспечения. Вот лучшие практики для этого процесса:

  • Понимание контекста проекта: изучение целей бизнеса, как создаваемое ПО поможет заказчику или пользователю.

  • Определение стейкхолдеров: определение ключевых заинтересованных сторон, кто и как может влиять на проект; построение коммуникаций с ними для выявления их потребностей.

  • Углубленный анализ требований: сбор функциональных, нефункциональных требований и ограничений проекта.

  • Документирование и визуализация требований: форматы SRS, BDD; диаграммы BPMN, ERD, Use Case.

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

  • Работа с изменениями: оценивание влияния изменений, ведение версионного контроля.

  • Валидация требований: проверка, что требования являются полными, однозначными и тестируемыми.

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

  • Поддержка требований: актуализация требований по мере реализации.

Архитектура

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

  • Понимание требований: обязательное учитывание функциональных и нефункциональных требований, выставление приоритетов критичным нефункциональным требованиям.

  • Применение архитектурных принципов: Single Responsibility Principle (SRP), Separation of Concerns (SoC), High Cohesion and Low Coupling и других.

  • Выбор подходящей архитектуры: монолит, микросервисы, event‑driven и т. п.

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

  • Учет отказоустойчивости: учёт сбоев, применение Failover, Circuit Breaker Pattern.

  • Модульность и повторное использование: построение системы на основе модульных компонентов.

  • Документирование архитектуры: создание артефактов, описывающих архитектуру, применение архитектурного репозитория.

  • Учет безопасности: проработка аутентификации и авторизации, шифрования, минимизации поверхностей атаки.

  • Управление данными: выбор подходящего типа базы данных, создание артефактов архитектуры данных.

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

Исходный код

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

  • Читаемость кода: использование осмысленных имён переменных, функций, классов; написание структурированного кода, соблюдение единого стиля форматирования.

  • Комментирование, документирование и самодокументирование: написание комментариев в частях кода, который сложен для понимания, назначение имён функциям и классам, которые отражают суть выполняемых действий.

  • Модульность и микроархитектура: разделение кода на небольшие модули, которые делают одну задачу, применение общеизвестных паттернов.

  • Автоматическое тестирование: автоматизация тестирования через модульные, интеграционные и регрессионные тесты.

  • Мониторинг и логирование: включение механизмов телеметрии в разрабатываемый код.

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

  • Производительность: написание эффективного кода, избегание лишней траты памяти, но без преждевременных оптимизаций.

  • Статический анализ: использование линтеров и статического анализа кода.

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

DevOps-процессы

Лучшие практики DevOps помогают повысить эффективность, автоматизировать рутинные задачи и улучшить взаимодействие между командами:

  • Автоматизация процессов: сборка и тестирование, CI (Continuous Integration); развёртывание, CD (Continuous Delivery/Deployment).

  • Инфраструктура как код (IaC): программное управление инфраструктуры, контроль версий.

  • Управление конфигурацией: централизованное управление конфигурацией.

  • Мониторинг и логирование: настройка журналирования, мониторинга, создание оповещений для ключевых событий (превышение нагрузки, ошибки и т. п.).

  • Тестирование на всех этапах: использование инструментов для тестирования инфраструктуры (примеры: Test Kitchen, Inspec).

  • Безопасность (DevSecOps): сканирование кода и контейнеров на уязвимости.

  • Стандартизация процессов: разработка шаблонов и стандартов для репозиториев, CI/CD‑конвейеров, управления инфраструктурой.

Жизнь с техническим долгом

Технический долг становится инструментом, когда его:

  1. Берут осознанно, с пониманием рисков и выгод.

  2. Документируют и управляют как любым другим ресурсом.

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

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

Осознание проблемы:

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

  • Проинформировать людей, участвующих в проекте (руководство, аналитиков и менеджеров по продукту), о существовании понятия технического долга и способах управления им.

  • Создать категорию или метку «ТехДолг» в системе управления задачами.

  • Включить известный технический долг в долгосрочные планы.

Подготовка и проведение анализа системы на наличие технического долга:

  • Создать стандарты для кода, архитектуры и инфраструктуры, которые будут служить мерилом для оценки технического долга.

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

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

  • Организовать мозговые штурмы и интервью вокруг вопросов: «Какое решение в архитектуре мы приняли, о котором сейчас жалеем, так как оно обходится нам дороже, чем мы рассчитывали?» или «Если бы мы сделали это снова, что следовало бы изменить?».

Фиксация найденного технического долга и подготовка критериев его устранения:

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

  • Разработать стратегию для приоритизации работы над устранением долга.

  • В процессе разработки добавлять элементы осознанного технического долга в систему управления задачами сразу после решения о его возникновении.

Разработка плана устранения технического долга:

  • Оценить не только стоимость погашения технического долга, но и стоимость его непогашения.

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

  • Приоритизировать элементы технического долга, начиная с тех частей кода, которые наиболее активно изменяются.

Материалы

Автор: T1_IT

Источник

Оставить комментарий