Мой любимый рецепт приготовления программных продуктов
Есть много способов приготовить картошку. Вот тут написано больше 100 способов. Рецептов кофе существует множество. Лично я предпочитаю черный, без сахара. Кто-то любит с молоком, кто-то предпочитает холодный. Бессмысленно спорить, какой из них лучше.
Способов организовать разработку программного обеспечения наверняка существует не меньше, есть куча нюансов и разных методов, подходящих на любой вкус и кошелек.
Я не готов спорить и говорить, что какой-то из них лучше других, естественно, у каждого есть свои предпочтения. Я всего лишь хочу поделиться своим любимым рецептом приготовления программного обеспечения. Может быть вам тоже понравится.
Программный продукт - не цель, а средство решения проблемы
Что такое программный продукт? Это такой сложный способ решать проблемы. Одно из самых ярких открытий, которые я сделал за свою жизнь программиста, заключалось в том, что программы, которые я пишу, никому не нужны. Никому кроме меня и, может быть, нескольких коллег рядом, неинтересны структуры классов, архитектурные решения и алгоритмические нюансы. Заказчика, который в итоге платит деньги за работу программистов, интересует не программа, а решение проблемы, бизнес-задачи - привлечение клиентов, эффективная работа отдела склада, яркие эмоции от игры, ну и т.д. И качество программного продукта не в том, насколько он классно запрограммирован или стильно сдизайнирован, а в том, насколько он пригоден и приспособлен для решения той задачи, для которой предназначен. Если игра красивая, быстрая, но скучная - в неё не будут играть. Если CRM система надежная и быстрая, но сложная и непонятная - ей не будут пользоваться. Если интернет-магазин имеет вау-интерфейс, с анимациями и картинками, но покупатель не может найти нужный товар, то клиенты уйдут в другой магазин.
Вывод 1
Приготовление программного продукта начинается с изучения проблемы, для решения которой он предназначен. Если этот шаг пропустить, продукт может получиться не очень полезным и, как следствие, его будет сложнее продать.
Анализ проблематики
В современной действительности изучением проблем занимаются продакт-менеджеры и бизнес-аналитики. Они общаются с пользователями, проводят исследования, ставят эксперименты. Результат их работы бывает разный. Часто они не только изучают проблему, но и сразу придумывают решение, которое формулируют в виде задачи на разработку.
Здорово, если разработка достаточно быстрая и есть возможность провернуть несколько итераций и доработать. В этой ситуации можно не упираться в точность и полноту требований, если что-то пошло не так - это будет быстро исправлено.
Кстати, если продукт, который вы разрабатываете сложен, а переделки и доработки обходятся дорого, то может быть не нужно отправлять сразу в разработку то, что придумали аналитики или продуктологи?
Может быть есть более дешевый способ убедиться в том, что это именно то, что нужно сделать?
Часто получается, что результат вроде бы полностью соответствует требованиям, но при этом пользоваться им так, как задумывал автор требований, почему-то нельзя. Обычно какие-то очевидные (автору требований) аспекты не были написаны в задаче явно, при разработке их не учли, и результат получается грустным, а переделывать уже долго.
Немножко помогает снизить этот эффект включение в постановку явного описания проблемы. Добиться вовлеченности команды разработки в продукт и так непросто, а если задача сформулирована так, что непонятно зачем все это делается, то мотивация и вовсе сходит на нет. Понимание цели задачи помогает оперативно принимать разумные решения в тех местах, которые требования обходят вниманием.
Вывод 2
В задание на разработку стоит включать не только требования к ПО, но и описание проблемы, задачи, которую должен решать продукт. Как это делать - не так важно, выбирайте инструмент на свой вкус.
Неплохим инструментом для передачи такого описания является формулировка UserStory, которая включает в себя цель взаимодействия с продуктом (и которую часто опускают :) . В сложных случаях можно использовать описания UseCases, в них тоже присутствует цель, задача, ради которой все затевалось. Небольшая подсказка для самопроверки - цель всегда находится за границами продукта и не связана с ним непосредственно.
Пример:
Я выбираю продукты в интернет магазине не чтобы положить их в корзину, а чтобы приобрести. Корзина - лишь один из способов достичь цели.
Выбор решения
Итак, проблема, потребность выявлена, описана. Можно приступать к разработке? Если у вас гениальные разработчики, которые сами все схватывают не лету и умеют не только писать классы/функции, но и находить решение бизнес-задачи - то да, можно сразу отдавать потребности в разработку. Собственно, техника UserStories на это и рассчитана - когда или продукт достаточно прост, или команда достаточно опытна и компетентна, в результат одну историю можно реализовать за разумное время и можно ограничиться тем, что держать в бэклоге набор историй для реализации.
Увы, так бывает не всегда. В сложных, узкоспециализированных доменах разработчики могут быть не очень глубоко погружены в предметную область, плохо понимать потребности клиентов и способы их решения.
Поэтому перед тем как отдавать в разработку кто-то должен найти способ решения пользовательской проблемы, достижения его целей с помощью программного продукта. Часто этот способ не единственный и тут появляется интересный момент, очень важная часть рецепта. Не нужно искать идеальный способ решения.
Во-первых, он часто недостижим, так как у разных людей понятие идеальности разное. А во-вторых, еще более часто идеальный способ оказывается неоправданно дорогим в реализации. Дорогим во всех смыслах - и в смысле затрат, и в смысле сроков.
Важно помнить, что при разработке ПО мы редко занимаемся благотворительностью. Мы всего лишь создаем способ решения проблем и задач, который более привлекателен, чем другие доступные способы. Он либо более удобен, либо более дешевый, либо более эффективный (т.е. фактически удельно обходится дешевле или позволяет заработать больше, чем на него тратится) Стоимость реализации софта очень важна, если переборщить с затратами - проект закроют, а команду разгонят.
Так что хитрость этого рецепта не в том, чтобы найти самый лучший/удобный/прекрасный способ решения проблемы, а в том, чтобы найти самый оптимальный способ решения проблемы с учетом имеющихся технологических и ресурсных ограничений в рамках доступных сроков и бюджетов на реализацию.
Этим обычно занимаются совместно системные аналитики (которые смотрят на имеющиеся возможности системы и комбинируют из них решение, проектируют взаимодействие и автоматизируемые бизнес-процессы) и архитекторы (которые определяют состав компонентов для разработки, формулируют запросы на изменение, проектируют API и выбирают технологии для интеграции между системами и подсистемами).
Задача это действительно сложная и творческая, так как когда есть ограничение минимум с двух сторон (и задача, которую надо решить, и сроки/бюджеты), то очевидное решение не всегда пригодно. Иногда удается придумать что-то действительно необычное, а иногда приходится идти на компромиссы.
Очень важное замечание. Дешевое решение не должно быть синонимом плохого решения.
Пример из жизни
Решение, которое мы разрабатывали, умело разворачиваться в отказоустойчивой конфигурации, но, к сожалению, не для всех компонентов. Были интеграционные компоненты, которые "из коробки" не поддерживали кластеризацию.
Был запрос от одного из заказчиков, чтобы эти компоненты тоже можно было резервировать и автоматически переключаться на резервный в случае отказа основного.
Делать это "по настоящему", по "продуктовому" с красивой настройкой, автоматическим переключением на уровне инфраструктурных сервисов, прозрачным подключением к кластеру со стороны клиентов было слишком дорого, бюджет проекта это сделать не позволял.
Однако буквально за пару-тройку дней удалось реализовать нужное поведение наложенными средствами, периодически пингуя состояние доступности сервиса и в случае сбоя изменяя на лету конфигурацию системы, переключаясь на резервный компонент. Все нужное поведение размещалось в одном скрипте, в параметрах конфигурации которого была жестко закодирована информация об основном и резервном компонентах.Такое решение закрывало потребность, соответствовало требованиям по времени недоступности сервиса в случае отказа, вписывалось в бюджет проекта и при необходимости могло использоваться в других проектах.
Да, было не очень изящно в плане конфигурирования и настройки, вместо красивых графических экранов нужно было лезть в конфиги. Но оно решало проблему, было лаконичным, изолированным, пригодным для повторного использования.
Уточнение деталей
Но кроме указания цели и решения важно (опять же - явно) включать в постановку те аспекты, которые важны для достижения результата. Заранее сказать, какие аспекты окажутся важными сложно, у каждой команды и продукта свои особенности. Полезно составить чеклист аспектов, на которые стоит обращать внимание при постановке требований и разработке.
Грустные примеры из жизни:
В требованиях не было написано, что все поля должны быть одним шрифтом и расположены по одной линии. Из разработки вышла форма, в которой поля "гуляют" по горизонтали влево-вправо, пара полей отличается по начертанию от остальных. Форма выглядит уродливо и неопрятно.
Естественно, включать в каждую постановку на разработку интерфейсной формы требования, что она должна быть ровной и приятной для глаз - это идиотизм. Это должно быть одним из пунктов чеклиста как при проектировании макетов, так и непосредственно при разработке форм.
В требованиях не было явно написано, что при попытке уйти со страницы нужно предупредить, что несохранённые данные будут утеряны. Результат - случайный щелчок мышью по другим ссылкам на странице (наприме в навигационном меню) приводит к потере данных, которые пользователь уже ввел в форму, но еще не отправил на сервер.
Такой проблемы можно избежать, если в чеклист описания требований формы включить пункт "явно указывать, является ли форма модальной и как должна себя вести при попытке с неё уйти"
Чеклист для контроля качества требований сложно составить сразу. Это живой, изменяющийся артефакт, подстраивающийся под текущие потребности. Важно не забывать, что он должен быть и должен использоваться в рабочем процессе, даже если он состоит всего из одного пункта.
Вот примеры аспектов, которые имеют свойство теряться и забываться при постановках:
Как будет происходить управление доступом к разрабатываемой функции? Кому доступна функция по-умолчанию?
Какие записи должны попадать в журналы аудита?
Поведение в нештатных ситуациях - отказ сети и т.п.
Бонус. Самый важный пункт чеклиста для постановки задачи: "Автор постановки задачи понимает и может объяснить/обосновать все, что указано в постановке. Постановка задачи не содержит элементов и описаний, которые непонятно зачем нужны и как работают."
Пора готовить
И только теперь, когда постановка задачи пропиталась всеми нужными деталями, можно запекать - отдавать в разработку.
Хорошая постановка задачи содержит:
описание проблемы, которую надо решить,
описание предполагаемого решения (которое уже протестировано на прототипах, демонстрациях и интервью, т.е. есть уверенность, что это решение действительно решит ту проблему, ради которой затевалось),
примерный способ реализации (который позволяет достаточно точно оценить, сколько это займет времени и какие компетенции для этого нужны).
Такая постановка задачи позволяет сделать более предсказуемой не только разработку, но и тестирование. Описание потребности и способа решения позволяет спланировать тест-кейсы еще до того, как первый вариант кода выйдет из разработки.
Заключение
Фактически, весь процесс разработки ПО разделяется на две части:
Изучение потребностей и постановка задач
Разработка ПО в соответствии с постановками
Если вы разрабатываете сложные системы и для вас важна предсказуемость качества, сроков и затрат, то в бэклоге команды разработки должны лежать задачи, которые "готовы к разработке".
Данный рецепт нацелен на то, чтобы большая часть неопределенностей снималась до разработки. Первая часть рецепта призвана существенно снизить вероятность рисков, которые могут привести к заметному увеличению сроков разработки или к тому, что полученное решение окажется неприменимым в той ситуации, для которой разрабатывалось.
Отмечу, впрочем, что разработка может активно участвовать и в первой части. Устранение неопределенностей может идти, например, путем быстрого создания и переделки прототипов с целью выявления важных атрибутов будущего решения, которые потом пойдут в основной поток разработки в качестве требований. Но и требования к качеству, надежности и проработанности программных решений, полученных в результате таких экспериментов, будет другим.