процесс разработки


Начну с небольшой истории. Жил был проект, и работало над ним три программиста. Начиналось все очень бодро и весело – за неделю была создана демострационная версия, показывающая принципиальную осуществимость задачи проекта на одном маленьком примере. Потом за две недели был создан и доведен до уровня пригодности к использованию пользовательский интерфейс. Потом для демонстрации финансовому директору была добавлена фича X, а для демонстрации генеральному – фича Y. Руководство было в восторге от темпов и легкости решения задач, которые раньше казались неразрешимыми. Шло время, новые фичи добавлялись одна за другой. Затем было решено взять эту разработку и: ставить во все филиалы, в 10 раз увеличить количество пользователей, продавать ее другим организациям (нужное подчеркнуть). Тут выяснилось, что не все так гладко. То и дело из программы вылезали странные ошибки, не поддающиеся воспроизведению. Программа регулярно падала без объявления войны. Изначальные предположения о данных не оправдывались, и требовалась немедленная доработка, чтобы продолжать работать с какой-нибудь нетипичной информацией. Где-то раз в неделю пользователи натыкались в программе на очередное сообщение об ошибке, использующее английские матерные выражения для большей экспрессивности. Развертывание системы на каждом новом сервере было кошмаром. Разработка замечательных новых функций замедлилась, команда тратила все больше времени на исправление ошибок и техподдержку. В общем, запахло жареным. Знакомо, не правда ли?

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

  1. Не надейтесь на чудо. Я знаю людей, которые считают, что “вычистить код”, который писался полгода – дело нескольких недель. Безнадежные оптимисты… Фред Брукс в своем “Мифическом человеко-месяце” пишет, что качественный программный продукт требует для разработки в три раза больше ресурсов, чем отдельная программа с аналогичной функциональностью. Разница между затратами на разработку прототипа и готовой версии – такого же порядка. Документация, инсталлятор, устранение ошибок и повышение общего качества кода – все это требует времени. Если ваш прототип не предназначался для сейлз-презентаций, добавьте время придумывание и реализацию хорошего пользовательского интерфейса. На стадии прототипа у вас нет ничего вышепересиленного Значит, придется делать все это на стадии трансформации в продукт, и это действительно долго. Так что не надейтесь на чудо. И всеми средствами уничтожайте подобные надежды вашего руководства (в частности, см. пункт 6).
  2. Объявите новый этап проекта. Стиль разработки продукта сильно отличается от разработки прототипа. Например, при создании продукта нужно перестать срезать углы и вместо быстрых решений использовать правильные. Обеспечить высокое покрытие тестами всего кода, Обрабатывать все ошибки, которые могут возникнуть. Обращать внимание на производительность. Совсем по-другому подходить к тестированию и оценке критичности найденных ошибок. Едва ли будет ошибкой сказать, что по-другому нужно будет подходить практически к каждому аспекту разработки. Даже если разработчики знают об этом эффекте, им будет тяжело переключиться. Помогите им. Проведите общее собрание и объявите о начале нового этапа проекта. Напомните, что приоритеты кардинально изменились и дайте им время осознать и прочувствовать это. На некоторое время оторвите всех от написания кода, например, проведите серию встреч по восстановлению задач проекта, основных проектных решений, архитектуры. Если проект длинный, то отправьте всех участников в недельный отпуск – им будет легче переключиться.
  3. Ротация разработчиков. Когда долго работаешь над одной задачей, то критическое восприятие ее притупляется. Если у вас хотя бы два разработчика, пусть они поменяются участками работ. В результате у каждого разработчика будет свежий взгляд на задачу, что поможет ему легче преодолеть инерцию и перейти в новый режим работы. Кроме того, так вы можете гарантировать, что хоть один человек посмотрит на код критическим взглядом (см. пункт 7).
  4. Заменяйте прототип по кускам. Ни в коем случае не выкидывайте весь прототип, чтобы начать с чистого листа. В коде накапливается множество знаний о нюансах, которые вы никогда не сможете получить из спецификации. Кроме того, очень удобно, когда в любой момент у вас на руках есть работающий продукт. Таким образом, гораздо лучше, если вы будете постепенно заменять модули прототипа кодом продуктового качества. Наверняка вы захотите параллельно с этим преобразовать стихийно сложившуюся архитектуру прототипа в что-нибудь более стройное и логичное – это тоже возможно. Пусть каждый разработчик перечитает книгу Мартина Фаулера “Рефакторинг” – и вперед. В некоторых случаях вместо проведения рефакторинга проще написать новый модуль с чистого листа и заменить им старый. Это тоже хороший вариант, главное, – обратите особенно внимание на то чтобы не сделать в новой версии неочевидных ошибок, которые уже были сделаны при написании прототипа; для этого вам пригодится рецензирование кода (пункт 7).
  5. Используйте юнит-тесты! Возможно, для прототипа вам удалось обойтись вообще без тестов. Или достаточно было нескольких тестов, проверяющих базовые сценарии использования. Для продукта этого недостаточно. Вам понадобится много тестов. Обеспечьте высокий процент тестового покрытия. Теперь вам недостаточно знать, что программа корректно работает в трех основных презентационных сценариях, вам нужна уверенность в том, что программа будет корректно работать и во всех исключительных случаях. Это недостижимый идеал, но в ваших интересах приблизиться к нему. По моему опыту, разумный минимум – это более 85% code coverage во всех тестируемых модулях (некоторые модули вообще нет смысла тестировать, не включайте их в эту статистику)
  6. Визуализируйте изменения. Скорее всего, вам будет тяжело объяснить заказчику или спонсору проекта, почему над готовым прототипом нужно работать еще столько времени, чтобы сделать из него продукт. Если спонсор проекта – человек, далекий от программирования, то вам будет очень тяжело. С точки зрения спонсора, проект практически готов, и требуется лишь немного времени на доводку. Вы же собираетесь потратить больше времени, чем было затрачено на разработку прототипа. Чтобы облегчить свое положение, сделайте так, чтобы увидев рабочую версию, можно было в течение 5 секунд получить представление о степени ее готовности. Помните, что непрограммист может оценить состояние проекта только по состоянию интерфейса. Поэтому начните новый этап с того, что испортите интерфейс продукта, так чтобы его качество примерно соответствовало качеству содержимого. Покажите этот интерфейс заказчику и объясните, что примерно в таком состоянии находится весь продукт в данный момент. По мере продвижения к готовому продукту постепенно улучшайте интерфейс, чтобы продемонстрировать внутренние изменения.
  7. Отрецензируйте каждую строку кода. Если вы последуете предыдущим советами, то не начнете реализацию продукта с чистого листа, а будете трансформировать прототип, последовательно заменяя его модули переработанными модулями продуктового уровня качества. Здесь есть одна опасность – имея на руках работающую систему, вы можете забыть, что часть ее – это модули из прототипа, вероятно, не обладающие нужным уровнем качества. Если в итоговый продукт попадут такие модули, то через некоторое время вы будете иметь дело с очень забавными ошибками – вылетом программы при вводе неправильного значения, отсутствием проверки прав доступа к функции, отсутствием валидации вводимых данных, “кривыми” сообщениями об ошибках и т.д. Чтобы этого избежать, надо гарантировать, что ни одна строка непроверенного кода из прототипа не попадет в итоговый продукт. Лучший способ – систематически использовать рецензирование кода (code review), которое должно проводиться разработчиком, не являющимся автором кода. О том, как правильно проводить рецензирование кода, можно прочитать здесь. Будет здорово, если вы добавите в весь исходный код прототипа информацию о том, что рецензия еще не проводилась, например с помощью комментариев “This block needs code review”, напишете небольшой скрипт для сбора статистики о количество строк неотрецензированного кода в проекте, и использовать эту статистику как один из показателей степени завершенности продукта. Обратите особое внимание на проверку всех интерфейсов и сообщений об ошибках! В итоговый продукт ни в коем случае не должны проникнуть ни опечатки, ни “тестовые” тексты (”Здесь будет подробное сообщение об ошибке”) из прототипа.
  8. Напишите спецификацию. Возможно, спецификации, по которым создавался прототип, покрывают только небольшую часть функциональности. Возможно, прототип создавался вообще без спецификаций. Это нормально для прототипа. Но для продукта вам понадобятся спецификации. В первую очередь для того, чтобы проверить предполагаемую функциональность и архитектуру на логичность и внутреннюю непротиворечивость: если вам очень трудно выразить словами свое представление о том, как должен работать продукт, значит, его надо сделать проще. Если создателям продукта сложно его понять, то каково будет пользователям? Потратьте время на то, чтобы функциональность вашего продукта можно было легко описать в спецификации, это окупится.

Очень обидно осознавать, что около года назад, когда перед проектом, которым я руководил, стояла задача трансформации прототипа в продукт, я даже не увидел, что начинается новый этап разработки. Из вышеперечисленных техник для стабилизации продукта были использованы только юнит-тесты и спецификации. И то и другое – в недостаточном количестве. Соответственно, качество продукта было весьма плачевным. От этого не спас даже очень высокий профессиональный уровень разработчиков – даже самый лучший разработчик не напишет код промышленного качества, если он концентрируется на какой-то другой задаче. Чтобы улучшить ситуацию понадобилось больше полугода… Что ж, теперь я знаю, насколько важно правильно перейти от создания прототипа к созданию продукта.

Материалы по теме:

  • Джоэль Спольски отлично пишет об опасностях старта с чистого листа в своей статье “Things you should never do, part I”.
  • Джоэль Спольски пишет про важность визуализации прогресса проекта в интерфейсе в своей статье “The Iceberg Secret, Revealed”.
  • Иван Сагалаев пишет об интересном способе построения интерфейса для прототипов: “Черновой стайлинг”.

« Previous Page