Привет! Меня зовут Дима Симушев, я технический руководитель юнита Fashion&Electronics в Авито. И это ещё одна статья про управление техническим бэклогом. В отличие от многих других статей, я не хочу фокусироваться на классификации и причинах появления техдолга. Вместо этого расскажу про комплексный подход по управлению техническим стримом команды. Это один из инструментов тимлида, который помогает удерживать сервисы от энтропии и скатывания в дремучее легаси.

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

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

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

Что такое технический бэклог

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

Если вам интересно чуть больше узнать о именно о техдолге, обратите внимание на статьи Technical Debt и Technical Debt Quadrant Мартина Фаулера, а также Mess is not a Debt Роберта Мартина. В них есть хорошее описание техдолга и как его можно категоризировать.

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

Мы не смешиваем техдолг и продуктовые фичи. Ресурс команды распределяется в некоторой пропорции между техническими и продуктовыми задачами, которые мы приоритезируем независимо.

Если нам пришлось отрезать какую-то продуктовую функцию, потому что не укладывались в сроки — это не техдолг и не часть технострима. Это часть продуктового бэклога, а значит, и ответственность за управление этими задачами лежит полностью на продакт-оунере. С другой стороны, если при работе над продуктовой задачей мы осознанно отрезали мониторинг или алертинг, то это часть технического бэклога.

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

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

Итак, в технический стрим входят:

  1. Техдолг;

  2. Задачи на рефакторинг систем;

  3. Задачи на обновление библиотек;

  4. Стратегические технические проекты, направленные на увеличение стабильности системы, её наблюдаемости и поддерживаемости.

Наполняем технический бэклог

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

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

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

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

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

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

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

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

Бывает и так, что все решения оправдали себя, но вам всё равно не хватает инструментов, чтобы быстро обнаружить и локализовать проблему:

  1. Нет метрик или алертов на эти метрики.

  2. Мало логов или наоборот их настолько много, что важная информация теряется в общем потоке бесполезных событий.

  3. С количеством логов всё нормально, но вы не можете сопоставить вызовы в разных микросервисах так, чтобы восстановить правильный поток выполнения запроса пользователя.

Во всех случаях вы с помощью разных трюков сможете найти и исправить дефект. Времени и сил на это уйдет много, но вы же не зря нанимали такое количество senior-инженеров, не правда ли? Чтобы упростить отладку в будущем, вам нужно хорошенько поработать с кодом и добавить недостающие инструменты мониторинга и отладки. Каждое улучшение на этом пути — отличный кандидат для технического бэклога.

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

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

Оцениваем размер технобэклога

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

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

Если вы работаете спринтами, то уже знакомы с механикой оценки задач. Сложность управления техническим бэклогом в том, что в нём очень много задач со средним и низким приоритетом. Это значит, что до командной оценки всех технических задач вы доберётесь очень нескоро. В лучшем случае вы сможете оценить какое-то небольшое число наиболее приоритетных задач. Но сколько всего у вас в техническом бэклоге и как меняется его объем со временем? И тут мы входим в серую зону допущений разного уровня правдоподобности.

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

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

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

Общий объем технобэклога удобно измерять в количестве спринтов, которое потребуется для полного его устранения. Обычно я стараюсь держать объём технического стрима в пределах 1-1,2 двухнедельных спринтов. Это то количество, которое команда способна устранить за квартал, уделяя на технические задачи 20% времени каждый спринт. Задачи внутри технострима могут меняться: какие-то успешно закрываются, какие-то создаются в результате компромиссных решений. Не обязательно закрывать абсолютно все задачи, но обязательно контролировать предельный объем технического бэклога.

Если в какой-то момент объём технострима становится больше, чем на 1,5 спринта — мы договариваемся с продактом о выделении дополнительного времени. Если технобэклог становится существенно меньше — мы можем больше времени уделять продуктовым задачам и сократить лимит ёмкости под технострим с 20% до меньшего значения.

Теперь, когда у вас есть понятная метрика, вы можем оценить, где вы сейчас. Я встречал две наиболее популярные ситуации: у команды практически пустой технический бэклог или в нём очень много задач. Если с большим размером технострима все понятно, то очень маленький его объём говорит скорее не об отсутствии проблем, а о том, что команда вообще не заводит технические задачи на улучшение внутреннего качества продукта. О том, где можно поискать задач для технострима я уже рассказал выше в статье.

Лучше всего, когда у команды есть технобэклог, но его объем находится в пределах нормы (общая емкость — 1-1,2 спринта). Такие средние значения на моей практике встречались редко и обычно свидетельствовали о том, что команда уже умеет управлять техническим бэклогом, хотя и может делать это неосознанно. Если это ваш случай, подумайте, что можно сделать для перехода к осознанному процессу, ведь явное лучше неявного.

Создаём меньше техдолга

Иногда в момент анализа ситуации команды понимают, что у них есть серьезные проблемы. Объем технического бэклога в 6-7 спринтов означает, что даже если прямо сейчас вы полностью остановите всю продуктовую разработку, то только через квартал у вас получится избавиться от техдолга.

Первое, что нужно сделать в такой ситуации — перестать генерировать техдолг.

В этот момент вам стоит обсудить с заказчиками классический компромисс скорость-качество. На самом деле такого компромисса не существует, но это тема для отдельной статьи. Именно сейчас вам придётся начать говорить «нет» заказчикам и их некачественно проработанным инициативам. Чем меньше углов вы будете срезать в дальнейшем — тем меньше будет поводов для увеличения размера технического бэклога. Так вы сможете снизить количество техдолга, который брали на себя осознанно.

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

Подумайте о технической стратегии развития продукта и определите целевую архитектуру. Набросайте несколько верхнеуровневых документов о том, как вы эту архитектуру видите. Определите вместе с командой набор базовых принципов, которые помогут не создавать дополнительных проблем в коде. Формализуйте их в виде гайдлайнов (dos & don'ts). Они помогут вам поддерживать качество в будущем.

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

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

Если у вас вообще нет тестов и нет времени чтобы обеспечить хорошее покрытие юнит-тестами, начните с примитивных api-тестов. Это не займёт у вас много времени, но поможет зафиксировать зелёные сценарии. Такой подход критически важен для безопасного рефакторинга, к которому вы обязательно придёте при разборках с техдолгом. Грамотная стратегия автоматизации тестирования легаси проектов выходит за рамки этой статьи, но вы можете получить представление о базовых подходах из книги Майкла Физерса «Эффективная работа с унаследованным кодом».

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

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

Разбираем существующий технобэклог

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

За управление технобэклогом должен кто-то отвечать. Отдавать управление всей команде сразу — не лучшая идея. Да, такой подход может сработать, но для успеха команда должна быть очень зрелой и ответственной. Увы, в большинстве случаев это не так, поэтому хорошенько подумайте, кто будет отвечать за технический бэклог.

В моих командах таким ответственным часто становился кто-то из senior-инженеров. Он получал возможность поуправлять реальным бэклогом, пусть и техническим. Это хороший шаг на пути к роли тимлида, где придётся вместе с продактом поддерживать уже весь бэклог задач команды. А для меня это хорошая возможность делегировать рутинные операции и заняться чем то-то более важным.

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

Если так получилось, что у вас не нашлось подходящего senior-инженера, то владельцем бэклога автоматически становится тимлид и весь процесс остаётся в его прямом управлении.

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

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

  2. Подготовка задач и груминг: все задачи должны быть описаны и понятны команде.

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

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

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

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

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

Вместо заключения

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

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

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

Предыдущая статья: Семантики доставки событий в распределенных системах

Комментарии (2)


  1. alexrozen
    29.08.2023 09:36

    Если у вас вообще нет тестов и нет времени чтобы обеспечить хорошее покрытие юнит-тестами, начните с примитивных api-тестов. Это не займёт у вас много времени, но поможет зафиксировать зелёные сценарии

    А api-тесты бывают более затратны в написании и поддержке, чем unit, т.к. отражают и внешние условия и внутреннюю бизнес-логику.

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


    1. justblackbird Автор
      29.08.2023 09:36
      +3

      Тут есть нюанс: несмотря на сложность api-тестов покрыть основные зеленые сценарии ими проще, чем юнитами. Причина очень простая - api-тестов нужно сильно меньше.