«Правильные JIRA issues». Как правильно разбивать задачи на тикеты
Я сейчас занимаюсь тем, что помогаю акаунту в несколько десятков разработчиков зарелизить проект качественно и в срок. Среди прочего у проекта есть проблема с разбиением задач на тикеты в JIRA. Просто для понимания масштаба — проекту год, разработчиков грубо говоря три дюжины, номер последнего тикета 12000+. При этом много тикетов с тегов investigate, много тикетов в результате которых создается pull request на 20 строк при том, что для достижения результата который «можно пощупать руками» (tangible) нужно 100 строк и остальные 80 строк размазаны по другим спринтам и другим командам. Это ведет к следующим проблемам
Все делается медленнее чем могло бы. Новый разработчик в новом спринте заново разбирается каким должен быть конечный результат и естественно тратит на это время
Разработчики вообще не разбираются каков конечный результат и просто имплементируют кусок из середины, мерджат PR и все. Как результат если хоть одна маленькая деталь в описании неточна, то есть хороший шанс, что в сборе все вместе не заработает и надо будет потом имплементировать
Масса дубликатов, т.к. целостной картинки ни у кого в голове нет, собрать ее по десяткам тысяч тикетов крайне сложно
Стиль имплементации одной end-to-end задача объемом в 100–200 строк кода существенно разнится, вплоть до использования разных библиотек для однотипных задач.
Задачу приходится описывать значительно более подробно, чем можно было бы. У меня есть впечатление, что в ряде случаев тимлидам быстрее все закодить, чем описывать, что надо сделать в JIRA
End-to-end тестирования либо вообще нет, либо оно происходит сильно оторвано от разработки через спринт, а то и через два от момента реализации первого тикета
Если что-то идет не так со сроками или с зависимостями, то имея в спринте сотню тикетов от разных эпиков распределенные по разным командам что-то спланировать, поменять или вообще в разумные сроки понять что будет сделано в конце спринта довольно сложно.
Мы обсудили это с коллегами из менеджмент команды, они попросили меня написать инструкцию (раз ты к нам с этим пришел, ты и пиши) как правильно разбивать большие задачи на тикеты. Я начал писать документ на confluence и понял, что текст дальше «делай хорошо и хорошо будет» двигается с заметным трудом. Более или менее полезная инструкция это уже прям целая статья. Собственно статью я и решил написать. Далее идет набор простых правил, которые я после публикации статью собираюсь объяснить командам. Набор правил несколько ситуационный и не содержит общую теорию всего, а скорее набор пунктов, которые я хотел бы улучшить из опыта работы в нескольких акаунтах за последние 2–3 года.
JIRA is just a tool
Самый важный момент, разбиение на тикеты вообще не самое важное. Одна из частых ошибок совершаемых при разбиении задач на тикеты это фиксация на тикетах. На самом деле нам не надо разбивать задачи на JIRA тикеты. Нам надо разбить общий объем работ на задачи для отдельных разработчиков, которые можно спланировать, сделать, протестировать и отгрузить в рамках одного спринта. Это основной приоритет. JIRA это инструмент который позволяет эти задачи удобно записывать и отслеживать. Но основа тут все же планирование, гранулярность задач и правильная формулировка задач. Я стараюсь внедрить в команды следующий порядок работы над новым функционалом (эпиками)
По большей части работа БА, определить, что в поведении системе изменится после того как эпик будет завершен. В виде документа на Confluence на который потом через 2 года можно будет сослаться и использовать для планирования изменений поведения системы
Работа тех лида, сделать документ, в котором описывается, какие изменения, каких компонентов системы для достижения пункта №1 надо произвести.
Работа ПМ-а и тим лида (в 90% случаев тим лид и тех лид это один человек) — создать для каждого гранулярного, независимого изменения каждого из компонентов JIRA тикет и запланировать порядок работ — кто из членов команды, когда и над чем будет работать.
К пункту №2 в большинстве случаев очень полезно иметь как минимум диаграмму компонентов и часто dataflow диаграмму.
Этот пункт ключевой, без планирования технической реализации вся остальная работа с JIRA превращается в тыкву.
Part of the story part of the release notes
В release notes спринта должны идти как можно более компактно формулируемые результаты. Одно из качеств тикета это соотношение его контракта (описание что надо получить в результате/acceptance criteria) к объему работы.
Например: (детали изменены и вообще из другого проекта) ProfileBridge сервис должен на входе принимать id пользователя оговоренного формата и на выходе возвращать профиль пользователя (openAPI описание структуры прилагается), который он запрашивает у одного из трех провайдеров.
Проверить что работает предельно просто, посылаем запрос, проверяем результат. Зависимости достаточно просты. Разработчику достаточно просто объяснить, что делать — вот варианты входных данных, вот API сервисов, вот что надо на выходе. Написать авто-тест дела пару часов, ну может быть дня, если структура большая и надо учитывать краевые случаи.
Понятно, что задача разбивается на пачку подзадач. Но если их делать небольшой скоординированной группой разработчиков из одной команды, регулярно проверять что и как делается и помогать делать похожие части однообразно, это вполне хорошая задача, которую одна команда может сделать в спринт. В зависимости от деталей и размера команды, то и не только эту задачу.
Как можно сделать неправильно? Например, разбить вот таким образом
Создать enum со списком интеграций
Сделать метод, который по id определяет в какую систему слать запрос на профиль
Послать зарос в систему А
Послать зарос в систему Б
Послать зарос в систему В
Нормализовать ответ от системы А
Нормализовать ответ от системы Б
Нормализовать ответ от системы В
Теперь давайте эти задачи случайным образом распределим между 5-ю разработчиками из 3-х команд в 3-х разных спринтах. И будем каждую из частей тестировать Unit тестами и только ими т.к. по другому при таком распределении никак. И вишенка на торте все детали реализации разработчики (говорящих на 3-х разных языках) будут брать только из описания тикетов.
Строго говоря, так делать тоже можно, но дольше дороже и менее надежно.
Как понять, что такой подход не оптимален? Задать себе вопрос «можем ли мы одним предложением сказать какая полезная функция добавилась к _системе_?». «получения профиля пользователя по id от третье сторонних провайдеров» на такую функцию вполне тянет. «Сервис ProfileBridge умеет посылать запрос в систему Б, который мы вам пока не отдадим и этого вообще никак снаружи сервиса не видно» — звучит довольно слабо.
Понятно, что всегда есть некоторая специфика, например в принципе не все функции можно имплементировать за спринт. Но пытаться упаковывать тикеты в спринт как можно ближе к этому критерию вполне можно.
Одна большая функция может быть разбита на шаги (см список выше), но важно попытаться сделать так, чтобы эти шаги шли в одном релизе.
Избегайте общих слов
Вынесу отдельным пунктом. Надо стараться избегать общих слов в заголовках и описаниях тикетов. Общие слова это один из способов дезинформации. Общих слова — это например
Improvement
Investigation
Some changes
Minor modifications
Короче любая формулировка которая выглядит солидно и вроде как говорит что что-то делается и/или улучшается, но не понятно, что именно — скорее всего скрывает что-то что вы хотели бы сформулировать явно. См шуки про
— Issue: Something loose in cockpit
— Comment: Something tightened in cockpit
Tickets are pull requests
В идеале тикет должен в результате своего завершения порождать один pull request. Тут есть два момент
Должен быть pull request хотя бы один
В идеале, но не всегда, только один.
Понятно, что есть тикеты на «исследовать поведение API такой-то системы при таких-то условиях». И бывают тикеты для закрытия которых надо сделать изменения больше чем в одном репозитории. Но вместе с тем правило один «тикет один PR» все же существенно упрощает управление командой.
Человек сделал работу — PR с результатами можно послать на ревью
Можно более или менее гранулярно на уровне PR контролировать что вошло в релиз. Если тикет ассоциирован больше, чем с одним PR это может быть чуть менее тривиально. Можно нечаянно зарелизить половину тикета, в большинстве случаев это не хорошо.
Меньше шансов сделать месиво в коде. Например, возможен такой сценарий
Тикет 123 содержит два PR в один и тот же репозиторий.
Первый PR одобрен смерджен в ветку dev
От него другой разработчик отпочковал свой PR для тикета 456 и тоже его смерджил
Второй PR для тикета 123 создан, но не прошел merge и вообще решено тикет 123 в релиз не включать
Вопрос — что делать с PR для тикета 456 который содержит часть имплетментации для тикета 123?
Тут, конечно, можно либо сказать — «ну и пусть содержит, это не мешает», либо начать вырезать тем или иным образом изменения из PR для тикета 456. Но в любому случае это кропотливая работа, которая может сломать код и может оставить после себя странные артефакты в коде.
Как это можно это правило лучше соблюдать?
Каждый тикет должен оставлять материальные следы. Если это POC то код закомиченный в репозиторий. Если это написать документацию в Confluence — то лучше вообще сделать под это специальный тип тикетов, чтобы можно отследить сколько у нас разработчики пишут код, а сколько документацию (хинт разработчики как правило пишут документацию медленно и плохо, это не их основная работа). Если тикет не оставляет после себя материальных следов (например, проверить, что VPN работает), то может быть вообще это не тикет для dev команды. Если это какая-то задача на исследование чего-то то тем более должны быть результаты исследования и поскольку разработчики часто исследуют мир с помощью кода — код закомиченный куда-то. Перефразируя правило — нет PR (а особых случаях ссылки на документ) — нет работы.
Если изменения касаются одного репозитория, то результаты работы это один PR. В случаях если промежуточные результаты нужны для другого тикета — лучше тикеты перереразбить и перепланировать так чтобы PR были гранулярными.
System is a contract, think SemVer
Как правило (если честно я затрудняюсь вспомнить исключения из, но наверняка они существуют) система — это контракт — набор каких-то соглашений, которые она реализует для своих пользователей. Это может быть UI/UX, это может быть API контракт, это может быть какой-то нефункциональный SLA.
Каждый тикет так или иначе что-то в системе меняет (иначе зачем бы мы их делали?). Важно для каждого тикета, до того, как мы его берем в спринт понимать, что именно в контракте системы мы хотим им поменять. Это можно делать разными способами, самый простой, который я могу рекомендовать это SemVer (https://semver.org/). На практике это выглядит так, изменения вносимые любым тикетом относим к одной из категорий
Изменения, ломающие обратную совместимость
Изменения затрагивающие API, но не ломающие обратную совместимость
Изменения, не затрагивающие API, как правило багфиксы или какие-то нефункциональные изменения, например улучшения производительности.
Для пунктов 1 и 2 заранее описываем, что изменится и на кого это повлияет.
В принципе я видел варианты, когда команды говорили
«Мы не можем заранее описать, что изменится в API».
Или даже, «мы что-то изменили в API, но документировать не стали, это нас задерживает на это надо слишком много времени».
На каком-то этапе, где-то в начале работы, до первого релиза, при работе одной командой, так в общем работать даже можно, хотя и не факт, что такая работа эффективна. Но в больших акаунтах где много команд это уже не хорошо. Ну и после того, как система стала доступна пользователям делать изменения в стиле «что-то поменял в API, что именно не скажу», кажется довольно странным поведением.
Это приводит нас к правилу — До того, как берете тикет в спринт планируйте что именно в API он изменит и документируйте эти изменения лучше заранее, ну или в исключительных случаях хотя бы постфактум.
Give me exact instructions
Понятно, что тикет должен описывать какие изменения надо сделать. И описание должно быть достаточно полным, чтобы его мог взять в работу разработчик и QA команда могла потом проверить правильно ли все реализовано. НО именно достаточно полным для разработчиков и QA команды.
Есть специальный метод итальянской забастовки, когда разработчики в силу тех или иных причин начинают сопротивляться изменениям и начинают требовать предельно детальные описания задач. Я видел случаи, когда описание изменения в 50 строк кода занимало две страницы текста.
Обычно в командах есть некое общее понимание как делать задачи, что хорошо, что плохо и каким именно образом писать код. Сам по себе этот общий контекст обычно не возникает и нужны специальные усилия для его создания. Обычно это:
Совместные ревью кода в режиме «шарим экран и обсуждаем почему это сделано так и как можно лучше»
Коучинг членов команды
Прозрачный обмен информацией на дейликах между членами команды не «у меня некоторые проблемы с функционалом тикета», а «я что-то не пойму как правильно выставить параметры payment method в XML в запросе к Sabre, может кто-то с таким сталкивался уже».
Estimates responsibly / minor developers infinity
Понятно, что, когда разработчика просят поменять цвет кнопки на экране, никто никогда не знает куда это может завести и сколько займет времени. Но все же нельзя не признать, что оценки трудоемкости, причем хуже того оценки в человеко-днях все же важны для бизнеса. Пользователи системы люди далекие от высоких материй и хотят знать, когда уже в системе появится вот эта полезная функция, а бизнес внезапно имеет как правило фиксированный бюджет и несмотря на то, что люди держащие в руках деньги кровью подписали agile manifesto они все же хотели бы знать хватит ли у них денег, хотя бы приблизительно.
Это плавно подводит нас к тому, что оценки трудоемкости тикетов все же важны. Есть несколько распространенных ошибок которые команды делают, оценивая работу. Давайте рассмотрим, что именно идет не так и как с этим бороться
Страх перед неизведанным
Это, наверное, самая распространенная ошибка. Возникает в случае, когда разработчик, который оценивает задачу (или в случае скрам церемонии с оценками — вся команда) не знает, как ее делать и не знает, как ее делать (не понимает алгоритм или не работал с конкретной библиотекой/технологий и т.п.). В таком случае как правило в поле оценки ставится «малая программистская бесконечность» это обычно один спринт или в зависимости от ограничений и/или задачи, что-то похожее. В случае если оценивается эпик или что-то сопоставимо большое, то в ход идет «большая программистская бесконечность» — это как правило месяц.
По понятным причинам точности оценке это не прибавляет, и цифра в поле оценки теряет всякий смысл.
Способ борьбы тут понятен. Говорить с коллегами о своих страхах и проблемах, не прятать их за большими цифрами искать тех кто с этим уже сталкивался, если таких людей не находится разбивать неизведанное на части, оценивать части. Но в коем случае не ставить большие, но все еще относительно реалистичные оценки. Если задача все еще не понятна после всех проделанных шагов, впишите в поле оценки либо ноль, либо, в редких случаях что-то запредельно большое — скажем 5 лет. Как именно делать — зависит от репортинга заказчику, как правило лучше вписывать ноль.
Over qualification — мы слишком опытные чтобы делать это быстро
Лет 20 назад, я посмотрел на оценки трудоемкости нашей команды и по мотивам провел эксперимент. Задал один и тот же вопрос менеджменту и разработчикам. Вопрос был «как вы считаете с ростом опыта команды оценки трудоемкости командой в среднем повышаются или понижаются».
Ответ от менеджмента «конечно понижаются, команда же более опытная, больше опыта — быстрее делает».
Ответ от разработчиков «конечно повышаются. Больше опыта, больше возможных проблем с реализацией мы видим и большее количество тонкостей в реализации надо учесть».
Надо понимать, что оба ответа имеют право на жизнь в разных ситуациях. Но надо помнить, что если в оценивании задач не соблюден баланс и оценка полностью отдана на откуп разработчикам, то она будет только расти.
Заключение
Тикеты в JIRA это инструмент, который делает процесс анализа бизнес требований и последующего за ним изменения системы проще и прозрачнее. Это именно процесс от «нам нужна такая фича» до «вот она выкачена на prod». Игнорирование того факта, что это процесс в динамике и фокусировка только на самих тикетах как на ритуале ведет к существенному ухудшению качества работы команды.