- PVSM.RU - https://www.pvsm.ru -
Практики управления техническим долгом в отдельно взятой команде
Примерно год назад наша команда перешла из фазы ускоренного наращивания функциональности к более плавной разработке с упором на повышение качества. К этому моменту в наших продуктах накопилось заметное количество неоптимальных решений, некрасивого кода, устаревших библиотек. Со всем этим надо было что-то делать.
К сегодняшнему дню удалось выстроить процесс, который делает борьбу с техническим долгом предсказуемой, безболезненной и неизбежной.
Что удалось получить в результате:
Давайте расскажу, как мы этого добились.
Мое рабочее определение технического долга — это количество работы, которую необходимо выполнить, чтобы проект соответствовал представлениям команды о прекрасном. Заметьте, что технический долг может возникать не только за счёт либерального применения костылей в разработке, но и за счёт изменения представлений о прекрасном. Например, изменились общепринятые практики в индустрии. Или разработчики разлюбили ООП и полюбили функциональное программирование. Или когда-то модный фреймворк уже не торт и стало сложно найти специалистов, которые хотели бы на нём писать.
Впрочем, основная причина технического долга — энтропия во всем своем разнообразии. Отключенные юнит-тесты, устаревшие комментарии, потерявшие связь с кодом, неудачные архитектурные решения, реализация фич, которыми больше никто не пользуется, задел на будущее, которое не наступило и многое-многое другое.
Из этого следует, что появление технического долга неизбежно в любом долгоживущем проекте.
Чем плох технический долг? Он увеличивает стоимость дальнейшей разработки за счёт ряда факторов:
Эти потери иногда называют «процентами по техническому долгу»
Бывают ситуации, когда эти потери обходятся дешевле, чем устранение технического долга:
Стремление успеть в завтрашний дедлайн любой ценой, в ущерб скорости разработки послезавтра.
Иногда быстровозводимая конструкция из костылей — объективно правильный выбор. В моей практике это было ярче всего выражено при изготовлении демоверсий к выставкам. Дата мероприятия жестко зафиксирована, если не успел к важной выставке — следующая попытка будет через год. Показывать продукт при этом можно «из рук», аккуратно обходя все баги. Мне, как инженеру, делать такие проекты неприятно, но костыли в них оправданны.
Когда делаешь продукт, который будет жить долго, всё по-другому. Успеть в срок за счёт сомнительных технических решений — дорогое удовольствие. Полная стоимость складывается:
Второй пункт очень легко недооценить, а про третий, самый дорогой, есть риск не подумать совсем.
Когда встречаешь на конференции техлида с дергающимся глазом, может оказаться, что именно кошмар бесконечной отладки конструкции из костылей привел его в такое состояние.
Чем хуже ситуация с техническим долгом, тем сильнее искушение похоронить весь код проекта и написать всё заново. Это одна из классических ошибок, способных убить весь проект.
Тема настолько хорошо раскрыта в известной статье Джоэля Спольски, что не вижу смысла приводить своих аргументов.
Things You Should Never Do, Part I [1]
Аргументировать необходимость устранения технического долга с проекцией на выгоду бизнесу не всегда просто. У команды разработки может возникнуть соблазн обойти острые углы и начать крупный рефакторинг явочным порядком. Сделать это можно в нерабочее время, в паузах между другими задачами или «на хвосте» у других задач за счёт раздувания оценок.
Что в этом плохого? О, целая куча вещей:
После применения командой этого рецепта глаз начинает дергаться уже у менеджмента.
Существует ряд закономерностей из жизни задач в проектах:
Про эти вещи очень хорошо рассказывает Максим Дорофеев в своей «Технике пустого инбокса» [2]
Чтобы технический долг не копился, работы по его устранению стоит оформлять с оглядкой на принципы, перечисленные выше.
Все задачи, кроме самых мелких, заводятся в бэклоге. Так у них появляется шанс быть сделанными не только в свободное время, но и в рамках запланированных работ. Кроме того, такие задачи сложнее совсем потерять из виду — на бэклог смотрят чаще и пристальнее, чем на TODO в коде, бумажки на мониторе, заброшенные вики-страницы, залитые чаем салфетки со схемами и прочие источники информации.
Пока такие изменения остаются недорогими с точки зрения затрат разработки и объемов необходимого тестирования, мы можем постепенно улучшать свою кодовую базу, не отрываясь от выполнения бизнес-задач и не внося дополнительных рисков.
Если в лесу упало дерево, но этого никто не слышал, был ли звук? Если в проекте есть плохой код, но этот модуль никогда не потребуется менять, есть ли технический долг?
Я считаю, что когда программисту неприятно смотреть на какой-то старый модуль — это само по себе не очень большая проблема. Куда хуже то, что происходит, когда в этом модуле потребуется добавлять новую функциональность или расширять старую. По сравнению с внесением изменений в хорошо написанный код, такие задачи чаще (и сильнее) выходят за исходную оценку и содержат больше багов. Иногда намного больше. Чтобы защитить себя от проблем подобного рода, мы стараемся планировать рефакторинги так, чтобы они были сделаны перед написанием новой функциональности в том же месте.
Если изменения функциональности и рефакторинг кажутся небольшими — их можно делать вместе. Эмпирически подобранный размер задачи, для которой такой подход будет оптимальным — 3 дня работы одного разработчика и меньше. Когда видно, что работы больше, она разделяется на рефакторинг с сохранением текущего поведения и реализацию новой функциональности.
Таким образом, порядок работ по устранению технического долга определяется очередностью бизнес-задач в бэклоге.
У принципа «опора на бизнес-приоритеты» есть ещё одно применение. Одна из типичных проблем, от которой страдают разработчики, стремящиеся писать хорошо, — сложности с выделением времени на оптимизацию производительности, улучшение поддерживаемости или другие вещи, которые напрямую не фигурируют в плане работ. Для этих улучшений почти всегда можно найти бизнес-потребность. Кто не хочет, чтобы система работала быстрее, стабильнее, была дешевле в сопровождении? Все эти преимущества можно оценить и исходя из этой оценки — положить задачи на улучшение в бэклог, вместе с любыми другими.
Так что если вам хочется оптимизировать производительность, а приходится вместо этого править очередной скучный баг — возможно, вы просто не умеете объяснить пользу от оптимизации на понятном владельцу продукта языке.
Почти любой код, кроме написанного совсем недавно, немного отстает от актуального представления о прекрасном в области стиля и архитектуры. Когда нужно менять код в рамках какой-то задачи, хорошим тоном считается сделать все безопасные улучшения, которые возможны в затронутом участке. Что это может быть?
От таких улучшений ожидается, что они сделают код лучше, но не будут создавать ощутимого удорожания разработки или тестирования.
За счёт этого принципа качество кода понемногу повышается в фоновом режиме, даже в тех местах, где не планировалось отдельных рефакторингов. При этом чем чаще мы работаем над определенной частью системы, тем лучше код этой части. Приятный контраст с проектами, где больше всего времени разработчик проводит в частях с самым плохим кодом.
Один из базовых принципов SCRUM говорит, что в конце каждого спринта система должна приходить в стабильное состояние.
«К концу спринта инкремент должен быть готов, что подразумевает его соответствие критериям готовности скрам‐команды и готовность к использованию. Он должен быть готовым к использованию вне зависимости от решения владельца продукта его выпускать или повременить».
–SCRUM Guide [3]
Любые работы по устранению технического долга делаются с соблюдением этого принципа.
Большие преобразования обязательно декомпозируются так, чтобы любой отдельный этап можно было закончить за один спринт. Например, систему сборки мы меняли в два этапа (Angular 1.x: крадущийся webpack, затаившийся grunt [4])
Мы работаем с VCS по принципам, близким к классическому gitflow [5]. Разработка идёт в фича-ветках, тестирование там же. Как правило, такая ветка живет не дольше одного двухнедельного спринта. Ветка, живущая дольше, почти всегда приводит к дополнительным затратам.
Наш опыт четко подтверждает эту закономерность. Каждый раз, когда нам не удавалось закончить большой рефакторинг за две недели, это сопровождалось болью и страданиями. И чем дольше была задача и дольше жила открытая ветка, тем медленнее шла работа и тем больше было проблем.
Потребность всегда быть в нескольких шагах от стабильного релиза создает одну из самых сложных и интересных инженерных задач — поиск оптимальной декомпозиции стратегических планов. Масштабные изменения можно разложить на отдельные независимые шаги. Желательно так, чтобы начать получать пользу как можно раньше. Чем лучше проведена такая разбивка работ, тем больше шансов довести дело до конца.
Раз в релиз делаем подробное ревью технического бэклога:
При появлении бизнес-историй на горизонте делается технический анализ и с бизнес-историей связываются все технические истории, которые помогли бы в реализации.
При подготовке к планированию спринта:
Придя на роль лида в команду, я спросил каждого разработчика и QA, какие улучшения в продукте они больше всего хотят сделать. Большинство пожеланий было связано с техническими улучшениями платформы и рефакторингами. Как показал дальнейший опыт, все ключевые технические проблемы продукта вошли в этот набор пожеланий. Так что этой практикой можно пользоваться, чтобы быстро сформировать технический бэклог с нуля или получить общее представление о состоянии с техническим долгом в новом для вас проекте.
Текущее наполнение бэклога техническими задачами происходит за счёт описанных выше практик и не требует отдельных усилий или анализа. Помимо этого, в бэклог добавляются все новые идеи по техническому совершенствованию продукта. Это делает любой член команды, которому такая идея пришла в голову. Главное на этом этапе — не потерять идею. Уточнение и определение приоритета происходят уже потом, в ходе планирования работ.
Автор: alexanderlebedev
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/scrum/263443
Ссылки в тексте:
[1] Things You Should Never Do, Part I: https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/
[2] «Технике пустого инбокса»: http://mnogosdelal.ru/courses/dovedenie-del-do-kontsa/
[3] –SCRUM Guide: https://www.scrumguides.org/docs/scrumguide/v2016/2016-Scrum-Guide-Russian.pdf
[4] Angular 1.x: крадущийся webpack, затаившийся grunt: https://habrahabr.ru/company/ncloudtech/blog/321584/
[5] gitflow: http://nvie.com/posts/a-successful-git-branching-model/
[6] Источник: https://habrahabr.ru/post/337308/
Нажмите здесь для печати.