Наша разработка постоянно растет, поэтому приходится онбордить по несколько человек в месяц и каждому рассказывать, как правильно грумить задачи. Обучать груму «вручную» больно, потому что это отнимает много времени, какие-то знания теряются по дороге и выскакивают ошибки, которых можно было избежать. Чтобы облегчить жизнь лидам и новичкам, мы собрали чек-лист с описанием этапов грума и примерами. Он будет полезен разработчикам продуктовых компаний, которые онбордят или которых недавно приняли в штат. Чек-лист поможет разбивать задачи на этапы, чтобы ничего не терялось и результат соответствовал ожиданиям.
Все примеры ниже — специфичные и подойдут не каждому, они построены в основном на продуктах Mindbox «Рассылки» и «Программа лояльности». Продукты помогают нашим клиентам запускать автоматические рассылки по триггерам (действиям или событиям), чтобы не спамить пользователей, выдавать промокоды и выстраивать бонусные системы. Если поймете, что чек-лист полезен, можете заменить примеры на свои и использовать.
Ниже подробнее о том, как сделать качественный грум:
Цель грума — провалидировать решение с командой перед тем, как брать задачу в работу. Для этого нужно:
Зачем задача нужна бизнесу:
Краткое описание этапов реализации — минимум по одному предложению на каждый этап. Желательно, чтобы каждый этап можно было ревьюить и мержить отдельно. При этом этапы нужно добавлять по необходимости и не пытаться во всех задачах разгрумить все аспекты.
Недвусмысленное описание того, как должна работать система по завершении задачи.
Какую проблему решаем? Точно ли нужно ее решать именно так? Не нужно ли более общее решение?
Не позволяем ли мы создавать один и тот же функционал двумя способами без особых на то причин?
Пример, как не надо. Обычно все страницы списков сущностей стандартные и в них используется стандартный контрол фильтра для поиска. При этом на странице проблем нет стандартной подгрузки батчами и контрола фильтра, потому что ПО решил, что нужен другой UX. В результате написали кастомный код, еще и страница тормозит:
Страница проблем в админке Mindbox. Фильтр не такой, как на других страницах, в нем всего один параметр — статус проблемы
Как проверить, что приемочные критерии выполнены?
В задаче сложная бизнес-логика с большим количеством неочевидных сценариев? Если да, нужен BDD-тест.
При этом нужно учесть, что мы пишем тесты в коде, — у бизнес-аналитика нет фреймворка для тестов.
Примеры, когда понадобилась детальная подготовка тестовых сценариев от бизнес-аналитика:
Кейсы дедубликации и безопасности операций
Кейсы фильтров по времени относительно текущего из контекста
Как тестировать новые изменения на части клиентов: с помощью фичи-тоггла или другим способом?
Начинаем ли хранить терабайты новых данных или расходовать много CPU? Если да, то нужно обновить модель железа.
Как ведем себя в случае отказов, если сервис недоступен, LRT лежал, был регулярный даунтайм БД?
LRT (long running task) — обработчик фоновых задач.
Нужно ли заводить проблемы в каком-то из сценариев?
Под проблемами мы понимаем сообщения для клиентов о том, что какие-то автоматические механики в админке работают неправильно, в чем ошибка и как ее исправить. Например:
Какие должны быть ограничения доступа: пермиссии персонала, авторизация?
Как именно будет происходить миграция: изменения в базе данных, контрактах сервисов, наборе топиков Kafka? Не сломается ли обратная совместимость?
Отдельно ли редактируем метаданные и рантайм, который их использует? Стандартный пример задачи на блоки в сценариях: UI, бэкенд для UI, рантайм — все отдельно.
Примеры подэпиков в эпике сценариев:
Нужны ли нагрузочные тесты? Какой риск хотим снять, используя нагрузочный тест?
Какие метрики используем?
Только если другие члены команды плохо знакомы с этой частью кода.
Только важные и неочевидные, не надо расписывать «до бетона» реализацию каждого класса.
Только важные и неочевидные. Полный список нужных тестов описывать не надо — его можно окончательно составить только в процессе реализации.
Пример, как надо. Несколько кейсов при отложенной отправке:
Только важные и неочевидные, которые хочется обсудить перед реализацией.
Пример, как надо. Классы, их взаимодействие и интерфейсы при привязке заказов к рассылкам:
В том числе — какие нужны индексы и типы полей.
Пример. Этап задачи о модели связи заказа с рассылкой:
Важно грумить так, чтобы задачи можно было ревьюить небольшими частями. +300 строк — норм, +1500 — нет.
Пример. В каждой задаче о новом виде проблемы написано, что можно мержить отдельно:
Этот блок — специфика Mindbox, но может пригодиться тем, кто работает над созданием админок.
Новые поля должны валидироваться, экспортироваться, импортироваться, фильтроваться, отображаться в UI, логироваться и копироваться.
Новая сущность должна синхронизироваться с сервисом зависимостей, а новая связь — отправляться в сервис зависимостей.
Авторы
Тёма Рудневский, разработчик, техлид
Николай Андрейчук, разработчик, техлид
Все примеры ниже — специфичные и подойдут не каждому, они построены в основном на продуктах Mindbox «Рассылки» и «Программа лояльности». Продукты помогают нашим клиентам запускать автоматические рассылки по триггерам (действиям или событиям), чтобы не спамить пользователей, выдавать промокоды и выстраивать бонусные системы. Если поймете, что чек-лист полезен, можете заменить примеры на свои и использовать.
Ниже подробнее о том, как сделать качественный грум:
- цель грума,
- необходимый минимум,
- уточнение требований и контекста,
- типичные этапы,
- особенности при доработке механик.
Цель грума
Цель грума — провалидировать решение с командой перед тем, как брать задачу в работу. Для этого нужно:
- снять технические риски,
- уточнить требования,
- разбить грум на небольшие части, которые можно ревьюить и мержить отдельно,
- уточнить оценку задачи,
- сохранить информацию о решении и его мотивации.
Необходимый минимум
Контекст
Зачем задача нужна бизнесу:
- какую потребность бизнеса решает,
- какие сервисы затрагивает,
- как реализовано сейчас и что меняем.
Плохо | Чуть лучше | Хорошо |
Делаем SentMailingConnectedEntitiesContext , храним в нем датапарты с идентификаторами сущностей |
Для бизнеса важно иметь связь рассылки с заказом и, возможно, другими сущностями | Кейс: в саппорт звонит пользователь и говорит, что ему не пришло письмо про заказ. Задача: иметь возможность быстро найти в админке рассылки, которые связаны с заказом |
Список этапов
Краткое описание этапов реализации — минимум по одному предложению на каждый этап. Желательно, чтобы каждый этап можно было ревьюить и мержить отдельно. При этом этапы нужно добавлять по необходимости и не пытаться во всех задачах разгрумить все аспекты.
Плохо | Хорошо |
Добавляем сохранение связи рассылки и заказа в триггеры и операции |
|
Приемочные критерии
Недвусмысленное описание того, как должна работать система по завершении задачи.
Плохо | Чуть лучше | Хорошо |
Привязывать сущность при отправке рассылки сразу при срабатывании триггера или вызове операции | В тестах при отправке рассылка связывается с тестовой сущностью. Принимает программист. Плюс всю задачу можно принимать на тесте при простой отправке |
При отправке письма о заказе из триггера или операции можем отфильтровать все действия рассылки с помощью фильтра по ID рассылки |
Уточнение требований и контекста
Валидация проблемы
Какую проблему решаем? Точно ли нужно ее решать именно так? Не нужно ли более общее решение?
Консистентность системы
Не позволяем ли мы создавать один и тот же функционал двумя способами без особых на то причин?
Пример, как не надо. Обычно все страницы списков сущностей стандартные и в них используется стандартный контрол фильтра для поиска. При этом на странице проблем нет стандартной подгрузки батчами и контрола фильтра, потому что ПО решил, что нужен другой UX. В результате написали кастомный код, еще и страница тормозит:
Страница проблем в админке Mindbox. Фильтр не такой, как на других страницах, в нем всего один параметр — статус проблемы
Сценарии приемки
Как проверить, что приемочные критерии выполнены?
Плохо | Чуть лучше | Хорошо |
В задаче со сложной приемкой отсутствуют критерии | Проверяем работу фильтра после отправки письма | Кейс 1:
Кейс 2:
|
BDD-тест (behavior driven development)
В задаче сложная бизнес-логика с большим количеством неочевидных сценариев? Если да, нужен BDD-тест.
При этом нужно учесть, что мы пишем тесты в коде, — у бизнес-аналитика нет фреймворка для тестов.
Примеры, когда понадобилась детальная подготовка тестовых сценариев от бизнес-аналитика:
Кейсы дедубликации и безопасности операций
Кейсы фильтров по времени относительно текущего из контекста
Фича-тоггл
Как тестировать новые изменения на части клиентов: с помощью фичи-тоггла или другим способом?
Плохо | Хорошо |
Делаем без фичи-тоггла, выкладываем код на продакшен. Там дурацкая ошибка, и сервис падает на всех клиентах в «канареечном» окружении. Приходится откатывать и блокировать пайплайн | Делаем под фичей; включаем на одном клиенте в бете; видим, что не работает; выключаем фичу и спокойно чиним |
Объем железа
Начинаем ли хранить терабайты новых данных или расходовать много CPU? Если да, то нужно обновить модель железа.
Плохо | Хорошо |
Строим новый индекс на большой таблице, никого не предупредив | При добавлении новых таблиц оцениваем их размер. Если он большой, разбираемся, есть ли столько места и как его выделить |
Поведение в случае отказов
Как ведем себя в случае отказов, если сервис недоступен, LRT лежал, был регулярный даунтайм БД?
LRT (long running task) — обработчик фоновых задач.
Плохо | Хорошо |
Описываем этап задачи, который обрабатывает записи с текущей минуты. Если LRT не работал какое-то время, часть периода остается непокрытой | Описываем этап задачи, который сохраняет (например, в свои настройки) информацию, за какой период он обработал данные. Неважно, когда он запустится в следующий раз, но продолжит обработку он с нужного времени |
Проблемы
Нужно ли заводить проблемы в каком-то из сценариев?
Под проблемами мы понимаем сообщения для клиентов о том, что какие-то автоматические механики в админке работают неправильно, в чем ошибка и как ее исправить. Например:
- настроена автоматическая выдача промокодов, а промокоды в пуле закончились;
- настроено списание бонусов по событию, а у клиента нет баллов, и баланс станет отрицательным;
- в шаблоне письма что-нибудь делим на количество заказов, а заказов ноль — получается, что делим на ноль.
Плохо | Чуть лучше | Хорошо |
Клиент криво настроил триггер, в нем падает отправка письма и заводится баг на разработчика. Это отвлекает разработчика и заставляет связываться с клиентом через менеджеров и поддержку | Клиент криво настроил триггер, в нем падает отправка письма и заводится проблема на рассылку с текстом, который придумал программист. Клиенту приходит об этом письмо на почту, он сам не может разобраться в том, что произошло, и обращается в поддержку | Клиент криво настроил триггер, в нем падает отправка письма и заводится проблема на этот триггер с текстом, который придумал ПО. Клиенту приходит об этом письмо на почту, он сам разбирается со своим триггером и никого не отвлекает |
Ограничение доступа
Какие должны быть ограничения доступа: пермиссии персонала, авторизация?
Плохо | Хорошо |
Любой младший маркетолог клиента, который отправляет массовые рассылки, может зайти на страницу точек интеграции и посмотреть секретные ключи для вызовов сервисов | Страница интеграций закрыта пермиссией «Просмотр точек интеграции», которая выдается только доверенному персоналу |
Типичные этапы
Two-phase-миграция
Как именно будет происходить миграция: изменения в базе данных, контрактах сервисов, наборе топиков Kafka? Не сломается ли обратная совместимость?
Плохо | Хорошо |
Из сущности «Персонал» договорились удалить «Тип персонала», так как теперь у всех один тип и этот функционал больше не используется. Удаляем свойство из сущности и сразу пишем скрипт, удаляющий колонку. Почему это плохо: при деплое миграция базы может произойти раньше, чем деплой нового кода. Старому коду будет не хватать этой колонки, и он упадет. |
Удаляем свойство из сущности, мержим и ждем, когда этот код окажется на всех проектах. После этого пишем скрипт, удаляющий колонку. |
Обнаружили ошибку в контракте: при передаче суммы изменения баланса возвращаем <bBalanceChangesSum>650<bBalanceChangesSum/> Исправляем ошибку и возвращаем узел <balanceChangesSum>650<balanceChangesSum/> |
Исправляем ошибку, возвращаем два узла:
Ждем, когда все клиенты перейдут на новый узел, удаляем его. |
UI и бэкенд
Отдельно ли редактируем метаданные и рантайм, который их использует? Стандартный пример задачи на блоки в сценариях: UI, бэкенд для UI, рантайм — все отдельно.
Примеры подэпиков в эпике сценариев:
Нагрузочные тесты
Нужны ли нагрузочные тесты? Какой риск хотим снять, используя нагрузочный тест?
Метрики, алерты, хартбит
Какие метрики используем?
Плохо | Чуть лучше | Хорошо |
Описание этапа подготовлено без метрик | В описании этапа рассказано, какие метрики было бы интересно репортить | В описании этапа расписано, какие метрики было бы интересно репортить, какие алерты на них можно построить и какой примерный текст ранбука ожидается |
Описание этапов
Место для начала и копипасты
Только если другие члены команды плохо знакомы с этой частью кода.
Плохо | Хорошо |
Добавляем SentMailingConnectedEntitiesContext , который умеет связывать сущности с отправленной рассылкой |
Добавляем SentMailingConnectedEntitiesContext, который умеет связывать сущности с отправленной рассылкой. Сама отправка и привязка должна происходить в MailingProtocol'3.SendInterna l, куда нужно пробрасывать SentMailingConnectedEntitiesContext |
Нюансы реализации
Только важные и неочевидные, не надо расписывать «до бетона» реализацию каждого класса.
Плохо | Хорошо |
Добавляем SentMailingConnectedEntitiesContext , который умеет связывать сущности с отправленной рассылкой. Много текста с подробностями реализации |
Добавляем SentMailingConnectedEntitiesContext , который умеет связывать сущности с отправленной рассылкой. Чтобы привязать все контекстные сущности к рассылке, можно сделать в нем метод BindEntitiesToMessage(modelContext, rootMailingCustomerAction ), который достает все зарегистрированные ISentMailingConnectedEntityDescription и вызывает BindEntityToMessage у каждого из них |
Тест-кейсы
Только важные и неочевидные. Полный список нужных тестов описывать не надо — его можно окончательно составить только в процессе реализации.
Плохо | Хорошо |
Сложная задача, в которой не написано, какие тесты можно написать хотя бы от бизнеса. Несложная задача, в которой детально расписаны все возможные тест-кейсы, которые могут появиться |
Описаны базовые тест-кейсы, которые точно должны выполняться. См. пример ниже |
Пример, как надо. Несколько кейсов при отложенной отправке:
Интерфейсы классов или контрактов сервисов
Только важные и неочевидные, которые хочется обсудить перед реализацией.
Плохо | Хорошо |
Несколько задач, в каждой не указаны контракты. При разработке людям нужно синхронизироваться по этим контрактам самостоятельно, и если они забудут, придется решать эту проблему при интеграции | См. пример ниже |
Пример, как надо. Классы, их взаимодействие и интерфейсы при привязке заказов к рассылкам:
Схема данных в БД
В том числе — какие нужны индексы и типы полей.
Пример. Этап задачи о модели связи заказа с рассылкой:
Этап, после которого можно мержить код
Важно грумить так, чтобы задачи можно было ревьюить небольшими частями. +300 строк — норм, +1500 — нет.
Пример. В каждой задаче о новом виде проблемы написано, что можно мержить отдельно:
Гарантия консистентности при параллельных запросах
Плохо | Хорошо |
Человек с сайта быстро отправляет два запроса на списание баллов так, что они обрабатываются одновременно, а не последовательно, и уходит в отрицательный баланс | Кейс параллельного списания баллов рассмотрели в задаче и объяснили, как не допускать такой ситуации |
Особенности при доработке механик
Этот блок — специфика Mindbox, но может пригодиться тем, кто работает над созданием админок.
Новые поля
Новые поля должны валидироваться, экспортироваться, импортироваться, фильтроваться, отображаться в UI, логироваться и копироваться.
Новая сущность и связь
Новая сущность должна синхронизироваться с сервисом зависимостей, а новая связь — отправляться в сервис зависимостей.
Авторы
Тёма Рудневский, разработчик, техлид
Николай Андрейчук, разработчик, техлид