что такое технический долг
Что такое технический долг
Фраза из лексикона сильных профессионалов
Есть понятие технического долга — это когда мы когда-то давно приняли компромиссные решения в разработке, а теперь у нас из-за этого проблемы.
Представьте стартап: например, приложение отслеживает ваш режим дня и расставляет задачи оптимальным образом. Разрабатывать такое приложение дорого, нужны деньги. Деньги не берутся из воздуха — их дают инвесторы. Инвесторы хотят, чтобы деньги вернулись как можно скорее, а для этого нужно как можно скорее запускать приложение.
Из-за скорости команда разработчиков принимает такие решения:
Эти решения — предвестники технического долга. Сегодня благодаря им приложение выйдет быстро, а через год разработка будет существенно буксовать, если этот технический долг не вернуть.
Что такое технический долг
Технический долг — это общее название для тех задач, которые отложили ради скорости. Слово «долг» означает, что разработчикам придётся в будущем что-то делать с нынешним кодом и исправлять то, что сделано на скорую руку.
Например, сегодня мы за пять минут «захардкодили» API и не предусмотрели его расширяемость. Через год API всё же придется расширить. Тогда разработчикам придется углубляться в старинный код, разбираться в старых кишках. А помните, что они ещё и не задокументированы? В общем, это надолго.
Откуда ещё появляется технический долг
В нашем примере весь технический долг появился из-за спешки. Это самая частая причина появления долга. Сделать софт из хардкода и палок всегда быстрее, чем заложить нормальный фундамент.
Ещё технический долг появляется, когда в команде не делают код-ревью и не проверяют качество и стиль программирования. Это может привести к ошибкам, на которое придётся тратить время в будущем.
Также долг может появиться просто из-за отсутствия квалификации и опыта у программистов. Например, вместо того чтобы взять готовое решение и использовать стандартную библиотеку, разработчик пишет свою систему аутентификации. Но из-за незнания нюансов в такой системе могут появиться ошибки, из-за которых придётся всё переписывать.
Что делать с техдолгом
Технический долг нужно возвращать с процентами.
Самый рабочий и продуктивный подход — закладывать время в разработке на исправление и доработку того, что было брошено. Чем больше технического долга есть в коде, тем дольше и сложнее выходит каждая новая версия программы. Иногда такого долга становится так много, что приходится создавать новую версию практически с нуля, учитывая все прошлые ошибки.
Технический долг и места его обитания
Эта статья — вольный пересказ доклада, который я посетил на конференции GOTO Berlin 2017: A Crystal Ball to Prioritize Technical Debt.
Изображения из доклада и права на них принадлежат автору @AdamTornhill.
Каждый разработчик в принципе понимает, что такое технический долг. Что в его проекте этот долг наверняка присутствует. Если повезет, он вспомнит несколько кусков кода, которые давно просятся быть переписанными.
Но как формализовать понятие технического долга, чтобы объяснить его другим? И, тем более, объяснить это менеджеру так, чтобы получить одобрение на рефакторинг? Как найти все места в проекте, которые нужно по-хорошему переписать, и как определить, какие из них должны быть переписаны в первую очередь?
Если эти вопросы неоднократно у вас возникали, прошу под кат.
Не весь коряво написанный код по определению является техническим долгом. Конечно, если есть такой код, то его лучше рано или поздно переписать. Но все мы знаем, что полировать код можно чуть ли не до бесконечности. Как же определить, какой код является техническим долгом?
Довольно хорошее описание технического долга дал Мартин Фаулер:
Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice.
То есть, чем больше усилий во время разработки мы затрачиваем из-за какого-то куска кода, тем большим техническим долгом он является. С этим сложно не согласиться, но все же этого недостаточно для того, чтобы четко определить, какие места должны быть переписаны.
Для того, чтобы оценить, насколько каждый конкретно файл/класс/функция затрачивает наши усилия при разработке, Адам вводит такое понятие, как горячие точки, Hotspots. И для поиска этих хотспотов нужен только один инструмент, который есть практически у каждого разработчика — система контроля версий.
Оценить количество усилий на поддержку файла с кодом можно, взглянув на то, как часто этот файл меняется, и на то, какая сложность у этого файла. С оценкой частоты изменений все однозначно и понятно. Сложность можно оценить разными способами, в зависимости от ваших предпочтений. В простейшем случае это может быть размер файла или количество строк кода. При прочих равных условиях поддерживать файл на 100 строк кода сильно проще, чем файл на 1000 строк кода. Если же размер файла в вашем случае не является критерием оценки сложности, можно воспользоваться различными утилитами для статической оценки сложности (например, цикломатической).
Тогда хотспоты можно будет выявить следующим образом:
Вот пример поиска горячих точек в проекте Tomcat:
Большие синие круги — это папки. Маленькие — файлы.
При всем этом, наличие хотспота совсем не означает, что этот файл проблемный (но чаще всего так и есть). Это означает, что в этих файлах вы проводите больше всего времени. И что при рефакторинге эти файлы должны быть первыми в списке, чтобы убедиться, что код там чистый, легко поддерживаемый и расширяемый.
Также в качестве примера приводятся графики анализа кода нескольких проектов, разных насколько это возможно. Разные языки, разное время жизни, разные компании-разработчики. По оси X у нас расположены файлы, по оси Y — частота их изменений.
У всех проектов наблюдается один и тот же паттерн. Большая часть кода расположено в «хвосте» графика. И соответственно, есть очень небольшая часть файлов, которые изменяются очень часто. Эти файлы тоже являются первыми кандидатами для рефакторинга.
При поиске хотспотов можно пойти глубже. И в проблемных файлах искать хотспоты уже на уровне отдельных функций:
Инструмент, который был использован для поиска таких хотспотов — codescene.io
Также полезной практикой будет регулярной отслеживание сложности вашего кода. Анализ таких данных в виде графиков будет очень наглядно показывать, в какие моменты вы сбились с верного пути.
Итоги
Мне этот доклад показался полезным в первую очередь из-за четкого определения технического долга и его размера.
Понятно, что чтобы заниматься таким серьезным анализом кода с выявлением хотспотов, это нужно очень сильно увязнуть в технических долгах. Но даже на базовом уровне, в повседневной работе, я стал обращать внимание на классы, которые чаще всего затрагиваю, и стараюсь такие классы потихоньку рефакторить.
Также, в качестве бонуса (был вопрос из зала на докладе), Адам рассказал, как правильно доносить до менеджмента необходимость в рефакторинге. Чаще всего менеджеры — не технические люди, довольно далекие от кода, иначе бы проблем не возникло. Но что эти люди хорошо понимают — это цифры и графики. Чтобы правильно донести до них информацию, нужно говорить с ними на одном языке. И как раз графики с хотспотами и временной зависимостью сложности кода могут тут помочь. На графиках можно показать, что вот такой-то функционал, который мы добавили недавно, сильно усложнил добавление новых фич. Следовательно, если мы в дальнейшем хотим ускорить темпы разработки, нужно потратить сколько-то времени на рефакторинг.
Андрей Ребров: Технический долг в процессах разработки
Недавно Андрей Ребров поделился в фб со своими читателями своим выступлением про «Техдолг в процессах разработки». С его разрешения, в рамках написания книги про выпускников YC, публикую тут его конспект.
Всем привет, я в разработке с 2008 года. С 2013 года я создаю технический долг в стартапе ScentBird (YC S15), где я являюсь сооснователем и техдиректором. Так же я технический консультант (помогаю техдиректорам) нескольких стартапов — в космической и игровой индустриях.
У нас в компании 40 человек в разработке (Engineering), Product Engineering — 55, общее число сотрудников — 160 человек.
Технический долг — ранее написанный код, который замедляет разработку новых возможностей продукта и как следствие замедляет развитие бизнеса.
Откуда берется технический долг
Мы у себя в компании пришли вот к какому решению для работы с техническим долгом.
Важно правильно сопоставлять задачи по техническому долгу с другими задачами по разработке. Для команды, по-хорошему, не должно быть большой разницы, работают ли они над бизнес-фичой или над техническим долгом.
Для больших задач по техническому долгу мы ввели «технический бриф».
Для любой задачи больше недели мы начинаем делать технический бриф. Это двухстраничный документ, который объясняет, какую мы решаем проблему, а не просто играемся с технологией (R&D).
Очень важно описать, что же будет являться критерием успеха для данной задачи. «Давайте перепишем» — не подходит.
Что мы будем менять? Насколько далеко мы полезем со своими изменениями?
Например, в начале этого года мы внедрили Кафку, при том что у нас был RabbitMQ. сделали мы это специально для задач команды дата инжиниринга, которая занимается нашей аналитикой, отправляет ивенты во внешние системы для отправки писем, пуш-нотификаций, внешней аналитики. Они все сравнили и Кафка подходила лучше всего. Надо протаскивать не любимую технологию, а технологию, которая решает задачу.
В документе мы указываем команды, которые будут участвовать в проекте, и команды, которые надо проинформировать, что произошло изменение.
С таким брифом можно уже приходить к product owner или ЛПР.
RACI Matrix
После этих шагов невозможна ситуация, что кто то скажет: «А меня не поставили в известность».
Очень классный артефакт. Всем кто находится в инженерном менеджменте крайне советую, очень сильно помогает расставить точки над «i».
Когда у вас есть бриф, вы можете достигнуть «единый роадмап».
Единый роадмап
Пару лет назад у нас была следующая ситуация: мы только учились правильно управлять продуктом, правильно управлять разработкой и у нас было несколько роадмапов. У продуктовиков — про фичи, У разработки — фронтенд, бэкенд, SRE, QA automation. Естественно, были вопросы «стыковки», кто делает, кто принимает решения.
Единый роадмап показывает всю ситуацию — чем мы занимаемся в каком порядке, куда направляются человеческие ресурсы.
В нашем роадмапе есть проекты разного размера: стратегические инициативы (большие активности с несколькими департаментами для максимальных показателей по подписчикам, выручке и тд), есть инфраструктурные проекты (склад, интеграция внешних ERP).
Это позволяет видеть, как маленькая задача (про технический долг) продвигает стратегическую задачу. Так же это облегчает задачу продать технический долг.
Умение общаться с бизнесом на языке бизнеса, а не на языке разработки (как бы вам этого не хотелось)
Подведение итогов
Выяснить, что то, куда вы пришли — это то куда вы хотели прийти. Стал ли продукт лучше работать? Стал ли он более стабильным? Можно ли теперь скейлиться? Иногда это очень сложно посчитать.
Мы сейчас переходим со SpringBoot на Micronaut, чтобы проще запускать обвязку сервисов машинах разработчиков и для ускорения локальной компиляции. Конечная цель — повысить эффективность разработчиков. Померить эффективность разработчиков сложно. Померить уровень удовлетворенности разработчиков сложно, но можно, это «тонкая материя». Можно померить сколько используется памяти, стартап-тайм. Мы договариваемся об измеримых метриках и их мерим.
Следующий этап — презентация команде и бизнесу. Это может быть большой круг. В нашем подпроекте по переходу на другую платежную систему у нас были регулярные презентации бизнесу: что сейчас происходит, решили ли мы проблемы, насколько стабильна новая платформа. «Смотри, наш лид-тайм уменьшился и это здорово.»
презентация команде имеет другой смысл — это в первую очередь обмен опытом, знаниями и решение той самой проблемы про bus-фактор — перейдя на новую технологию нужно чтобы как можно больше людей знали, как ей пользоваться правильно и в рамках нашей компании.
Следующий пункт — очень важно отпраздновать.
Очень часто мы находимся в потоке, делая одну задачу за другой, и вдруг мы понимаем, что мы не испытываем удовлетворения от своей работы: да, мы делаем крутые проекты, мы решаем интересные задачи, у нас интересный коллектив, но… чувства радости нет. Важно, когда мы закрываем очередную задачу по техническому долгу собраться разработчиками за кружечкой чая и обсудить как это выходило, какой опыт получили и что делать дальше. Об этом важно помнить. Успехи надо праздновать.
Вопросы
— Как синхронизировать роадмапы команд?
Я не могу сказать, что мы достигли совершенства, у нас третий подход к тому как делать роадмапы, скорее всего не последний. В сентябре, мы как менеджмент, определили куда мы движемся как компания. Выбранные направления начали формироваться в продуктовые брифы, начинают описываться: цель, как будет работать и тд. Параллельно я работая с техлидами и тим лидами: вот смотрите, куда компания хочет прийти в следующем году, что нам необходимо с точки зрения разработки, какой технический долг убрать, а где заранее проинвестировать в нашу платформу, чтобы наша платформа позволила прийти в нужную точку. И так появляются технические брифы. Когда и те и те брифы готовы, мы сходимся вместе — превращаем брифы в более точные и понятные проекты с точки зрения практического решения задач. Мы используем Story Mapping — когда из описания процессов и flow появляются отдельные индивидуальные задачи.
В следующем году мы будем делать экспансию в новый для нас регион. Мы понимаем, что нам для этого нужно внедрить Tenants в базы данных, пересмотреть то, как мы делаем инфраструктуру, вещи с управление данными, GDPR. Мы поговорили про функциональные сценарии, про пользователей, а есть еще вещи связанные с системой, давайте о них поговорим и опишем. Начинают появляться задачи из технического брифа.
После этого у нас есть все задачи на доске, мы начинаем планировать по фазам и заносим в бэклог. В рамках этого сторимапа мы планируем выход в новый регион, для нас эта задача связана с основным сайтом, мобильными приложениями, системой управления складом, платежным шлюзом. Как раз здесь происходит синхронизация по командам: какая команда и какой объем задач будет выполнять.
Когда сторимапы готовы, когда у нас есть понимание, что мы будем делать и когда она теоретически закончится (мы используем грубые оценки на этом этапе), после этого задачи ложатся на роадмэп, мы используем цветовое кодирование, у нас есть Swimlane выхода в новый регион, дальше в рамках него разными цветами подсвечиваются задачи разных команд и дата их начала. Каждый квартал мы делаем встречу и пересматриваем наш роадмап. Такой подход мы используем сейчас, посмотрим, что мы будем думать в первом квартале следующего года.
— В чем оличие от OKR?
OKR будут в нашей продуктово-инженерной команде. Мы не являемся техническим бизнесом (мы не Docker), технологии для нас вспомогательны, у нас есть масса дополнительных подразделений: операционка со складом, бизнес-девелопмент, дизайн. Вводить единый ORK на всю компанию очень сложно.
Технический долг? О чем вы вообще говорите?
Что такое технический долг?
Если вы попытаетесь поискать ответ на этот вопрос в интернетах, то обнаружите чушь вроде этой: «Технический долг – это долг, который накапливается из-за принятия неидеальных технических решений, и должен погашаться через рефакторинг.» Неидеальных?! Кто видел идеальные решения хоть где-либо? И как оценить расхождение с идеальным решением? Нет! Это все словоблудие, беспредметный треп ни о чем!
В ТРИЗ (теории решения изобретательских задач) существует понятие идеального объекта: Идеальный объект – это объект, которого нет, но функция которого выполняется. Если взять это определение идеального, то весь код, что мы пишем – сплошной технический долг. Но в чем его измерять? В строках? В выражениях? В сложности синтаксического дерева или в количестве вершин и граней графа вычислений? Это сложный и запутанный путь в никуда!
Так что же такое технический долг? (дубль два)
Технический долг – это осознанное и задокументированное решение не делать что-то сейчас. Допустим, есть компания, и у нее есть множество аккаунтов сотрудников. Пока все хорошо и просто. Но! Сотрудник ведь может быть в нескольких компаниях! Как ему между ними переключаться? Или стоит объединить данные из нескольких компаний на одном единственном рабочем экране?
Отвлечемся немного от этой задачи. Действительно ли мы сейчас должны принимать какое-либо решение о реализации? Или мы можем инвестировать время и другие ресурсы во что-то более важное? Каким вообще образом все эти переключения или агрегация данных из нескольких компаний могут принести нашей собственной компании прибыль? Это ли то, что мы продаем? Интересно ли нам этим заниматься? Ответ: Нет! Это не создает ценности, но лишь улучшает опыт сотрудников в достаточно редких случаях. При этом, наш клиент — компания, а не сотрудник. Нам важно, чтобы был счастлив тот, кто платит деньги, а не какой-то случайный человек. В противном случае мы ничего не добьемся в попытках всем угодить. Так и запишем:
Этому все еще нельзя присвоить численную оценку, да и не нужно. Быть может, мы никогда не дойдем до необходимости погашать этот технический долг. Мы задокументировали это решение и время от времени вспоминаем о нем, мы даже можем дописывать к нему пожелания клиентов о реализации такой возможности, однако это вовсе не обязывает нас его «погашать». Мы просто помним о принятом нами решении, помним его аргументацию и дописываем в него пожелания пользователей или связанные с ним НЕ-технические проблемы, вроде: “Компания X отказалась от подписки на наш сервис по причине отсутствия данной функциональности. Контракт мог бы приносить нам
Теперь многим, кто ошибался насчет технического долга, должны стать понятны следующие моменты:
1. В большинстве случаев “технический долг” подразумевает не технический долг, а низкое качество кода и отсутствие культуры у разработчиков.
2. Технический долг вовсе необязательно погашать. Более того, большую его часть лучше вообще никогда не погашать, потому как погашение непременно увеличит сложность проекта, создаст новые дефекты и векторы атаки.
3. Технический долг – это часть корпоративного нарратива. Если вы его никак не документируете, ваша компания находится в полубредовом состоянии.
4. Технический долг помогает концентрироваться на главном, а во времена затишья создавать побочные продукты или расширять долю рынка.
Стратегии выплаты технического долга
Технический долг: он есть у всех, и каждый достойный своего звания разработчик хочет его выплатить, но как же организовать этот процесс?
Реализуем севооборот
В своей предыдущей статье я сравнил выплату технического долга с важностью севооборота в сельском хозяйстве. Если вы продолжаете обрабатывать поле (кодовую базу) сезон за сезоном, чтобы получать большой урожай (завершать проекты, добавлять фичи и т.п.), и не даёте этому полю сезон на восстановление (выплату технического долга), то оно постепенно начинает терять своё качество и урожайность.
Эта метафора остаётся подходящей и для разработки ПО; кроме того, она содержит в себе намёки на возможные стратегии, которые можно использовать для выплаты технического долга.
Существует на удивление широкий диапазон способов выплаты долга. И это очень полезно, поскольку предоставляет нам множество вариантов при планировании.
В рамках этой статьи мы будем предполагать, что вы работаете в методологии agile-разработки, однако многие принципы при условии творческой переработки применимы и к другим методологиям.
Специальные спринты для выплаты технического долга
В полной аналогии с севооборотом мы можем прекращать работу над фичами на каждый четвёртый спринт или около того, выделяя его только для выплаты технического долга.
Плюсы:
Выделенные Capacity для выплаты технического долга
В такой модели agile-команда резервирует определённое количество поинтов или процент от общей capacity спринта для выплаты технического долга на постоянной основе. Например, в каждом спринте команда может брать 5 сторипоинов разнообразной работы по выплате долга.
Плюсы:
Выделение сотрудников на выплату технического долга
Это гибрид двух последних вариантов. В каждом спринте выбирается один разработчик для работы над техническим долгом, в то время как все остальные продолжают заниматься своей обычной работой.
Плюсы:
Выплата технического долга после завершения работы
В такой модели при планировании разработчиками работы они вносят в план подчистку соседнего кода и выплату обнаруживаемого технического долга, уже находящегося в области работы. Это соответствует принципу бойскаутов: всегда оставляй стоянку (кодовую базу) чище, чем она была до тебя.
Иными словами, это подразумевает, что когда ты касаешься кода, он должен становиться лучше. В коде, которого касаются чаще всего, нужно выплачивать наибольший процент по техническому долгу, поэтому логично выплачивать долг в тех областях кода, над которыми ты работаешь.
Похожая концепция приведена в книге Малкольма Глэдуэлла The Tipping Point, где приводится пример с метро Нью-Йорка. Управление городского транспорта выяснило, что если отцеплять вагоны метро, очищать их от граффити и обеспечивать постоянное отсутствие граффити, то можно сэкономить на эффекте разбитых окон, при котором люди считают, что состояние вагонов никого не волнует и уровень преступности может увеличиваться. Сокращая количество «зайцев» и граффити, управление могло также снизить количество насильственных преступлений в метро.
Если перенести тот же принцип на нашу кодовую базу, то нужно сделать так, что при касании областей кода они подчищались и выплачивался технический долг.
Вероятно, из прочитанного выше вы могли догадаться, что я фанат данного подхода, но давайте всё-таки рассмотрим его плюсы и минусы.
Плюсы:
Крупные переработки кода
Выше я рассказывал о стратегии выплаты технического долга путём постепенной замены частей системы, как в мысленном эксперименте с кораблём Тесея, но что если этого недостаточно? Что если у вас нет времени заменять всё ПО часть за частью и вам нужно внести более радикальные изменений?
Вот несколько идей, которые могут вам помочь:
Разбиение приложения на более мелкие приложения
При такой методологии мы разбиваем монолитное приложение на мелкие приложения. Часто такой подход дополняется предметно-ориентированным программированием (Domain Driven Design) и/или микросервисами, но основной его смысл заключается в том, что если приложение слишком объёмно для замены, его можно разделить на меньшие части, замена которых реалистична, после чего можно заменять каждую часть, одну за другой.
Также эту схему можно реализовать с помощью шаблона Strangler Application Мартина Фаулера, при котором создаётся новое приложение, получающее те же запросы, что и старое, и осуществляющее вызовы к легаси-системам, пока для каждой из них не будет готова современная замена.
Плюсы:
Прототипирование приложений в резервной capacity
В такой модели разработчики могут использовать резервное время или время, выделенное на технический долг, чтобы работать над долговременными проектами, например, над заменой всего приложения или его части. Как только будет достигнут достаточный прогресс и можно будет серьёзно приступать к работе, эти задачи начинают внедряться в спринт или в серию спринтов для формальной реализации и поставки.
Действуя по этому шаблону, я очень успешно перенёс JavaScript-приложения на TypeScript, в том числе тратя на это время вне работы (не то, чтобы это было обязательно, но я решил сделать так) и ожидая вывода онлайн сред регрессивного тестирования.
Плюсы:
Полный переход к новому приложению
В этой модели вся работа над старым приложением прекращается, если не считать исправления критичных багов, и начинается работа над приложением, которое станет его полной заменой. Обычно именно это подразумевают люди, когда говорят о переписывании приложения.
Плюсы:
Минусы: