Эволюционная разработка программных систем

Программный продукт — это место где разработчики виртуально встречаются с пользователями. И часто с этой встречи обе стороны уходят разочарованными. Программа работает не так, как нужно пользователям. Недовольные разработчики спешно исправляют ошибки и устраняют замечания. Все сроки уже прошли, но проект прочно завис в стадии “готово на 95%”. Список ошибок в багтрекере растет, все раздражены. Можно ли с этим бороться?

История громких открытий, глубоких кризисов, неожиданных взлётов и падений постоянно доказывает — будущее нам неизвестно. Все люди разные, цели и желания пользователей нашей программы совсем не такие как у нас, разработчиков. Мы можем только предполагать как пользователь программы воспримет результаты нашего труда. 
Почему же каждый раз начиная новый проект мы пишем программу так, словно абсолютно достоверно знаем кто, как и зачем будет её использовать?

Все начинается с требований

Кажется очевидным, что для получения нужной программы достаточно реализовать все необходимые функции. Аналитики проводят обследование, чтобы выяснить все необходимые функции. Результатом обследования становится большое, предельно полное и подробное Техническое Задание, включающее все что удалось выяснить. А когда ближе в концу проекта неожиданно появляются новые требования и уточнения, то естественная реакция разработчиков — обвинить аналитиков в том, что они плохо провели обследование.

Разработка программного обеспечения неотделима от сбора и формирования требований. Невозможно создать хороший продукт по плохим требованиям. Программа не будет соответствовать ожиданиям пользователей и потребует значительной доработки. Как можно повысить качество собираемых требований?

К слову сказать, чем больше подписей на листе согласования Технического Задания, тем выше вероятность, что большинство согласующих его даже не читали. Увеличение количества контролирующих не повышает качество Технического Задания. Соответствующий психологический эффект называется “диффузия ответственности”.

Эволюционный подход

Чтобы не получить в итоге большого неотлаженного и перегруженного функциями монстра с кучей функций, не пытайтесь сразу строить сложную систему, а растите её постепенно. Нет смысла подробно прорабатывать детали реализации функции, пока не станет ясно насколько она действительно полезна. Расширяйте функционал только после проверки и отладки базовых принципов работы. Вносите измеримые и понятные изменения в работающую программу. Неудачное решение можно быстро убрать, а сэкономленные ресурсы использовать для новых экспериментов.

Похожим образом пишут картины. Сначала художник рисует набросок, эскиз. Эскиз не содержит деталей, но глядя на него уже можно понять что именно будет изображено на будущей картине. Потом приходит очередь первого слоя краски — оформляется фон, прорабатываются элементы переднего плана. После первого слоя — прорабатываются основные формы сюжета, определяется цветовое решение. Затем прорабатывается текстура и мелкие художественные детали.

Требования — это своего рода “генетический код” конечного продукта, а программный код — это организм, создаваемый по требованиям. Генотип биологических организмов не создаётся “с нуля”. Новые виды возникают эволюционным путём, через постепенные изменения в генотипе уже существующих видов. Эволюционное и гармоничное развитие программных продуктов невозможно без аналогичного процесса управления требованиями.

В организации управляемого потока изменений хорошо помогает визуальная техника Story Mapping. Она позволяет сфокусироваться на общих принципах работы программы, быстро определить минимальный набор функций и приступить к реализации первой версии продукта. Дополнительные требования оформляются в виде изменений и дополнений продукта в рамках общей концепции. Порядок реализации определяется не столько функциональной наполненностью продукта, сколько объёмом “полезности”, связанной с карточкой на доске. Таким образом, самые нужные, важные и полезные возможности реализуются раньше.

Не бойтесь изменений

Постоянные изменения и дополнения требований, естественно, приводят к частому переписыванию кода. Кажется, что это приведёт к росту затрат на разработку по сравнению с традиционным подходом. Опыт показывает, что при соблюдении “гигиены кода” существенно изменяется структура затрат, а не их объём. С одной стороны, пишется больше кода при реализации новых требований, с другой стороны меньше времени тратится на реализацию лишнего. Время разработки отдельных функций увеличивается, но сильно уменьшается время поиска и исправления ошибок, снижаются затраты на аналитику, тестирование и сопровождение. Легко читаемый, модульный и структурированный код упрощает параллельную работу и расширение команды. Готовая система получается быстрее и с меньшими затратами.

Пишите ясно

Легко изменять программу, в которой, подобно хорошему тексту, видна структура, определены главные и второстепенные мысли. Для описания назначения каждой функции или метода должно быть достаточно двух-трёх предложений, а тело функции не должно сильно превышать её описание. В коде должно быть ясно видно “что делается”, а “как делается” — скрыто во внешних вызовах. Такую программу легко читать и легко изменять.

Не спешите

Не спешите явно выделять уровни абстракции, до того как они понадобились. Явный уровень абстракции — это жесткий скелет программы, сильно ограничивающий её изменчивость. От неудачно выбранного скелета больше вреда, чем пользы. Однако, в большой системе определенный уровень жесткости необходим — он задаёт уровни абстракции, на которые опираются новые модули. Очень важно не блокировать возможность оформления “скелета” программы, когда для этого придет время: не смешивайте уровни взаимодействия, не создавайте лишних связей, если без этого можно обойтись и т.п.

Пишите чисто

Будьте готовы переписывать код, но не провоцируйте лишних изменений. Нет ничего более постоянного чем временное. Мы не знаем какая именно часть будет переделываться через неделю. Чем больше программа, тем выше вероятность, что именно та функция, которую вы сегодня написали, останется такой навсегда. Пишите так, чтобы изменять ваш код было легко, но так, чтобы не было необходимости его изменять. Поводом для изменения должны быть внешние причины, например новые требования.

Заключение

Мы быстро получаем “готовую” программу и получаем обратную связь от пользователей и заказчиков. Многие требования, которые когда-то казались такими важными, теряют актуальность после проверки на практике. А еще обнаруживаются направления развития, которые даже не могли прийти в голову на этапе обследования. Экономия времени на неделании “лишних” требований даёт отличную возможность для реализации действительно нужных функций.