Правила ХР (Часть1)

Соглашение о кодировании

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

Следовательно, все должны подчиняться общим стандартам кодирования - форматирование кода, именование классов, переменных, констант, стиль комментариев. Таким образом, мы будем уверены, что внося изменения в чужой код (что необходимо для агрессивного и экстремального продвижения вперед) мы не превратим его в Вавилонское Столпотворение.

Вышесказанное означает, что все члены команды должны договориться о общих стандартах кодирования. Неважно каких. Правило заключается в том, что все им подчиняются. Те кто не желает их соблюдать покидает команду.

***

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

Коллективное владение кодом стимулирует разработчиков подавать идеи для всех частей проекта, а не только для своих модулей. Любой разработчик может изменять любой код для расширения функциональности, исправления ошибок или рефакторинга.

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

***

При условии выполнения остальных требований XP, больших проблем с этим нет.
Конституция разработки ПО

Как и в любой другой теории, в XP есть аксиомы, на основе которых строится все остальное. Поскольку управление проектом - это скорее социология чем математика, то эти аксиомы выражаются в виде Билля о правах.

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

Билль о правах Разработчика
У Вас есть право знать что необходимо сделать с четкой расстановкой приоритетов.
У Вас есть право всегда делать качественную работу.
У Вас есть право просить и получать помощь коллег, менеджеров и заказчиков.
У Вас есть право делать и корректировать свои собственные оценки обьемов работы.
У Вас есть право самим брать на себя ответственность, а не получать ее назначением.
CRC Сессия

Используйте Class, Responsibilities, Collaboration (CRC - Класс, Обязанности, Взаимодействие) карточки для дизайна системы командой. Использование карточек позволяет легче приучиться мыслить обьектами а не функциями и процедурами. Также карточки позволяют большему количеству людей участвовать в процессе дизайна (в идеале - всей команде), а чем больше людей делает дизайн, тем больше интересных идей будет привнесено.

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

CRC сессия происходит так: каждый из участников воспроизводит систему говоря какие сообщения он шлет каким обьектам. Проходит по всему процессу сообщение за сообщением. Слабые места и проблемы сразу выявляются. Альтернативы дизайна также хорошо видны при симуляции процесса.

Для наведения порядка часто используется ограничение числа одновременно взаимодействующих двумя.

***

CRC Сессии позволяют делать то что нужно, а не то что хочется сделать будучи Супер Архитектором в душе. Очень важно четко следовать правилам, поменьше базарить и не бросать сессию в середине говоря “ну, дальше там все ясно”. Там-то как раз все проблемы и сидят.

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

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

User Stories пишутся заказчиком с помощью разработчиков. Заказчик помогает удостовериться что большинство желаемых функций системы покрыто User Story.

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

“Усложнять - просто, упрощать - сложно” Народная мудрость

Простой дизайн всегда легче реализовать чем сложный. Поэтому всегда делайте простейшее решение которое может работать. Если находите что-нибудь сложное - замените это чем-нибудь простым. Всегда оказывается быстрее и дешевле заменить сложный код простым до того как начнешь разбираться в сложном коде.

Рефакторите чужой код если он кажется вам сложным. Если что-то выглядит сложным - это верный признак проблемы в коде.

Сохраняйте решения насколько возможно простыми как можно дольше. Никогда не добавляйте функциональность на будущее - до того как появляется в ней необходимость. Однако имейте в виду: сохранять дизайн простым - тяжелая работа.

***

Это требование является очень проблематичным. Практически невозможно ему сразу следовать. Очень часто традиционный разработчик срывается в написание Инфрастктур, Фреймверков и Универсальных Подсистем. Приходится постоянно возвращать себя к тому что же хочет Заказчик. Это требование становится легче выполнять, если заучить мантру Это Нам Никогда Не Понадобится, и строго следовать правилу написания UnitTest-ов в первую очередь.

Приходится по капле выдавливать из себя Супер Архитектора, чтобы стать Эффективным Программистом.
Функциональные тесты

Приемочные тесты (ранее их также называли Функциональные) пишутся на основе User Story. Они рассматривают систему как черный ящик. Заказчик ответственен за проверку корректности функциональных тестов. Эти тесты используются для проверки работоспособности системы перед выпуском ее в производство. Функциональные тесты автоматизируются так, чтобы имелась возможность их часто запускать. Результат сообщается команде и команда отвечает за планирование исправлений функциональных тестов.
Частая интеграция

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

Каждая пара разработчиков должна отдавать свой код как только для этого появляется разумная возможность. Это может быть когда все UnitTest-ы проходят на 100%. Отдавая изменения несколько раз в день, Вы сводите проблемы интеграции практически к нулю. Интеграция - это деятельность вида “заплати сейчас или заплати больше позднее”. Поэтому интегрируя изменения ежедневно маленькими порциями вы не окажетесь перед необходимостью тратить неделю чтобы связать систему в одно целое непосредственно перед сдачей проекта. Всегда работайте над последней версией системы.

Для менеджера. Если разработчик не отдает изменения в больше одного дня - это ясный индикатор серьезной проблемы. Вы должны немедленно разобраться в чем дело. Весь опыт XP команд говорит что всегда причиной задержки является плохой дизайн и его всегда потом приходится переделывать.

***

Мы делаем ежедневные билды и за исключением HotFix версий, мы работаем в одной ветке исходного кода - то есть все работают над одной и той же версией кода.

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

Iteration Planning Meeting созывается перед началом каждой итерации для планирования задач которые будут сделаны в этой итерации. Для итерации выбираются User Stories, которые выбрал заказчик в плане релиза начиная с самых важных для заказчика и самых плохих (сопряженных с риском) для разработчиков. Также в итерацию включаются неработающие Функциональные тесты.

User Stories и невыполненные Функциональные тесты разбиваются на задачи. Задачи записываются на карточках. Эти карточки и есть детальный план на итерацию. Каждая задача должна быть продолжительностью от 1 до 3 идеальных дней.

Разработчики разбирают задачи и оценивают продолжительность времени, необходимого для их выполнения. Таким образом, каждый разработчик оценивает сколько времени задача займет именно у него. Это важно, чтобы конечную оценку обьема работ делал сам разработчик.

Скорость проекта определяет помещаются ли ваши задачи в итерацию или нет. Общая продолжительность задач запланированных на итерацию не должна превышать скорости, достигнутой в предыдущей итерации. Если вы набрали слишком много, то заказчик должен решить какие User Stories, отложить на следующую итерацию. Если набрали слишком мало, то надо добавить следующую User Story. В некоторых случаях можно попросить заказчика разделить одну из User Story, на две, чтобы включить часть в текущую итерацию.

Откладывание User Story на следующую итерацию может выглядеть страшно, но не позволяйте себе жертвовать рефакторингом и Unit Test-ами чтобы сделать больше. Задолженность по этим категориям быстро замедлит вашу скорость. Не делайте того, что по-вашему понадобится в следующих итерациях - делайте только то что необходимо для выполнения текущих User Stories.

Следите за скоростью проекта и отложенными User Stories. Вполне возможно, что план релиза придется переделывать каждые три-пять итераций. Это нормально. Ведь план релиза - это взгляд в будущее и естественно ожидать что ваши предсказания придется корректировать.

***

Вы будете смеятсья, но похоже, что мы не можем адекватно оценить задачу в идеальных днях. То есть оценить-то мы можем, но это оказывается неправдой. Поэтому, в последнее время мы стараемся планировать задачи в идеальных часах и разбивать User Stories на более мелкие задачи (4-8 идеальных часов).

При оценке обьема работы стоит принимать во внимание с кем в паре вы собираетесь работать. Ваш партнер может заметно повлиять на скорость работы.
Итерации

Итеративная разработка увеличивает гибкость процесса. Разделите ваш план на итерации продолжительностью от 2 до 3 недель. Сохраняйте постоянную продолжительность итерации на время проекта. Пуст итерации будут пульсом вашего проекта. Это тот ритм который позволит сделать измерение прогресса и планирование простым и надежным.

Не планируйте задач заранее. Вместо этого собирайте Планирование Итерации в начале каждой итерации чтобы запланировать что будет сделано. Также нарушением правил считается забегать вперед и делать то, что не запланировано в этой итерации. Таким образом, становится возможным держать под контролем изменяющиеся требования Заказчика.

Принимайте всьерьез сроки завершения итерации. Измеряйте прогресс в процессе работы. Если видно, что вы не сможете сделать все запланированные все задачи к сроку, то снова собирайте Планирование Итерации и оцените задачи заново и отложите часть задач.

Сконцентрируйте усилия на завершении самых важных задач, выбранных Заказчиком, вместо того чтобы иметь несколько незаконченных задач, выбранных разработчиком.

***

Мы приняли длину итерации в 2 недели. Для некоторых задач коротковато, но все равно, это хорошо, поскольку мы еще не очень точны в оценках обьемов работы.

Мы уже успели наступить на многие грабли, приведенные выше. Несколько итераций закончились с результатом в 0 (ноль) выполненных User Stories. Причина в том, что были начаты сразу несколько историй и ни одна не была закончена. Естественно, что это не совсем то, что хотел бы видеть заказчик. Поэтому, сейчас мы стараемся не начинать задачи по следующей User Story пока не закончили предыдущую.
Меняйтесь задачами

Необходимо периодически менять задачи у разработчиков для уменьшения риска концентрации знаний и узких мест в коде. Если только один человек в вашей команде может работать в данной области и этот человек уходит или вам просто надо много всего сделать в данном сегменте программы, вы обнаружите что ваш проект еле-еле продвигается вперед.

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

Команда становится намного более гибкой если все знают достаточно о каждой части системы чтобы начать работать над ней. Вместо того чтобы ждать пока “гуру” закончит работу над критическим куском кода, несколько программистов могут работать над ним одновременно.

При начале новой итерации каждый разработчик должен перейти на новую задачу. Парное программирование помогает преодолеть проблему адаптации (это значит что новый разработчик может начать работать в паре с опытным в данной области разработчиком).

Такая практика также стимулирует появление новых идей и улучшение кода.

***

До сих пор в нашей системе есть куски в которые разработчики опасаются залезать. Люди которые их писали ушли, куски вроде бы работают, но менять их опасно. Проблему можно решить с помощью рефакторинга и Unit Test-ов, но это требует времени. Это сильно тормозит работу.
Оставляйте оптимизацию на потом

Никогда не оптимизируйте ничего до окончания кодирования. Никогда не пытайтесь угадать где будут узкие места по производительности. Измеряйте!

Сделайте чтобы это работало, затем чтобы работало правильно, затем чтобы работало быстро.

***

Так оно и есть. Мы используем профайлер AQTime и обычно для ускорения системы достаточно сделать небольшие изменения в нескольких строчках кода. И заранее предвидеть подобные вещи невозможно.

thalion.kiev.ua

Март 7, 2008 — Рубрика: Практика
Метки: , , , ,