Рубрика:
Программирование /
Жизнь. Организация
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
АДЕЛЬ ФАЙЗРАХМАНОВ, Software developer, Fujitsu GDC Russia (Казань)
Борьба с хаосом при разработке ПО
Проект по разработке программного обеспечения легко становится хаотичным и, как следствие, некачественным, трудно поддерживаемым, срывающим сроки. Рассмотрим некоторые принципы борьбы с хаосом
Часто можно услышать, что индустрия разработки ПО еще молода, недостаточно развита. Отчасти это верно. Нет сформировавшейся науки, нет свода законов, по которым можно было бы разрабатывать программы и гарантированно получать требуемый результат. Возможно, когда-нибудь, в светлом будущем, студентам соответствующих специальностей вместе с курсом «Программирование» начнут преподавать курс «Разработка ПО», где будут объяснять, каким образом применять навыки программирования, чтобы в результате получались качественные программные продукты. Но в настоящее время разработчикам приходится опираться лишь на некоторые правила, сформировавшиеся из опыта уже нескольких поколений. Они не дают какие-то гарантии, но невыполнение их часто ведет к сорванным срокам, некачественным продуктам, а иногда и к полному провалу проекта. Об этих правилах я и хотел бы поговорить в данной статье.
Прежде всего нужно сказать, что некоторые пункты из нижеописанного не действуют на проекты, которые разрабатываются одним человеком. Некоторые – ненужны для проектов с малым количеством пользователей. У каждого проекта – свои условия и свои методы борьбы с хаосом.
Монолитность
Код хорошего проекта должен производить впечатление написанного одним человеком в одно время, вне зависимости от того, сколько реально человек его писали и сколько времени это заняло.
Заранее должно быть установлены стандарты кодирования (наименование классов, функций, форматирования стандартных операторов), разделения кода по файлам и даже заранее должен быть выбран разделитель новой строки (Windows- или UNIX-style).
Но все это лишь поверхностные признаки, они обязательны, но их не так сложно придерживаться. Более сложная цель – концептуальная целостность. Фредерик Брукс посвятил ей главу в своей книге «Мифический человеко-месяц». Краткий смысл главы в следующем: для проекта следует выбрать Главного Архитектора, который создаст изначальную архитектуру и будет решать любые более-менее крупные архитектурные вопросы. Другие разработчики должны наступить на горло своим амбициям, своему мнению и использовать только решения Главного. Звучит спорно, реализуемо сложно, но плюсы в перспективе перевешивают минусы. Монолитность – это все-таки одна из обязательных черт хорошего проекта.
Система управления версиями
Любой проект, который разрабатывается дольше, чем один день, должен храниться в SVN, TFS либо в старенькой CVS, либо в модных распределенных системах git, Mercurial, Bazaar. Разработчик, хоть раз участвовавший в проекте с использованием системы хранения версий, почти наверняка согласен с этим утверждением. Я опишу здесь некоторые правила хорошего тона при использовании VСS (Version Control System – «Система управления версиями»).
Коммит (или Check-In) – это отдельное изменение кода в репозитории VCS. Наиболее частый тип коммита – изменение нескольких файлов в соответствии с заданием (например, добавить метод в какой-то класс, вставить его вызов в другом классе). Правило: «Каждый коммит должен быть снабжен комментарием». Комментарий не должен быть особенно большим (его написание не должно отнимать много времени), но в нем нужно описать все изменения, которые были произведены над кодом. Идеальный случай: задание в трекере (о нем речь пойдет ниже) реализовано полностью данным коммитом, тогда комментарий прост – номер таска и его наименование.
Рассмотрим более сложную ситуацию. По таску необходимо добавить новую функциональность в старый класс. Разработчик видит, что добавление этого функционала чревато слишком большими и трудоемкими изменениями, и решает немного улучшить (отрефакторить) данный класс. Вполне разумно отрефакторить класс, сделать коммит с комментарием «Класс такой-то отрефакторен». И лишь потом добавить новый функционал с комментарием в стиле «#1234 Добавлен новый вариант выходных данных(JSON)». Здесь мы подошли к еще одному правилу: «Каждый коммит должен содержать какой-то смысл, который можно описать парой предложений, и желательно один». Все эти правила нужны для удобного и легкого просмотра истории изменений. Операция эта достаточно частая при командной разработке («А кто поменял этот класс? И с какой целью?»), и очень неприятно видеть, когда кто-то из разработчиков решил, например, произвести автоформатирование (в проекте не были приняты стандарты форматирования) и закоммитить одновременно с выполнением какого-то изменения. Попробуйте где-то среди этой большой кучи изменений найти замену оператора = на +=. Всегда разделяйте два разных по смыслу изменения в два разных коммита.
Также необходимо помнить о возможности ветвления проекта в VCS. Если разработчик или группа разработчиков делает какое-то большое изменение, которое может затронуть проект (сломать компиляцию или повалить юнит-тесты), то необходимо это изменение вести в отдельной ветке. Почти все современные VCS поддерживают ветвление в какой-то мере, и надо этими возможностями пользоваться.
Система управления проектами
Использование системы управления проектами или ее упрощенного варианта – багтрекера также уже является стандартом де-факто для современного проекта. Важность ее для долговременных проектов трудно переоценить. В случае багтрекера это лишь средство слежения за ошибками и недоработками проекта, полученными от пользователей, тестеров или самих разработчиков. На каждую ошибку создается тикет в багтрекере, в котором описывается сама ошибка, способ ее воспроизведения, возможно, скриншоты. В общем, любая информация, которая окажется полезной при вылавливании бага. Дальнейшая судьба тикета определяется поставленным процессом. Либо освободившийся разработчик назначает тикет на себя, либо менеджер назначает его определенному разработчику, и начинается работа по отладке. Далее тикет может перейти к другому разработчику. Например, при отладке было замечено, что проблема идет из БД, тогда тикет переназначается разработчику БД (это люди, разрабатывающие серверную логику на таких языках, как PL/SQL, T-SQL и т.д.). В большинстве случаев это заканчивается тем, что ошибка в системе исправляется, тикет переходит в состояние «Исправлен», и человек, его создавший, получает уведомление об этом по почте.
При использовании системы управления проектами в тикетах содержатся не только баги, но и любые другие задания: создание нового функционала, изменение существующего, изучение разработчиком новой технологии, необходимой для проекта. В систему также включены элементы тайм-менеджмента. Каждый тикет перед началом работы с ним оценивается по времени. Каждый работник (дизайнер, верстальщик, программист, менеджер) во время работы списывает потраченное на него время. Как итог – у менеджера полная информация о временных параметрах текущих заданий, что помогает при планировании и распределении задач. Списанные на задачи часы могут быть основой для начисления зарплаты, если разработчики работают по почасовой ставке. Особо творческие менеджеры могут получать различные графики, например, эффективности команды или отдельных ее участников.
Спецификации
Одно из самых ненавистных занятий разработчиков – это написание спецификаций. «Кому они нужны? Их же никто не читает!» Отчасти это верно. Именно отсутствие привычки читать спецификации делает их написание бесполезным занятием. Это еще одна разновидность проблемы курицы и яйца – не пишем, потому что не читают, не читают, потому что читать нечего. Спецификации бывают технические и функциональные. Функциональные описывают внешнее поведение системы: что она может, как ею управлять и т.д., из нее потом вырастают руководства пользователя, система помощи в программе, FAQ на сайте... Техническая спецификация описывает внутреннюю кухню системы: архитектуру, внутренние механизмы и другие важные для разработчиков детали. Наличие функциональной спецификации важнее наличия технической, однако я сейчас говорю о программистских проектах и программистах и хотел бы поднять тему технической спецификации.
Часто можно встретить ситуацию, когда весь проект сильно зависит от одного программиста, который создавал архитектуру, знает все приемы. Его десятки раз в день отвлекают от работы вопросами другие разработчики. Это раздражает его, но и где-то глубоко греет душу. Он незаменим. Страшно представить, что случится с проектом, если этот разработчик покинет его. А как же долго входят в проект новые разработчики! Это все – очень плохие признаки и вечная головная боль менеджера.
Эти проблемы и призвана решать техническая спецификация. В ней должны быть описаны все базовые архитектурные принципы системы: как разрабатывать новый модуль, каких принципов придерживаться при расширении существующего, как в системе идут различные процессы, все вспомогательные системы (например, в случае международного сайта – как получить текущие страну и регион пользователя).
Наличие хорошей технической спецификации может сильно повысить производительность команды, что в конечном счете окупит временные траты на ее написание. Она также может устранить проблему незаменимости некоторых разработчиков для данного проекта. Без нее невозможно достичь монолитности крупного проекта. Главное, не забывать держать ее в актуальном состоянии. Проекты постоянно меняются изнутри, спецификация не должна отставать от них.
Юнит-тестирование
Думаю, мало кто из разработчиков не слышал о юнит-тестах. Они дают проекту массу пользы: тесты являются одним из видов документации отдельных классов (по ним очень просто понять, как использовать тот или иной класс), значительно повышают надежность некоторых рефакторингов (можно не заметить какую-то деталь, а провалившийся юнит-тест подскажет нам, что мы сломали именно последним изменением, и можно легко это исправить). Процент покрытия кода юнит-тестами является одним из важных параметров проекта. Таким важным, что некоторые заказчики вставляют в требования к проектам покрытие тестами кода не менее 50 (75 или даже 100) процентов кода.
О том, как и когда писать юнит-тесты, существует очень много мнений. Доминирующей сегодня является методология TDD, при которой код пишется или изменяется только тогда, когда тест, который этот код проверяет, проваливается. В классическом TDD процесс разработки выглядит очень непривычно для людей неосведомленных. Надо разработать класс, реализующий некий функционал. Пишется тест, который сразу проваливается. Потом пишется класс и метод, который самым простым способом выполняет условия теста (буквально доходит до конструкций вида «return 1;»). Далее пишется еще один тест, который опять проваливается, и код, который старается выполнить его. В процессе можно проводить некоторые рефакторинги, устранять копирование кода. И такие итерации повторяются до тех пор, пока по набору тестов, которым удовлетворяет код, нельзя будет сказать, что класс удовлетворяет требованиям.
Разумеется, немногие используют такой подход в чистом виде. Делают некоторые послабления, например, не теряют времени на простейшие решения, удовлетворяющие тесту, потому что знают, что придется реализовывать «нормальный» функционал.
Непрерывная интеграция
В больших системах количество юнит-тестов велико, и программисты при разработке запускают только те, которые проверяют ту часть кода, с которой они сейчас работают. Однако для системы важно, чтобы работали все тесты и, если какой-либо из тестов не прошел, то нужно, чтобы разработчики узнали об этом как можно раньше. Данную проблему, вместе с некоторыми другими, решает концепция непрерывной интеграции.
Реализация этой концепции очень ресурсозатратна, поэтому для нее обычно выделяется отдельный сервер. На него ставится специальный софт (Hudson, TeamCity, CruiseControl или другие), который по расписанию или после каждого коммита забирает последнюю версию исходного кода из системы контроля версий, прогоняет все тесты и сигнализирует, если какие-то тесты не пройдены. Кроме выполнения тестов на сервере непрерывной интеграции можно выполнять много других полезных задач. Например, ежедневная (ночная) сборка проекта. Для компилируемых языков можно собирать полные релизные, тестовые и другие версии.
Я привел некоторые принципы, которые ведут проекты из хаоса к порядку. Мы, программисты, редко любим порядок. Хочется писать код, используя свои приемы, а не принятые на проекте, коммитить, когда захочется, заниматься задачей без предварительной оценки по времени, о спецификациях даже говорить нечего. Даже юнит-тесты не все любят.
Менеджерам (если они хорошие менеджеры, конечно), наоборот, присуща любовь к порядку. Здесь находится один из фронтов противостояния, и крайне важно для успешности проекта, чтобы менеджер его выиграл. Я говорю как разработчик.
Тестирование
Нельзя обойти вниманием и то, от чего напрямую зависит качество проекта. Можно строго выполнять все, что написано выше, но выпускать некачественный продукт. Отдавать пользователям продукты, не прошедшие функционального тестирования – верх неуважения. Некоторые продукты не будут приняты заказчиком, пока не пройдут тестирование на безопасность. Изменения высоконагруженных приложений часто проходят обязательные тесты на нагрузку и производительность.
Во многих компаниях решение о выпуске релиза или обновления зависит только от начальника отдела тестирования, поскольку только он может сказать, удовлетворяет ли продукт нужному уровню качества. Небольшие компании не могут позволить себе содержать целый отдел тестирования, но любой команде, которая выпускает продукты для пользователей, необходим хотя бы один тестер, который будет проводить функциональное тестирование. Он протестирует каждую кнопку, каждый пункт меню, пройдет по пользовательским сценариям и, я уверен, найдет кучу ошибок, которые в случае отсутствия тестирования достались бы пользователям.
***
Целью данной статьи было рассказать о некоторых практиках и пользе от них. В наше время доступна немало возможностей для их реализации: большое количество программ (часто бесплатных), множество статей в Интернете, общение с другими разработчиками (как в Интернете, так и на различных конференциях). Необходимо лишь понять, каких практик не хватает вашему проекту сегодня, и двигаться. От хаоса к порядку.
- Коллекция статей на тему гибких методик разработки: рефакторинг, TDD, шаблоны проектирования и т.д. – http://wiki.agiledev.ru.
- Блог Джоэля Спольски. Масса интересных мыслей о нашей индустрии – http://www.joelonsoftware.com. Русские переводы статей: http://local.joelonsoftware.com/wiki/Russian.
- Макконнелл С. Совершенный код. – Прекрасная книга, охватывающая весь процесс разработки ПО и описывающая множество полезных практик.
- Брукс Ф. Мифический человеко-месяц. – Книга написана 25 лет назад, читать ее трудно, но многие базовые вещи, описанные там, совсем не изменились.
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|