Счастливый путь (Happy path)
Счастливый путь (Happy path) — это наиболее часто встречающаяся корректная последовательность событий среди экземпляров процесса, т.е. самый популярный путь, без ошибочных ветвлений или циклов, начинающийся и заканчивающийся на валидные начальные/конечные события.
Счастливый путь не может быть задан, он может быть только выявлен в процессе анализа логов событий.
В таблице, в столбце «Путь (слово процесса)» выделены наиболее часто встречающиеся последовательности событий процесса оформления поступления товара на склад в разрезе различных аналитик.
Фрагмент таблицы различных путей процессов:
| Аналитика | Путь (слово процесса) | Кол-во экземпляров процессов |
|---|---|---|
| Аренда площадей | BKN | 826 |
| AKN | 469 | |
| BEKN | 420 | |
| Хранение для таможенного оформления | BGKPSTN | 435 |
| BGEGKPSTN | 413 | |
| BGKN | 390 | |
| BEGKPSTN | 314 | |
| BKN | 306 | |
| AGGKPSTZ | 264 | |
| Ответственное хранение | BCKN | 557 |
| BCGKPSTN | 323 | |
| ACKN | 304 | |
| BCN | 265 | |
| Транзитное хранение | BGKN | 642 |
| BKN | 441 | |
| AGKN | 397 |
В таблице выделены наиболее часто встречающиеся пути процесса в разрезе каждой аналитики: BKN, BGKPSTN, BCKN, BGKN — это счастливые (основные) пути. Они начинаются валидным (предусмотренным) событием «B» и завершаются валидным событием «N», то есть приводят процесс к ожидаемому полезному результату.
Другие пути, не являющиеся «Happy Path» являются альтернативными путями процесса. Среди альтернатив можно выделить антипод «Happy Path» — «unhappy path». Его переводят по-разному: «Несчастный путь», «Путь исключения», «Бракованный путь». «Unhappy path» позволяет выявлять брак в ходе осуществления процесса. Если счастливый путь один для каждой аналитики, то альтернативных путей может быть множество.
«Бракованный путь» не позволяет достигнуть требуемого результата — это главный критерий его определения. В примере выше бракованным является путь «AGGKPSTZ», так как начальное событие «А» и конечное событие «Z» не являются валидными начальными/конечными событиями.
Happy path в тестировании что это

Профессиональное движение DevOps зародилось в 2009 году. Его цель — настроить тесные рабочие отношения между разработчиками программного обеспечения и отделами IT-эксплуатации. Внедрение практик DevOps в повседневную жизнь организации позволяет значительно ускорить выполнение запланированных работ, увеличить частоту релизов, одновременно повышая безопасность, надежность и устойчивость производственной среды. Эта книга представляет собой наиболее полное и исчерпывающее руководство по DevOps, написанное ведущими мировыми специалистами.
Книги автора: Руководство по DevOps
Книги автора: Руководство по DevOps
Книги автора: Руководство по DevOps
Книги автора: Руководство по DevOps
Книги автора: Руководство по DevOps Как мы покупали русский интернет
Книги автора: Руководство по DevOps
Книга: Руководство по DevOps
Обеспечьте безопасность приложений
Скрыть рекламу в статье
Обеспечьте безопасность приложений
В тестировании на стадии разработки часто обращают особое внимание на правильность работы приложения, концентрируясь на потоках «положительной логики». Такой тип тестирования часто называют счастливым путем (happy path), в нем проверяется обычное поведение пользователя (и иногда некоторые альтернативные пути), когда все происходит, как было запланировано, без исключений и ошибок.
С другой стороны, хорошие тестировщики, инженеры службы безопасности и специалисты по фрод-мошенничеству[161] часто заостряют внимание на грустных путях (sad path), когда что-то идет не так, особенно если это касается ошибок, связанных с защитой данных (такие виды типичных для защиты данных событий часто в шутку называют плохими путями, или bad path).
Например, предположим, что на нашем сайте есть форма и в нее покупатель для оплаты заказа вносит данные своей платежной карты. Мы хотим найти все грустные и плохие пути, убедиться в том, что недействительные данные карты не принимаются, и предотвратить возможное использование уязвимых мест сайта, например внедрение SQL-кода, переполнение буфера и так далее.
Вместо того чтобы проводить проверку вручную, в идеале стоит сделать тесты безопасности частью автоматизированных тестовых модулей, чтобы они могли проводиться в конвейере развертывания непрерывно. Скорее всего, нам потребуются следующие виды функциональности.
• Статический анализ: это тестирование не в среде исполнения: идеальная среда — конвейер развертывания. Обычно инструмент статического анализа проверяет код программы на все возможные способы выполнения кода и ищет недочеты, лазейки и потенциально вредоносный код (иногда этот процесс называют «тестированием изнутри наружу»). Примеры инструментов статического анализа — Brakeman, Code Climate и поиск запрещенных функций (как, например, «exec()»).
• Динамический анализ: в противоположность статическому тестированию динамический анализ состоит из тестов, проводимых во время работы программы. Динамические тесты проверяют системную память, поведение функций, время ответа и общую работоспособность системы. Этот метод (иногда называемый «тестированием снаружи внутрь») имеет много общего с тем, как злоумышленники взаимодействуют с приложением. Примерами инструментов могут быть Arachni и OWASP ZAP (Zed Attack Proxy)[162]. Некоторые типы тестирования на проникновение (pentesting) можно проводить автоматически, их можно включить в динамический анализ с помощью таких инструментов, как Nmap и Metasploit. В идеале автоматизированное динамическое тестирование должно проводиться во время фазы автоматического функционального тестирования в конвейере развертывания или даже уже во время эксплуатации сервиса. Чтобы проконтролировать соблюдение требований безопасности, можно настроить инструменты вроде OWASP ZAP, так чтобы они атаковали наши сервисы через прокси-сервер, а затем изучать сетевой трафик в специальной тестовой программе.
• Проверка зависимостей: еще один тип статического тестирования, проводимый во время сборки программы в конвейере развертывания, включает в себя проверку всех зависимостей продукта на наличие бинарных и исполняемых файлов, а также проверку того, что у всех этих зависимостей (а над ними у нас часто нет контроля) нет уязвимых мест или вредоносного кода. Примеры инструментов для таких тестов — Gemnasium и bundler audit для Ruby, Maven для Java, а также OWASP Dependency-Check.
• Целостность исходного кода и подпись программы: у всех разработчиков должен быть свой PGP-ключ, возможно, созданный и управляемый в такой системе, как keybase.io. Все подтверждения кода в системе контроля версий должны быть подписаны — это легко сделать с помощью таких инструментов свободного ПО, как gpg и git. Кроме того, все пакеты, созданные во время процесса непрерывной интеграции, должны быть подписаны, а их хэш должен быть записан в централизованный сервис логирования для облегчения аудита.
Кроме того, стоит определить шаблоны проектирования для написания такого кода, злоупотребить которым будет непросто. Это, например, введение ограничений для скорости сервисов и отключение кнопок отправления ранее использованных данных. Организация OWASP публикует много полезных руководств, в том числе серию чек-листов, рассматривающих следующие вопросы:
• как хранить пароли;
• как работать с забытыми паролями;
• как работать с входом в систему;
• как избежать уязвимых мест межсайтового скриптинга (XSS).
Все-таки вам нужны юнит-тесты

В прошлом посте я говорил, что вам не нужны юнит-тесты. Но то были #вредныесоветы, а сейчас настало время разоблачений. Сегодня мы поговорим о всей важности тестирования и о том, чем грозит его отсутствие (либо неправильное применение). Я постараюсь максимально подробно описать плюсы тестирования и разобрать вредные советы из прошлого поста.
В качестве вступления
Каждое утверждение относится к конкретной области знаний. Например, я никогда не занимался строительством и не знаю, как нужно (и нужно ли) тестировать надежность конструкции. Я не занимался разработкой аппаратного обеспечения и не знаю, каким образом в этой области применяются модульные тесты, и применяются ли они в принципе. Я не занимался низкоуровневой разработкой, не писал на ассемблере и не знаю, как модульно тестировать микроконтроллеры.
Но я занимаюсь enterprise разработкой. Я знаю, как писать бэкенд для крупных сервисов и, что самое главное – я знаю, как применять модульное и интеграционное тестирование в больших проектах на языках высокого уровня.
А может и не знаю В любом случае, мне есть, чем поделиться.
Я занимаюсь проектами, в которых минимум пользовательского интерфейса, а многие (микро)сервисы и в принципе его не имеют. Проще говоря, существует единая точка входа в процесс, но до визуального отображения результатов работы будет вызвано множество функций в разных частях системы. Все, что они делают – обрабатывают, подготавливают, сохраняют и пересылают данные из одних мест в другие. И я хочу рассказать, насколько важно модульное и интеграционное тестирование в таких системах.
Простейший пример приложения
Чтобы лучше понять, как это – писать систему без интерфейса, давайте рассмотрим простейший пример. Допустим, у вас есть telegram-бот, который складывает числа. Он просто суммирует их и не делает ничего больше.
Вы ему присылаете несколько чисел, разделенных пробелом, например: «2 2 5». Он эти числа парсит, складывает между собой и возвращает вам результат: 9.
Выглядит очень просто, но это – приложение без какого-либо интерфейса. Да, здесь интерфейсом выступает сам telegram, но точкой входа в вашу систему будет являться вебхук-контроллер, который принимает события от telegram. Иными словами, вы сами никакого пользовательского интерфейса не предоставляете.
На бумаге это будет выглядеть как-то так:
- Пользователь отправляет вам сообщение, которое уходит на сервер telegram.
- Telegram оповещает ваше приложение о новом сообщении с помощью вебхуков.
- Ваше приложение выполняет необходимые действия и отправляет на сервер telegram ответ.
- Telegram оповещает пользователя о новом сообщении.
Диаграмма довольно условная, и telegram может работать по-другому, но в качестве примера сгодится вполне.
Ручного тестирования недостаточно
Вы можете запустить ваше приложение локально, настроить вебхуки и начать тестировать, используя клиент telegram. Иными словами, заняться ручным тестированием. И вы не будете испытывать каких-либо неудобств.
А теперь представьте, что система разрастается. По какой-то неведомой нам причине миллионы пользователей заинтересовались вашим приложением и бесконечно шлют свои сообщения. Вы решаете разделить ваше приложение на consumer, processor и producer:
- Consumer принимает вебхуки и складывает сообщения в очередь входящих сообщений.
- Processor забирает сообщения из очереди входящих сообщений, складывает числа и кладет результат в другую очередь.
- Producer берет сообщения из очереди результатов и отправляет их пользователям.
В таком контексте вам нужно будет поднять три локальных сервиса, две очереди сообщений и настроить связь между ними. Вы станете это делать лишь для того, чтобы проверить, что «2+2» вернет 4, а «3+привет» вернет «Извините, но вы должны ввести числа» (а не «3привет», как сами знаете где)?
Личное мнение – мануальное тестирование умрет
Лично я считаю, что понятие «ручное тестирование» очень сильно изменится, а мануальные тестировщики попросту перестанут существовать. Тестирование веб-приложений отлично автоматизируется тем же Selenium (либо чем-то еще), тестирование десктопных и мобильных приложений тоже будет автоматизироваться. Нет, ручное тестирование само по себе никуда не денется, просто тестировщики будут проводить целый комплекс работ – от создания и поддержки автотестов до эпизодического тестирования руками там, где это проще. Чисто ручное тестирование без использования скриптов там, где это возможно – это рудимент.
Здесь начинается тестирование
Да, разумеется, когда сервис отправится в тестирование (в QA отдел), самим тестировщикам не придется множество раз и подолгу его настраивать. По-хорошему, за них это должны делать скрипты, те самые пайплайны, над которыми мы смеялись в прошлый раз.
Да даже если тестировщику и придется все это поднимать, то это же часть его работы, верно? Ну поднимет и начнет тестировать, вроде бы никаких проблем.
За исключением одной: хороший разработчик отдаст в тестирование только тот код, который он уже сам проверил, чтобы исключить множество циклов доработки по возврату.
И, чтобы разработчику не пришлось каждый раз поднимать весь контекст у себя на машине, и были придуманы юнит- и интеграционные тесты. Вы просто берете и тестируете отдельно модуль сложения чисел, модуль получения входных данных из очереди входящих сообщений и модуль отправки результатов в выходную очередь. Когда вы делаете какое-то изменение, вы запускаете эти тесты и смотрите, что у вас все в порядке, и затем уже отдаете результат в отдел QA для проведения более объемлющего тестирования.
Далее под словом «тестирование» я буду подразумевать не работу отдела QA, а написание разработчиком юнит- и интеграционных тестов на свой код.
Далее, пробежимся по вредным советам из прошлого поста.
Хороший программист уверен в себе
Помните шутку про стадии роста программиста?
- Джуниор: я ничего не знаю
- Миддл: я знаю все
- Сеньор: я ничего не знаю
Чем больше мы знаем, тем отчетливее осознаем, что гораздо больше областей нам неподвластны. К чему это я? Да к тому, что сколько бы хорошим и уверенным в себе ни был программист, он по-прежнему может совершить ошибку. Даже лучшие от этого не застрахованы. И это нормально.
На самом деле, всем плевать, насколько вы опытны и уверены в себе. Важно только то, что результат вашей работы можно эффективно использовать, а о применимости результата вам расскажут ваши тесты.
На мой взгляд, самое главное правило хорошего программиста звучит следующим образом:
Закрывая тикет и отправляя задачу в тестирование, вы гарантируете, что:
- Тестирование не выявит багов в вашем коде.
- Тестирование не выявит проблемы регрессии, вызванные вашими изменениями.
- Закрытый вами тикет никогда не окажется в статусе Reopened.
Прогоняя юнит- и интеграционные тесты, вы становитесь в состоянии дать эту гарантию.
Тесты отнимают время
Да, это правда. Тесты действительно отнимают время, но это – цена за гарантию работоспособности. Все, что вам нужно сделать (оно же и самое сложное) – найти грамотный баланс где-то между «писать тесты на все подряд» и «не писать тесты вообще». Вы можете потратить больше времени на написание тестов и быть уверенным, что ничего не упадет. Также вы можете написать меньше тестов и, соответственно, потратить меньше времени, но ошибки регрессии будут более вероятны.
Требуют ли тесты поддержки?
Довольно много раз я слышал мнение, что юнит- и интеграционные тесты требуют поддержки. Зачастую именно по этой причине их не любят.
Лично я ничего более глупого не слышал. Тесты не требуют абсолютно никакой поддержки – вы их написали и радуетесь. Если во время рефакторинга или добавления новой функциональности вы случайно что-то сломаете, тесты вам об этом расскажут (при условии, что вы нашли тот самый баланс). Как правило, бизнес-требования по уже написанной функциональности не меняются каждую неделю, поэтому и тесты нет нужды обновлять.
Да, если вам все-таки приходится обновить логику приложения в каком-то месте, то придется обновить и соответствующие тесты. Но это один случай на сто, в остальных 99 случаях тесты просто делают свою работу и не требуют внимания.
Код и тесты – единое целое
Выше я уже сформулировал главное, на мой взгляд, правило хорошего разработчика.
Вспомнить правило
Закрывая тикет и отправляя задачу в тестирование, вы гарантируете, что:
- Тестирование не выявит багов в вашем коде.
- Тестирование не выявит проблемы регрессии, вызванные вашими изменениями.
- Закрытый вами тикет никогда не окажется в статусе Reopened.
Исходя из этого правила можно сделать вывод, что код и тесты на этот код – единое целое. Не стоит рассматривать тесты как какую-то необязательную надстройку над единственно важной вещью – кодом.
Как разработчик, вы должны предоставить результат, который затем может быть эффективно использован заказчиком. Тесты помогут вам такой результат гарантировать с высокой вероятностью.
Конечно, есть и QA-отдел. Но следует помнить, что только хреновый программист отдает в QA сырой код, который он даже не удосужился проверить и запустить. Цель хорошего программиста – отдать в QA только тот код, в котором он уверен.
Отдавая сырой код в QA и приступая к следующей задаче, вы вовсе не экономите время и не становитесь более эффективным. Наоборот, вы рискуете потратить гораздо больше времени, чем это необходимо, если тестировщики вернут вам задачу на доработку. Тогда вам придется снова погружаться в контекст, искать причину ошибки и отправлять задачу на вторую итерацию. А это, как я уже говорил выше, недопустимо для хорошего разработчика.
Проще просто не допускать, чтобы задача возвращалась вам на доработку, верно? Вы потратите больше времени сегодня, но вам не придется копаться в логах завтра. К тому же, вы застрахуетесь от ошибок регресси в будущем.
Время – цена тестирования. Но помните, что время может быть как потраченным, так и сэкономленным.
Тесты на библиотеки
Стоит ли тестировать тривиальные функции и методы библиотек, которые вы используете?
Допустим, есть такая функция:
public MyObject getInstance() return new MyObject(); >
Лично я не стал бы покрывать ее тестами. Тут нет бизнес-логики, и сама функция слишком тривиальна. Суть тестирования не в том, чтобы покрыть 100% строк и веток, а в нахождении нужного баланса – что стоит тестировать, а что нет.
Библиотеки, которые вы используете в своих проектах, уже оттестированы их разработчиком и, на первый взгляд, не требуют дополнительного тестирования с вашей стороны. Но всегда может настать момент, когда вы обновляете версию библиотеки, а там старый метод начинает вести себя по-другому. С этой позиции неплохо бы иметь чисто поверхностные тесты на те функции библиотеки, которые вы используете.
Либо же, как рекомендовал Роберт Мартин, вы можете писать адаптеры к этим библиотекам, и покрывать тестами эти самые адаптеры. Это поможет вам как отловить какие-либо изменения в поведении библиотек, так и заменять либо удалять их в принципе.
Happy Path тестирование
Happy Path, когда вы тестируете только положительные сценарии, может подойти только к поверхностному тестированию библиотек. Когда вы тестируете свой код, вы должны хотеть его сломать.
Представьте, как собирается тестовый автомобиль на конвейере. При happy path после сборки тестировщик просто покрутил бы руль, поддал бы немножко газку и удостоверился бы, что машина тормозит. Но достаточно ли этого? А как же жесткое тестирование подвески, резкий старт и разгон, устойчивость в поворотах и, конечно же, крэш-тест?
В тестах вы должны ломать свой код. Не переживайте, если код написан хорошо, то он не повредится.
Проблема вовсе не в тестах
Есть еще одно расхожее мнение – проблема вовсе не в тестах, а в человеке, который сидит по ту сторону монитора. Иначе говоря, если руки растут из нужного места, а не как обычно, то вероятность ошибок автоматически исключается, и в тестах нет нужды.
Проблема в человеке по ту сторону монитора, безусловно, есть. Люди – вообще источники всех проблем. И, повышая качество исполнителя, можно достичь очень даже впечатляющих результатов.
Но тут снова есть подводный камень. Повышая свой уровень, программист становится в состоянии решать гораздо более сложные задачи, но он по-прежнему не застрахован от ошибок. Ошибки допускают абсолютно все, вне зависимости от опыта и квалификации. Со временем ошибки просто перестают быть тривиальными и становятся более скрытыми и комплексными, но они по-прежнему остаются. И только тестирование своего кода поможет вам их вовремя заметить и исправить.
Простейший пример
Буквально вчера я написал юнит-тест на кусок своего кода в полной уверенности, что увижу зеленую галочку. Однако, тест упал. И не просто упал, а свалился с позорным NullPointerException. Для более-менее опытного программиста словить NPE – это вообще стыд и срам. Если вы получаете NPE, вам следует встать коленками на горох и самолично выпороть себя на глазах у всех коллег.
А вот тот самый кусок кода (упрощенный), на котором упал тест:
public void doSomething(Boolean condition) < if (condition) < // handle condition >// handle >
Можете сразу заметить проблемное место?
Суть в том, что в метод приходит булев флаг, в зависимости от которого нужно выполнить какое-то дополнительное действие. Флаг этот не является обязательным, то есть его может не быть вовсе, и в таком случае мы должны предполагать, что он эквивалентен значению false. И тест как раз проверял вариант, когда этот флаг не передается:
doSomething(null);
Разумеется, NPE упал на этой строке:
if (condition)
Когда я поправил код, все заработало:
if (Boolean.TRUE.equals(condition))
Глаза замыливаются, и вы можете начать работать с big-B Boolean как с обычным boolean. Но у тестов есть еще одно крутое преимущество – у них ничего не замыливается, и они не ошибаются.
Вывод: тесты – ваши друзья.
Главное правило хорошего программиста
Давайте еще раз вспомним главное правило хорошего программиста.
Закрывая тикет и отправляя задачу в тестирование, вы гарантируете, что:
- Тестирование не выявит багов в вашем коде.
- Тестирование не выявит проблемы регрессии, вызванные вашими изменениями.
- Закрытый вами тикет никогда не окажется в статусе Reopened.
А соблюдать это правило вам поможет одна простая аксиома:
Тесты в разумном количестве с высокой вероятности дадут гарантию того, что задача не будет возвращена на доработку.
Заключение
Тесты – не панацея. Сами по себе они не несут никакого смысла. И только грамотное сочетания программного кода и разумного количества тестов поможет достичь нужного результата. В каждой ситуации вам стоит решать, где и как вы будете (или не будете) писать тесты на свой код, чтобы достичь цели.
В общем и целом, правило простое – чем больше тестов, тем надежнее. Однако, крайности – это всегда плохо, так что вам всего лишь стоит найти баланс
Понравилось? Подписывайтесь на меня в соцсетях!
Поиски баланса в составлении функциональных требований. Особенности Shaping’а в Shape up

Продолжаю серию статей про малоизвестную (надеюсь что пока!) методологию разработки, которая запала мне в душу. Запала настолько, что я хочу донести знания о ней до как можно большего количества людей.
Лично я за свою карьеру ни разу не встречался с проектом, про который можно было бы сказать “Не представляю как можно увеличить ценность данного продукта для пользователей.” Причина, по которой хорошие, отличные, прекрасные, волшебные “сами по себе” идеи в итоге так и остаются просто идеями, зачастую кроется в целесообразности реализации.
Малый процент идей, в первом приближении оказавшихся целесообразными, ещё ждет этап реализации. А о том, как соотносятся изначальная задумка и конечный результат, красноречиво свидетельствует тот факт, что “Ожидание/Реальность” это даже не просто мем, а целый отдельный жанр мемов.
Так как в сфере разработки ПО (чаще всего) человек с ожиданиями и человек воплощающий ожидания в реальность — разные люди, перед ними остро стоит вопрос эффективной коммуникации, в части объяснения и понимания ожиданий. Впрочем, как и во всех остальных сферах.
В рамках методологии Shape up стадия “прожарки” сырых идей до состояния оформленного артефакта, на который стейкхолдеры готовы сделать ставку (выделить время разработчиков), называется Shaping (шейпинг). Время, которым стейкхолдеры готовы рискнуть для воплощения идеи, кстати, в терминологии Shape up называется аппетитом (Appetite), так что в итоге в разработку идут самые “аппетитно” приготовленные идеи.
Процесс постановки задач и best practices описания хотелок
Так или иначе, сырые идеи (хотелки) надо превратить в набор артефактов, ориентируясь по которым можно вести разработку. Хотелки обычно описываются либо словами (условно обозначим такой способ как ТЗ), либо макетами (макеты в своём “каркасном” варианте тоже сюда относятся), либо и тем и тем сразу.
ТЗ делается сравнительно быстро, но оно не детализировано, макеты же достаточно детальны, но требуют кучу времени и, следовательно, денег на подготовку. Чтобы нивелировать индивидуальные недостатки каждого из методов, макеты и ТЗ используются в связке. Очень логично и широко распространено.
Мои претензии к ТЗ и макетам из личного опыта:
- Макеты и дизайнеры, за них отвечающие, зачастую не готовы к мобильной/адаптивной верстке, разработчикам приходится импровизировать.
- Корректировка макетов не успевает за меняющимися требованиями, которые возникают в ходе разработки. Иногда макеты морально устаревают после первой же сессии проработки задач.
- В ТЗ написано что надо сделать, но часто не описана суть решаемой проблемы, поэтому ограничены потенциальные возможности специалистов предложить решение получше.
- На более повседневном уровне работы, недостаточная чёткость и определённость описания задач и критериев приёмки является скорее правилом, чем исключением.
Потенциальная золотая середина — Shaping
Окей, можно сколько угодно ругать ТЗ и макеты, привести миллион примеров как их можно зафакапить (давайте травить байки в комментариях), но без работоспособной альтернативы и говорить не о чем. В конце концов при всех моих претензиях к планете Земля, к эмиграции на Марс я пока не готов.

Идея в том, чтобы найти процесс, который останется быстрым, при этом на выходе даст достаточно деталей, чтобы разработчики могли воплощать идею корректно, не прибегая за разъяснениями каждые полчаса. Здравая идея. Возможно ли это? Я думаю, что шейпинг в значительной степени приближается к этому идеалу.
По итогам шейпинга формируется артефакт — питч (pitch), который должен соответствовать трём критериям:
- Он не отшлифован! Результат на этапе шейпинга обязан(!) быть грубым и приблизительным. Всем должна быть очевидна незаконченность в тех местах, куда пойдут творческие усилия команды разработки.
- Кейс решён! Общее направление работы команды разработки должно быть понятно и ясно. Риски столкновения с айсбергами непредвиденной работы остаются, но вы не потратите время на выбор между вёсельной лодкой, круизным лайнером и авианосцем, этот вопрос уже определен заранее.
- Он ограничен! Чтобы заканчивать проект в рамках жесткого дедлайна жизненно важно определиться с идеями и элементами, которые пока остануться за бортом.
Эти пункты уже позволяют сориентироваться перебор или недобор по детальности проработки в твоём питче. В отличие от напутственного “Продумывай столько деталей, сколько нужно, не больше и не меньше.”
Оживляю теорию практикой
Можно было пересказать кейсы, которые представлены в книге, скорее всего они лучше доносят суть подхода, но моя личная попытка как-то милее сердцу.
Немножко предыстории. У нас в CosySoft HR’ы в этом году придумали проводить пульс-опросы, чтобы периодически выяснять умонастроение народа в целом и отдельных представителей перед ассессментом (у нас так performance review называется). Реализовано это всё на данный момент с помощью гугл-формы с опросом, из которой сформирована гугл-таблица с результатами. К таблице я по просьбе HR’ов прикрутил гугл-скрипт, обрабатывающий результаты. Под кодовым названием “светофорная обработка результатов пульс-опроса”.
Также для вышеупомянутых ассессментов в компании выстроен процесс, который тоже вёлся в гугл-формах и гугл-таблицах. Чтобы он проходил быстрее и комфортнее для всех участников, логично было свести ассесменты в единый пайплайн. Для этого в течение лета был разработан модуль в нашем внутрикорпоративном приложении. Процессы проходили примерно параллельно, и в итоге пульс-опросы, вместе с обработкой результатов, пока в этот модуль не попали.
Я выбрал перенос пульс-опроса из сервисов гугла в модуль ассессментов целью для шейпинга и написания питча. Переносить придется логику обработки и отображения результатов, не ухудшая при этом UX наших замечательных HR’ов
Этап 1 — Определение границ
Краеугольный принцип всего Shape Up — Варьируемый объем работ за фиксированное время. Поэтому логично начать с выяснения аппетита. Я выбрал цифру в 80 часов работы, потому что делать этот проект буду в свободное время, за которое конкурирует огромная куча идей. С аппетитом определились, также я исходил из посылки, что делать всё одному, и чем меньше потребуется работы на бэкэнде, тем лучше
Этап 2 — Выявление элементов
Тут-то и начинается самая мякотка и некоторые “фирменные техники”. При проектировании электронных устройств инженеры и любители пользуются макетными платами (англ. Breadboard). Суть их использования сводится к получению функционально полноценного устройства без какой-либо проработки дизайна. На этапе прототипирования нужна возможность как можно быстрее и легче перебирать варианты гипотез, время думать о деталях еще не пришло.
В Basecamp адаптировали эту концепцию под прототипирование решений бизнес-задач. И даже переназывать не стали, так и говорят — Breadboarding (брэдбординг). Выглядит это примерно так. Если нам для решения задачи нужно “перейти к списку покупок”, а потом “утвердить список покупок”, то в виде “брэдборда” это будет выглядеть как то так:

Каждый из трёх пунктов может быть воплощён множеством разных способов и выглядеть кардинально по разному. Но даже вот так, мне как программисту, уже понятно, какую пользовательскую задачу я решаю.
Не уверен, что текстом можно выразить мысль с такой же наглядностью, и точно уверен, что нельзя за сравнимое время выдать хоть какой-то макет, который выразит тоже самое. С учётом существования всего остального приложения, с которым этот макет обязан согласовываться.
Плюс этот набросок совсем не жалко выкидывать если в ходе дальнейшей проработки окажется, что это не то, что нам нужно. Sunken cost околонулевой и защищать эту идею, потому что на неё было затрачено время, а не потому что она ценная, вряд ли кто-то станет.
В итоге я выявил такие элементы своего будущего решения:

- Первое что пришло в голову — надо как-то попадать на экран с аналитикой пульс-опроса. На существующей вкладке аналитики ассессментов уже дофига всего происходит, пусть аналитика по пульс-опросу живет на отдельном, самостоятельном экране. Ссылка на переход туда будет жить рядом с иконкой аналитики.
- На экране аналитики по пульс опросу должно быть две зоны — подробности по конкретному разделу и овервью результатов.
- Между конкретными разделами с подробностями надо как-то переключаться.
Этап 3 — Выявление рисков
В разработке и тестировании широко известен такой термин как “Golden/Happy path” — сценарий, в котором все факторы, не контролируемые разработчиком (пользователи, смежные системы, устройство пользователя, интернет и вообще вселенная в целом), сработают в точности так, как от них ожидается. Иными словами — это предположение, что всё пройдет точно по нашему изначально намеченному плану.
У хороших разработчиков со временем развивается умение до некоторой степени предвидеть непредвиденное, потому что они в ходе своей карьеры “повидали некоторое дерьмо”. Ведь никогда и ничего не идёт точно по плану. На мой взгляд именно навыка прогнозирования рисков жизненно не хватает людям на менеджерских позициях.
Поэтому зачастую, когда неучтённый риск материализуется в неожиданную проблему, людям приходится придумывать решения на ходу, выбирая из плохого и очень плохого. С весёлым бонусом в виде острого дефицита времени.


Обратите внимание, что пока всё будет идти хорошо, невозможно будет заметить разницу. Разница проявит себя в виде внезапно подкравшейся жопы.
Какие риски я выявил в своей идее
Главный риск, который мне пришёл в голову — непонятная ситуация с бэкэндом. Бэк модуля написан на Scala, которую я безмерно уважаю, даже немного её осваивал сколько-то времени назад, но в обычной профессиональной жизни я фронтендер, и нормально написать хоть что-то в заданных временных рамках, у меня точно не получилось бы.
Поэтому я сразу для себя решил делать максимально простой бекенд из всех возможных. Что потребовало небольшого исследования АПИ гугл скриптов, но в итоге я решил, что буду собирать большой JSON-объект он будет просто передаваться на фронт, и там я уже буду с ним разбираться как мне надо. Для первой версии приемлемо, “progress over perfection”! Это пример одного из trade-off’ов для достижения цели (поставка ценных для пользователей фич в установленные сроки), которые Shape up всячески поощряет. Здесь я обменял своё представление как должен выглядеть бекенд “по хорошему”, на минимизацию объёма работ в области, где я не обладаю достаточной экспертизой.
Ещё один вопрос, который возник в ходе анализа рисков — “что делать с историей ответов пользователя на пульс-опрос?”. В существующей гугл-таблице эта функциональность отсутствует, но вместе с тем в модуле ассессментов история прошлых ассессментов вполне себе предусмотрена. Прикинув на глаз, я решил, что сейчас это не must-have функционал, и делать я его в этот раз не буду. Это будет так называемый “No-go”, что надо будет отметить отдельным пунктом в питче.
Этап 4 — Написание питча
Обычный питч включает в себя 5 компонентов:
- Описание проблемы.
- Описание решения.
- Предполагаемый аппетит.
- Кроличьи норы — потенциальные риски из-за которых можно выйти за рамки аппетита, если пытаться решить на ходу. Отвечает на вопрос: “Что делать если в ходе реализации возникнет проблема Х?” Чтобы максимально обезопасить себя от факапа дедлайна, решение как обойти эти кроличьи норы принимается на этапе шейпинга и прописывается в питче явно.
- То чего в рамках данного проекта делать не надо (No-go’s) — тоже принимаемые заранее решения для более четкого определения границ проекта.
Описанные в таком формате требования впоследствии оставят достаточно свободы программистам, чтобы те не чувствовали себя т.н. code-monkeys и могли применить свою креативность и экспертизу. И дизайнерам тоже будет где разгуляться и проявить свои навыки. И позволяют организовать настоящую конкуренцию идей, за счёт скорости создания подобного артефакта.
С удовольствием почитаю мнения, желательно обоснованные, на тему соответствия моего питча заявленным выше критериям (Неотшлифованность, решенность кейса, ограниченность фронта работ).
Мои впечатления по итогам эксперимента
Так как я разработчик и описанием требований не занимаюсь обычно, у меня не особо большая база для сравнения с точки зрения процесса. Я больше с результатом взаимодействую по долгу службы. Однако, процесс шейпинга мне понравился тем, что с основными моментами я определился за пару часов одного вечера и довёл до нужной кондиции ещё за час другим вечером.
Касательно результата мне очень нравится четкое описание проблемы и свобода принятия более мелких решений на своё усмотрение. Хотелось бы не быть человеком-оркестром в этом приключении, чтобы быть более объективным. Но пока мне по-прежнему нравится Shape up и хотелось бы его потестить в боевых условиях.
Мотивационная цитатка про шейпинг вместо заключительного слова
“Когда проекты лучше зашейплены, у них более чётко определены границы, что позволяет командам разрабатывать более автономно. Когда команды более автономны, люди наверху могут тратить меньше времени на управление командами.
Тратя меньше времени на управление командами, люди наверху могут лучше шейпить следующие проекты.”
- shape up
- shaping
- agile
- эксперименты
- идеальный мир
- функциональные требования
- удобство работы
- менеджмент проектов
- эффективность
- творческий процесс в it