«

»

Jan 26

Идеальный процесс разработки – утопия или Continuous Integration?

Какой такой Continuous Integration?

Существуют немало приемов облегчающих разработку и сопровождение программ в промышленных масштабах – тестирование, система управления версиями, система отслеживания ошибок, автоматизированная система сборки и развертывания и т.д. Continuous Integration – объединяет все эти компоненты в единое целое, работающее по гибким правилам оптимальным для компании или проекта.

Continuous Integration глазами непосвященных

Continuous Integration глазами непосвященных

Процесс разработки програмного обеспечения – достаточно скользкая тема. Про нее много писано и модно говорено, но нередко, при общении с коллегами, возникают абсурдные ситуации – когда вроде все знают как хорошо и по-правильному, но работают по старинке – самоотвержено борясь с одними и теми же проблемами. Программисту сложно объяснить старшему (младшему, да и вообще, любому) менеджменту преимущества процесса разработки с точки зрения бизнеса. А не-программист (даже если он и руководитель) не знает с чего начать, чтобы заинтересовать свой отдел в процессе разработки не путем номенклатурного воздействия, а конкурентными преимуществами следования процесу разработки, заточенного под нужны отдела и специфику компании.

Эта статья – некоторая выжимка как теории так и опыта, которую можно взять за основу (а можно и не брать) при обсуждении светлого будущего с манагерами и между разработчиками.

Примерный сценарий как бы это могло выглядеть в до приторности идеальном мире:

Разработчик неторопливо потягивает кофе попутно изучая свежую прессу в виде rss-ленты его излюбленных блогов. Внезапно раздается тревожное треньканье и одновременно в жаббер и на емейл приходит оповещение что где-то приключилась беда. В письме указана ссылка на внутренний портал, где можно прочитать описание ошибки, которую необходимо исправить. Программист делает суровое лицо супермена и логинится в веб-портал системы управлению проектами, выбирая раздел баг-трекер. В списке новых работ одиноко мерцает тревожным желтым огоньком не закрытая задача – значит приоритет срочности средний. Он читает описание проблемы. Ошибку создал один из заказчиков, а служба поддержки уже запросила первичную информацию о среде окружения, версии продукта, воспроизводимости ошибки и т.д. Теперь дело за ним – повелителем битов и байтов! Он решительно переводит ошибку с представителя службы поддержки на себя и изменяет ее статус на “В работе”. Заказчик и тех-саппорт сразу же получают оповещения о том, что отдел разработчиков не дремлет.

– Итак, – размышляет разработчик, – для начала надо попробовать воспроизвести проблему! Для этого надо взять самую свежую версию продукта. Это проще простого – прямо через веб-интерфейс легким кликом мыши инициируем checkout проекта из системы контроля версий – весь исходный код, все зависимости и вспомогательные утилиты устанавливаются на машине разработчика. Так вот сразу лезть в код боязно, он все еще верит в доброе и светлое и надеется, что удастся обойтись малой кровью – поэтому запускает команду “быстренько все собрать и развернуть прям-как-для-продакшн на тестовом сервере №1”. Процессоры пыхтя перелопачивает все потоки сборки стремясь не вызвать у разработчика раздражения из-за мучительно долгого билда. Тем временем, на тестовом сервере производится создание новой виртуальной машины, воссоздается конфигурация идентичная установленой у заказчика. Развертывается база данных, создаются пользователи, запускаются сервисы и, в конце-концов, только что собранный продукт, еще с пылу с жару, устанавливается на подготовленную чистую систему.

Разработчик сверяется с предоставленным пользовательским сценарием ( use case – инструкцией – как же воспроизвести проблему – обязательный полем в описании ошибки в системе улучшения качества продукта):
– Сюда ввести вот это, выставить вот такой таймаут… Ага! Вот оно! Почему то стерлись все данные в базе. Хмыыыы. Придется лезть в код…, – смиряется он с неизбежным и отодвигает недопитое кофе на край стола – в свое время, рыцари примерно с таким же энтузиазмом опускали забрало при виде недобитых ветряных мельниц.

Пока проект загружается программист размышляет: “Хорошо что все свои предпочтения можно выставить один раз для всего проекта и при любом чекауте автоматически весь код будет индентирован так, как ты привык, в специальной директории будут аккуратно сложены свеже-сгенерированные файлы проектов для той самой, единственной IDE, которая всем IDE IDE, а если каких-то зависимостей на машине разработчика нету – они будут скачаны с билд-сервера, причем именно той версии, которая должна быть использована для этой версии проекта. При этом я могу сразу заняться работой, а не тратить дни на борьбу с инструментами.”

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

Стремительный полет мысли, пулеметная дробь от ударов по клавишам – как будто бы фикс готов. Пробуем прогнать проблемный сценарий – вуаля! ошибка не возникает.

Что ж, приходит время для добавления исправлений в основную ветвь разработки. Разработчик вновь набирает всего одну комманду и, откинувшись в кресло, следит что ему торопливо пишут pre-commit скрипты. Первым делом они обновили его версию кода (вдруг кто-то внес какие-то правки пока он искал ошибку). После этого был инициирован “быстрый билд” – когда проект собирается под все платформы (чтобы сразу заметить не сломан ли билд) и прогоняются только самые главные тесты. Нововведения проверяются статическими анализаторами кода на соответствие проектным стандартам и индентируются в соответствии с корпоративными стандартами. И наконец код добавляется в репозиторий, в отдельную(!) ветку.

Тут за работу берутся post-commit скрипты – сразу запуская “большой билд” во время которого прогоняются все самые пустяковые проверки – чтобы гарантировать, что внесенные изменения не поломали чего-то еще. В это же время самые суровые коллеги нашего героя получают приглашения провести code-review вместе с раскрашенным diff-ом измененных файлов и ссылкой на описание ошибки и вынести свой вердикт – нужен ли такой код проекту.
Пока они выражают свое одобрение мастерству и стилю, отмечая про себя ранее не виданные методы и тем самым професионально растя над собой – все тесты завершаются с зеленым статусом.

“Все в порядке!”, заключает программист изучив прямо на портале логи билда и тестов, “все в порядке” – подтверждают коллеги-ревьюверы и он с чистой совестью нажимает кнопку merge (слияния ветки посвященный багу за нумером таким-то и основной линии разработки). После чего переводит задачу в статус решено и возвращается к кофе. В это время собирается патч и отсылается клиенту.

Подобные сценарии (в том или ином приближении) обычное дело в компаниях где процесс разработки строится вокруг и на основе методик Continuous Integration/Continuous Delivery – системы непрерывной интеграции\системы непрерывного развертывания – как противовес явлению метко описываемому на английском как Integration Hell. Если бы было необходимо описать эту систему парой фраз это были бы: “всегда есть рабочая версия”, “оно само собралось”, “все всегда в курсе”.

Структуру ее можно представить в виде отдельных модулей примерно так:

Из чего состоит Continuous Integration

Из чего состоит Continuous Integration

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

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

5 “простых” шагов для внедрения Continuous Integration

Готовой инструкции, как ваш проект перевести на новые рельсы нет и быть может. Но начать можно с этого.

1) Реорганизация кода

Цели у данной задачи две:
собираться все должно быстро (+ см. пункт 2). (стремиться надо к тому чтобы минут десять занимал обычный билд, не более часа – полный – со всеми тестами)
– должна быть возможность прогнать авто-тесты по отдельным модулям/компонентам.

Нет, полный рефакторинг делать не надо. (вернее, может и надо, но не сразу – помните какая цель у данного шага)
Проект разбивается на независимые модули. Которые собираются раздельно друг от друга.
К проекту, разбитому на маленькие функциональные части легко писать авто-тесты. Его легче сопровождать.

Минус – очень сложно выбрать золотую середину и вовремя остановиться. Почаще вспоминать главную цель этого шага.

2) Настройка автоматической системы сборки

Цель – в любом окружении проект собирается сам, без помощи разработчика.

Разработчик не должен тратить время сражаясь с зоопарком зависимостей и особенностями конкретной платформы.
Есть простое правило – для любой цели есть своя, одна(!) лаконичная команда. Совершенно не принципиально кто конкретно будет ее выполнять – ant/maven/cmake/make/scons/bash/… – ваш проект – вы и выбирайте. Сделать можно на чем угодно.

Минус – придется крепко помучаться разрабатывая билд-скрипты.

3) Все, все, все в репозиторий!

Цель – хранение всех рабочих версий продукта.

В любой момент – можно посмотреть на код позапрошлогоднего релиза и собрать его.
Организацию структуры репозитория я здесь обсуждать не буду. Но она:
1. должна быть
2. должна быть не слишком вычурная
И да, хранить необходимо все, что нужно разработчику чтобы начать работать с кодом: все зависимости, тесты, сторонние утилиты, схемы базы данных, скрипты для загрузки тестовых данных, эмуляторы сети или хитроумных устройств.

Минусы – придется продумывать стратегию хранения – разграничение основной линии от исследовательской, по каким критериям определять возможность объединения нового кода с основной линии (код ревью, статические анализаторы и т.п.).

4) Тесты

Цель – у нас всегда должен быть рабочий продукт.

Если проект не собирается – продукт не рабочий. Если проект собирается, но не работает – продукт не рабочий.
Такой код в репозиторий попасть не должен. Может быть, абсолютно все автоматически протестировать и нельзя – но к этому определенно имеет смысл стремиться. Тестирование обязательно должно быть в pre-commit скриптах. Необязательно оно должно быть всеобъемлющее – но основные функции должны быть проверены. Апологетам теории, что есть вещи которые протестировать нельзя – давайте называть вещи своими именами – да, разработка тестов для некоторых задач не самая тривиальная вещь. Да, в некоторых случаях понадобятся объекты-заглушки, тестовые схемы данных, скрипты для эмуляции действий пользователя… Но все это сделать возможно.

Минус – объем кода для тестов может привысить размер кода продукта. Но повторяю – не обязательно сразу все – начните с критичных функций.

5) Соблюдение процесса разработки

Continuous Integration в процессе работы

Continuous Integration в процессе работы

Цель – чтобы все это заработало. Самый сложный шаг. Здесь указаны некоторые (не все!) пункты способствующие распространению идей Continuous Integration в светлые головы коллег. Повторение идей упомянутых выше не случайно.

1. На пальцах объяснить разработчикам, что одно дело, когда их рабочая копия не собирается, и совсем другое, когда основная версия из репозитория, утверждает что какой-то супостат добавил не-posix функции. накануне релиза.
2. Попробовав смержить результат двух месяцев автономной разработки с основной веткой – даже самый ярый противник каждодневных коммитов поневоле задумается. Чем чаще коммиты – тем меньше проблем при слиянии кода. У всех.
3. Поиграть в новичка на проекте – задавая уймы недалеких вопросов – тогда решение об авто-документации по сборке проекта, по зависимостям, по бизнес-логике приходит как то само собой.
4. Основная линия разработки священна и юные падованы не должны протягивать к ней свои шаловливые лапки без должного контроля.
Вносить правки в файлы конфигурации сборки – должны лишь избранные, отягощенные проклятием ответственности.
5. По коммиту должно быть легко узнать к какой задаче он привязан в баг-трекере. Кто автор. Ключевое слово – “легко” – в одно касание мыши.
6. Code Review – это не “Кто-то будет хаять мой код?!”, а обмен знаниями и масса возможностей для професионального роста.
7. Не важно кому люб Eclipse, а кто фанат Visual Studio. Билд скрипты не завязаны ни на IDE, ни на компилятор, ни на ОС разработчика. Но умеют генерить файлы проекта для любимой IDE каждого разработчика, при необходимости не чураются кросс-компиляции.
8. База данных хранится в системе контроля версий (структуры таблиц, пользователи, тестовые данные). При тестировании – создается своя, уникальная, никак не связанная с другими копия базы. Изменения в базе данных – также хранятся в системе контроля версий и привязаны к версиям продукта в виде зависимостей.
9. Тесты желательно сгрупировать по типам или целям. Так они станут быстрее и информативнее.
10. Развертывание продукта и его конфигурирование – полностью автоматизировано. Одна команда запускает все что нужно и для заказчика и для тестера и для руководителя проекта. Команд и целей для развертывания будет несколько, но скрипт пусть будет один. Не должен тестер тыкать в далее, вбивать куда-то пароли или выбирать пути установки для того чтобы начать тестирование.
11. В скрипте развертывания должна быть опция – “откатить все изменения и оставить систему какой была до установки”
12. Структуру репозиторию надо продумывать – выделять общие компоненты и зависимости между проектами, по возможности упрощать структуру – чтобы можно было легко определить где лежит исходный код, где тесты где документация.
13. Все заинтересованные люди должны быть информированы как о ходе работы по проекту (список задач, изменения их статусов, результативность разработчиков) так и о состоянии рабочей версии (результаты билдов и тестов) – Email, RSS, SMS – да как угодно.

И, на посошок, пару слов о системах CI, которые смогут объединить функции всех вышеупомянутых подсистем в одно целое:
Microsoft TFS – хорош тем что включает в себя из коробки все вышеперечисленное и мериады того упомянуто по ссылкам ниже – http://ru.wikipedia.org/wiki/Team_Foundation_Server
TeamCity (бесплатная лицензия для небольших проектов) – http://www.jetbrains.com/teamcity/
С этими лично не знаком – но, судя по отзывам, заслуживают внимания:
CruiseControl – бесплатный целиком и полностью – http://cruisecontrol.sourceforge.net/
Любопытен Apache Continuum – если ваш проект на maven – то развертывание проекта сводится к указанию pom-файла – http://continuum.apache.org/

Ссылки

Введение в Continuous Integration на русском:
http://habrahabr.ru/post/82724/

Лаконичная памятка-шпаргалка по Continuous Integration – http://refcardz.dzone.com/refcardz/continuous-integration (на момент написании статьи доступен для скачивания напрямую вот отсюда)

Фаулер про Continuous Integration:
http://martinfowler.com/articles/continuousIntegration.html
Фаулер про Continuous Integration совместно с базами данных:
http://martinfowler.com/articles/evodb.html
Фаулер про Continuous Delivery:
http://martinfowler.com/delivery.html

сравнение систем непрерывной интеграции – http://en.wikipedia.org/wiki/Comparison_of_continuous_integration_software
сравнение систем создания документации – http://en.wikipedia.org/wiki/Comparison_of_documentation_generators
сравнение систем по управлению проектами – http://en.wikipedia.org/wiki/Comparison_of_project_management_software
сравнение систем отслеживания ошибок – http://en.wikipedia.org/wiki/Comparison_of_issue-tracking_systems
Список систем для авто-сборки – http://en.wikipedia.org/wiki/List_of_build_automation_software

Литература (водится в интернетах)
Pragmatic Project Automation автор Mike Clark
Continuous Integration: Improving Software Quality and Reducing Risk автор Paul Duvall
на момент публикации есть вот тут:
!интересный! репозиторий с материалами по теме – http://buildrelease.googlecode.com/hg/Trunk/
(обратите внимание на разделы BRESystem/theory/ и, особенно, на Trunk/BreBooks)

1 comment

1 ping

  1. Evgeny

    Полезная статья!

  1. Continuous Integration для тестировщиков. Основные сведения -Bugs Catcher

    […] Идеальный процесс разработки – утопия или Continuous Integratio… […]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>