Всем привет! Я Виктор Брыксин, руковожу разработкой Яндекс Телемоста. В статье поговорим про декомпозицию задач в проекте и как можно получить реальные сроки его выполнения.
Спойлер: вы все равно ошибетесь, прогнозируя сроки. Но что можно сделать? Минимизировать шанс на ошибки и сделать их менее фатальными. Я расскажу про рабочие инструменты, которые помогли мне в свое время, — брать их на вооружение или нет, решайте сами. Если вы не знаете, как подступиться к декомпозиции сложного проекта и с чего начать, — эта статья вам в помощь.
Фантазируй Декомпозируй
Оценка сроков проекта бывает задачкой со звездочкой. Допустим, к вашему проекту предлагают подключить еще пять человек. Возможно ли сделать план работ команды так, чтобы никто не подрался за задачи? Если да, то как именно?
Или к вам прибегает менеджер и просит оценить сроки проекта. Вы чешете голову и прикидываете: «Ну где-то два месяца». У него возникает естественный вопрос: «Почему так долго?» Ведь задача в голове менеджера может выглядеть сильно меньше, чем в вашей.
Или, например, к вам приходит руководитель и говорит: «Вот тебе задача, проработай ее и декомпозируй. Ты же сеньор, ты должен знать способы»… «А если я не уверен, что эти способы приведут к желаемому результату?»
Со всеми этими вопросами и будем разбираться в статье.
Когда у вас сложный и крупный проект, не получится избежать ошибок, однако важно уменьшить вероятность серьезных и фатальных. Это не про «делайте так, а по-другому не делайте». Если вы не знаете, как подступиться к оценке сроков вашего проекта, или не уверены, что ваши модели хорошо работают, то можете взять и попробовать для себя этот инструмент. В этой статье хочу поделиться своим опытом — то, что прочитал в книгах и пропустил через себя.
Раскладываем проект на команду: над какими вопросами придется подумать
Предположим, у вас есть проект по предварительной оценке на четыре месяца. А получили вы ее, применяя проверенные веками способы оценки сложных проектов: гадание на костях, оценка по потолочным трещинам или раскладывание карт Таро. И теперь нужно этот проект проработать и распределить задачи по команде. На какие вопросы вам придется ответить:
-
Какую команду стоит задействовать: размер, уровень экспертизы? Как это сделать наиболее оптимально?
-
Какой будет график работ?
Здесь самое время обратиться к приемам декомпозиции. По итогу мы получаем граф работ, в котором можем варьировать сроки и количество людей. Как его построить, разберемся дальше.
Виды декомпозиции
Сразу оговорюсь, чтобы не закидали помидорами, — в статье буду использовать свои авторские термины, потому что так проще избежать разночтений.
Итак, глобально есть два подхода к декомпозиции задач: технологическая и маршрутная.
Технологическая декомпозиция — это когда вы хорошо разбираетесь в предметной области и можете решить задачу в уме.
Маршрутная декомпозиция — это когда всё, что у вас есть, это картинки и некое описание того, как оно должно работать.
Важно отметить, для какой команды и каких процессов будут справедливы наши дальнейшие рассуждения:
-
Команда взаимозаменяемых разработчиков, например, T-shaped специалисты, или те, кто занимаются одной платформой.
-
Agile-подобный процесс со спринтами фиксированной длины и коммитментами на задачи, взятые в спринт.
И отсюда растут ограничения, с которыми мы работаем:
-
Мы не можем брать в спринт задачи, которые зависят от других незавершенных задач. Есть риски, что последние сдвинутся по срокам, соответственно, новые не пойдут в работу, но место в спринте займут.
Если структура команды другая, например, кросс-функциональная с разработчиками, которые не могут друг друга заменить, то оптимальный процесс декомпозиции может быть другим.
Маршрутная декомпозиция: когда нужно «еще вчера», и нет специальных знаний
Наверняка вы сталкивались с ситуацией: только пришли в проект, и вам кидают задачу: «держи, разгребай», а вы еще ничего не знаете. И как это обычно бывает — документации нет, спросить не у кого — тогда что делать? Можно использовать маршрутную декомпозицию.
Это декомпозиция по user story — вы пытаетесь переложить пользовательскую историю на задачи, причем каждая из задач становится точкой, в которой система переходит в заранее заданное состояние. И то, что вам нужно, — довести систему из некоторого состояния А в состояние Б.
В чем смысл такой декомпозиции? Мы раскладываем все, что делает пользователь на некоторые элементы, каждый из которых имеет самостоятельную ценность и помогает нам как разработке сделать следующий шаг, наращивая функциональность.
Я когда-то был тимлидом iOS-команды — давайте разберемся на простом примере из этой части моего опыта. У вас есть Мессенджер, и в него нужно добавить фичу шаринга чего-либо.

Рассмотрим, как эту задачу можно разложить в случае маршрутной декомпозиции:
-
По клику показывать пустое окно с отменой (например, ценность этого элемента — новый экран)
-
Заполнить окно аватарками (тут, например, ценность в том, что мы показываем людей, кому можно расшарить контент)
-
При выборе давать вводить текст
-
Отправлять сообщение
-
Добавить поиск
Здесь отталкиваемся от того, как думает и действует пользователь — вроде ничего сложного. В чем преимущества такого подхода:
Плюсы:
-
Не нужна техническая экспертиза. Декомпозицию может делать кто угодно — не нужно быть разработчиком и глубоко разбираться в технических деталях.
-
Делается быстро.
Теперь перейдем к недостаткам — они, как ни странно, растут из преимуществ.
Минусы:
-
Размеры задач в спринтах могут сильно отличаться. Если не иметь экспертных знаний, то можно декомпозировать так, что одна задача будет занимать два дня, другая — месяц. В чем здесь проблема? Чем объемнее задача, тем выше в ней уровень неопределенности, и, как следствие больше рисков, что она дальше будет по срокам разрастаться, а наша оценка окажется неверна.
-
Зачастую получаются линейные цепочки задач. Взять в работу следующую задачу можно только после завершения предыдущей. Соответственно, текущая задача развалилась по срокам — это сдвигает сроки для следующих.
Технологическая декомпозиция: когда можете уйти глубоко в детали
Этот вид декомпозиции стоит выбирать, если у вас есть специальные знания, позволяющие выполнить задачу близко к коду. Здесь мы погружаемся в то, что именно нужно сделать, концентрируемся на модулях, в которых нужно внести изменения. Тут есть приятный бонус — любое изменение изолированно в своем модуле, меньше шансов попасть в ситуацию конфликта зон ответственности. В случае, например, маршрутной декомпозиции изменения могут затрагивать несколько модулей сразу.
Вернемся к примеру из моего iOS-ного опыта про фичу шаринга в Мессенджере. В случае технологической декомпозиции задачи будут ставиться по реализации новой возможности в коде, например:
-
Сделать пустой Share Extension
-
Перенести модуль для работы с WebSocket в общую библиотеку
-
Перенести модуль для работы с REST API в общую библиотеку
-
Подключить модуль авторизации к пустому Share Extension
-
Синхронизировать авторизацию между Share Extension и основным приложением
-
Реализовать базовую навигацию + ViewController с отменой
-
Подключить модуль для работы с REST API, связать его с авторизацией
-
Нарисовать список получателей по ответу из REST API
-
Подключить авторизацию к модулю для работы с WebSocket
-
Реализовать отправку сообщений через WebSocket
Шаги в этом примере требуют специальных знаний об устройстве приложения и если вы «зашли с улицы», то вам может быть далеко не все ясно. В этом специфика технологической декомпозиции.
Плюсы:
-
Возможность более четко оценивать сроки задач. Разработчик с экспертными знаниями понимает, какое именно изменение нужно сделать в модуле, знает его размер и сложность. Соответственно, может четко варьировать размер задачи.
-
Граф задач произвольной сложности. Можно распараллелить задачи на разных людей. Все зависит от того, насколько можно сделать так, чтобы они не пересекались по модулям. Естественно, могут возникать блокирующие задачи — но при должном подходе их можно избежать.
Минусы:
-
Требуется высокая экспертиза. Вы практически не можете провести такую декомпозицию, если у вас нет специальных знаний. Это значит: вы много времени потратили на задачу и, как следствие, ее уже решили. Либо вы уже двадцать раз с такими задачами сталкивались, и это — двадцать первый.
Например, к вам пришел продакт и просит ввести новый тип сообщения в Мессенджере — например, карту. Вы сталкивались с подобной задачей уже N раз, соответственно знаете, каких десять действий нужно сделать, чтобы ее решить.
-
Подвержена ошибкам проектирования.
Важный момент — в случае маршрутной и технологической декомпозиции по разному распределена ответственность.
В маршрутной она смещена на разработчика, который делает эту задачу, он принимает решения в моменте. В технологической — ответственность на человеке, кто эту декомпозицию проводит. По сути он один придумывает решение за всех, а остальным остается просто написать код под диктовку.
Что из этого следует? Если у вас команда скилловых и опытных ребят, то лучше выбирать маршрутную — они разберутся. Если вы один сильный и красивый, а у вас команда желторотых джунов, то сделайте все за них.
Смешанная декомпозиция: собираем лучшее из двух предыдущих
Бывает еще смешанный вариант. Это мой любимый, потому что изолирует сложность технологической декомпозиции в рамках отдельных изменений.
На уровне большой сложной фичи делается маршрутная декомпозиция — выстраиваются состояния системы. Затем каждый переход системы из одного состояния в другое прорабатывается и делается технологическая декомпозиция.
Разберем вариант простейшей декомпозиции на примере той же фичи шаринга контента в Мессенджере.

Сверху мы видим маршрутную декомпозицию. Начинаем с пустого списка, добавляем туда адресатов, текстовое поле, делаем отправку.
Переходим к технологической декомпозиции. На каждой точке мы понимаем, что именно нам нужно. Например, чтобы показать адресатов, нам необходимо затащить сетевой стек. Мы знаем, что он требует авторизации, и еще нам бы хорошо подклеить одно к другому. Текстовое поле — не рокет сайенс, с этим шагом все понятно.
Переходим к отправке — для нее потребуется WebSocket. Тут, кстати, подключаются наши экспертные знания. Например, мы понимаем, что адресатов можно получить только через HTTP-запросы, а отправку сообщений сделать только через WebSocket, потому что так устроено наше API. Соответственно, WebSocket нам нужно будет подключить к авторизации. В итоге мы получаем такой интересный граф задач.
Но что дальше с этой радостью делать? Важно понять, какой у нас критический путь. Отмечу, что мы будем рассматривать критический путь в рамках модели наивных сроков, о которой дальше подробнее расскажем.
Модель наивных сроков и расчет критического пути
Критический путь — это цепочка зависящих друг от друга задач наибольшей продолжительности. Именно критический путь определяет, сколько фича реально будет делаться. Критический путь — это линейная цепочка задач, поэтому, она не параллелится, и ускорить ее добавлением большего числа людей невозможно.
Важно понять длительность критического пути, так как это напрямую влияет на оценку сроков вашего проекта.
Прежде, чем рассчитаем критический путь для нашей задачи — рассмотрим модель наивных сроков.
Она держится на трех наивных предположениях:
-
Каждая задача занимает не более одного спринта
-
В спринт не берутся блокирующие друг друга задачи
-
Емкость спринта в задачах бесконечна
В рамках трех предположений мы можем оценить, когда примерно сможем рассчитывать на результат, причем речь о минимально возможном сроке.

Итак, а теперь рассчитаем критический путь. Он начинается от конечной задачи: идем по графу и смотрим расстояния от каждого узла графа до нее. Получается, что у нас критический путь имеет длину четыре. И начинается с двух задач — авторизации и сетевого стека. Казалось бы, нужно начать с пустого списка, это же первая задача. Но нет! Лучше начать не с него, так как мы можем не успеть сделать сетевой стек и авторизацию. Если начать с пустого списка, критический путь будет занимать не четыре, а пять спринтов.
После оценки критического пути переходим к оценке сроков.

Мы раскладываем наш граф таким образом, чтобы мы начинали с задач, которые лежат на критическом пути и так, чтобы в один спринт не бралось блокирующих задач. И при этом считаем, что в спринт может влезть бесконечное количество задач.
Продолжим разбирать пример:
1 спринт: делаем сетевой стек.
2 спринт: делаем пустой список и подклеиваем сетевой стек к авторизации.
3 спринт: делаем адресатов на базе подклеенных сетевого стека и авторизации. Далее затаскиваем WebSocket. Видим, что мы могли затащить его и в первом, и во втором спринте — в зависимости от того, сколько у нас было людей.
4 спринт: подключаемся к авторизации, добавляем текстовое поле.
5 спринт: склеиваем все и добавляем отправку.
При критическом пути в четыре — в конце пятого спринта по наивной модели мы получим готовое решение. Почему это оценка сроков, а не коммитмент? Потому что от готового решения до релиза нужно заложить еще много чего: например, тестирование, раскатку. Но по крайней мере в этой точке мы можем сказать тестированию: «Ребят, у вас будет работа через пять спринтов».
Допустим, нам это не нравится и хочется быстрее. Пришел менеджер и сказал: «Нам надо завтра!». Ну а мы ему что: «Сорян чувак, завтра не получится». Но что мы можем сделать? Ресурсы из воздуха не берутся — мы можем варьировать количество людей, которые делают задачи в параллель, за счет реорганизации задач.
Есть два варианта:
-
Когда задача параллелится на N разработчиков, а у нас N — 1. Тогда мы можем привлечь еще одного, и, таким образом сделать задачу быстрее.
-
Когда задача не параллеится, однако по объему небольшая, и ее можно объединить с другой. Даже если они блокирующие в итоге вы сможете сэкономить время.
В этом примере адресаты и текстовое поле были две блокирующие задачи. Но мы посидели-посчитали и поняли, что эти две задачи влезут в один спринт, поэтому можем объединить их и не делать цепочку блокирующей. Как я уже говорил, по модели наивных сроков нельзя брать блокирующие задачи — если первая вылезла за сроки, то вторую мы даже не возьмем. В итоге: поздравляем — вы сэкономили один спринт, теперь задача вместо пяти спринтов сходится за четыре.
Полная и неполная декомпозиции: лучше не строить граф из 822 задач на 8 команд
Поговорим про еще 2 типа декомпозиции: полную и неполную.
Чем сложнее проект, тем больше шансов, что проработка будет многоуровневая. Мы не пытаемся сразу составить граф задач на 822 задачи на восемь разных команд, а находим точку, где есть осмысленный результат. И далее разбиваем задачу на этапы и декомпозируем каждый этап. Однако в таком случае мы не можем точно сказать, к какому сроку проект будет завершен. Но мы серьезно снижаем риски, что в случае ошибки что-то пойдет не так. Ничего не бывает хуже, если вы проработали гигантскую задачу, а в середине ее выполнения поняли, что в начале допустили ошибку, и весь ваш титанический труд можно выкинуть в помойку.
Если вас не жгут сроки, то для сложных фичей лучше полную декомпозицию не делать, вы точно облажаетесь. Весь смысл работы — ошибаться, но не фатально. Оставьте себе возможность ошибиться и локализуйте количество работы, которое вам придется сделать в случае ошибки.
Получаем из сроков дедлайны
Итак, мы смогли решить задачу «когда будет готово». Пришло время её усложнить и ответить на вопрос — когда точно будет готово?
Естественно, что предсказывать будущее еще никто не научился, поэтому наша задача — заложить время на устранение сработавших рисков. То есть по сути спланировать все так, как будто весь проект пошел не по плану в каждой точке.
Для этого можно воспользоваться следующим подходом:
-
Считать, что любая задача займет в N раз больше времени, чем оценивается. Для практического применения N=2 дает неплохой баланс между точностью оценки и увеличением сроков
-
Считать, что исполнители задач выйдут из строя в самое неподходящее время (например, в середине критически важной задачи) на 1-2 недели
-
Заложить время на все активности за пределами разработки — тестирование, возвраты от тестирования. Можно, например, заложить два-три цикла возврата, рассчитывая что устранение дефектов, найденных QA, займет в 2 раза больше времени, чем их поиск. Ещё мероприятия, связанные с релизным процессом: особенно если у вас мобильное приложение, внезапные затыки на ревью в Apple Store еще никто не отменял. Также стоит накинуть время на проведение экспериментов, сбор статистики, доработки по результатам выпуска, внезапные баги и падения, которые не были обнаружены на QA. Ну и конечно, стоит заложить время на все нюансы ваших процессов разработки, включая внезапные правки от самых неравнодушных, которые необходимо будет внести в самый последний момент.
-
Пересчитать критический путь с учетом этих допущений и новых задач.
Если же какие-то риски не прогнозируемы, тогда не стоит разговаривать о дедлайнах до момента, пока они все не будут отработаны. Потому что главная задача, когда вы озвучиваете дедлайн, — понимать, как вы будете его обеспечивать. Поэтому хорошо, например, планировать все RnD-работы для выполнения в самом начале, а о дедлайнах говорить уже после оценки их результатов.
Если же дедлайн требуют сейчас, а результаты RnD будут через месяц, воспользуйтесь внутренним чутьем разработчика. И если оно ничего не подсказывает вам — значит, вы не можете назвать срок, который способны гарантировать, и лучше честно об этом сказать.
Заключение
Так как же понять, какую декомпозицию использовать? По моему опыту лучше исходить из двух факторов: какой у вас состав команды и какого уровня технической сложности ваша задача. Если у вас сложный и масштабный проект — лучше начните с маршрутной и изолируете техническую сложность в рамках отдельных изменений. И помните, вы все равно ошибетесь, однако, надеюсь, эта статья поможет вам уменьшить фатальность ваших ошибок.
Понятно, что существует много разных способов декомпозиции задач в проекте и оценки сроков. Предлагаю обсудить в комментариях, как вы декомпозируете задачи в проекте?
ссылка на оригинал статьи https://habr.com/ru/articles/809475/
Добавить комментарий