|
|
(не показано 14 промежуточных версий 6 участников) |
Строка 1: |
Строка 1: |
− | = Введение =
| + | #REDIRECT [[Непрерывная интеграция]] |
− | «Continuous Integration» — это лекарство от страха. Помогает при программировании.
| + | |
− | Dr. Zoidberg ©
| + | |
− | | + | |
− | Согласно [http://en.wikipedia.org/wiki/Continuous_Integration Wikipedia] термин Continuous Integration введен Мартином Фаулером (Martin Fowler) и Кентом Беком (Kent Beck). Данный термин был придуман ими для обозначения практики частой сборки (интеграции) проекта. Максимально частая сборка является логичным продолжением цепочки
| + | |
− | редкие сборки под релизы->ночные сборки->непрерывные сборки
| + | |
− | | + | |
− | В настоящее время Continuous Integration (непрерывная интеграция) одна из практик применяемых в семействе гибких (Agile) методологий. В подобных методологиях она удачно сочетается с другими практиками, такими как модульное(unit) тестирование, рефакторинг, стандарт кодирования. Но даже без них модно получить пользу от непрерывной интеграции.
| + | |
− | | + | |
− | = Основные принципы =
| + | |
− | | + | |
− | == Каждое изменение должно интегрироваться ==
| + | |
− | | + | |
− | Слово continuous в термине [[Continuous Integration]] означает «непрерывный/непрекращающийся». Это означает, что в идеале сборка вашего проекта должна идти буквально все время. Каждое изменение в системе контроля версий (например [[CVS]]) должно интегрироваться без пропусков или задержек. Организация ночных сборок — это хорошая практика, но это не continuous integration. Ведь результаты такой ночной сборки будут доступны лишь на следующий день, когда их актуальность для разработчиков уже значительно снижена. На практике довольно часто реализуют оба процесса и непрерывную интеграция и ночные сборки — более редкую интеграцию.
| + | |
− | В очень крупных проектах это требование иногда невозможно соблюсти, но интеграция каждые сутки это предел за который не стоит уходить.
| + | |
− | Принцип непрерывной интеграции не выполним без другого условия — «Сборка должна идти быстро».
| + | |
− | | + | |
− | == Быстрая сборка ==
| + | |
− | | + | |
− | «Сборка должна идти быстро» — точнее не более 10 минут. Если после одного небольшого коммита ваш интеграционный сервер будет уходить в 2-х часовое пыхтение на сборку, тестирование и разворачивание от этого будет мало пользы. Разработчики будут уже далеко, над решение других проблем, им будет сложно вернуться и понять причины сбоя, если таковой был. Ведь суть непрерывной интеграции в получении быстрого feedback. Вдобавок, поздний ответ с сервера может отвлечь их от другого дела.
| + | |
− | | + | |
− | В случае если все этапы процесса никак не удается втиснуть в приемлемые временные рамки можно разделить его на несколько частей. При каждом коммите производить лишь саму сборку и минимальный набор тестов (smoke tests), чтобы уменьшить время. А по ночам проводить полный цикл интеграции, результаты которого команда будет анализировать с утра. Но это скорее вынужденная мера, а не пример для подражания.
| + | |
− | | + | |
− | == Сделайте тесты ==
| + | |
− | | + | |
− | Тесты просто необходимо включать в continuous integration процесс, в противном случае вы не можете быть уверены в качестве и работоспособности своего проекта. Чем тестов больше, тем лучше, в разумных пределах конечно. Основными двумя ограничителями на количество тестов будет:
| + | |
− | * время интеграции — сборка по-прежнему должна оставаться быстрой, основное тестирование можно перенести «на ночь»,
| + | |
− | * наличие автоматизированных тестов — не все тесты требуют автоматизации, нет смысла делать автоматизированные тесты только для самих тестов, они должны быть целесообразны.
| + | |
− | | + | |
− | Чем лучше ваши тесты, тем раньше находяться ошибки и раньше исправляются. Как известно, чем раньше ошибка исправлена, тем дешевле ее исправление. Это одно из основных преимуществ практики непрерывной интеграции — снижение стоимости исправления ошибок (не всех конечно). Попутно наличие хорошего набора тестов в процессе интеграции дает больше уверенности в том, что проект работает правильно.
| + | |
− | | + | |
− | Именнно присутствие тестов одно из отличий интеграции от нажатия кнопки Build в вашей любимой IDE.
| + | |
− | | + | |
− | == Интеграция на специальной машине ==
| + | |
− | | + | |
− | Организовывать процесс необходимо на специально выделенной машине.
| + | |
− | Такая машина по своей конфигурации и набору прикладных программ должна максимально соответствовать окружению в котором проект будет развернут (production enviroment). Очевидно, что полного совпадения достичь практически невозможно — маловероятно, что эксплуатироватся программа будет на машине с установленными средствами сборки, тестирования и проч. Но точное совпадение версий операционных систем (и сервис паков) необходимо.
| + | |
− | | + | |
− | При этом это не должна быть машина разработчика или кого-то еще, это должна быть '''выделенная''' машина (можно виртуальная). Ведь зачастую проект, собранный на машине одного разработчика, не собирается на машине другого. Выделение машины для целей интеграции позволяет уменьшить риск связанный с конфигурацией программного и аппаратного обеспечения.
| + | |
− | | + | |
− | | + | |
− | | + | |
− | = Методы =
| + | |
− | | + | |
− | == Continuous Integration сервер ==
| + | |
− | | + | |
− | Хотя в принципе практика continuous integration не требует никакого технического и программного обеспечения, гораздо удобнее, проще и дешевле наладить процесс с использованием таких средств. Такие средства называются сервера интеграции (continuous integration server)- специализированные приложения для автоматизации данного процесса.
| + | |
− | | + | |
− | Наиболее известный из серверов интеграции пожалуй [[CruiseControl]]. [[CruiseControl]] это сервер для интеграции приложений на java, написанный на java. Так же широко распространен его собрат (точнее портированная версия) под .NET — [[CruiseControl.NET]].
| + | |
− | | + | |
− | Ниже приведена схема организации такого сервера интеграции:
| + | |
− | <graph>
| + | |
− | digraph G{
| + | |
− | rankdir=LR
| + | |
− | | + | |
− | Trigger [shape="box", style="filled", fillcolor="green", label="Trigger", URL="#Trigger"]
| + | |
− | BuildLoop [shape="box", style="filled", fillcolor="yellow", label="Build Loop", URL="#Build_Loop"]
| + | |
− | Report [shape="box", style="filled", fillcolor="yellow", label="Reporting App", URL="#Report"]
| + | |
− | ExtApps [shape="box", style="filled", fillcolor="yellow", label="External Applications", URL="#Инструменты"]
| + | |
− | Logs [shape="box", style="filled", fillcolor="yellow", label="Logs", URL="#Logs"]
| + | |
− | Team [shape="box", style="filled", fillcolor="green", label="Team", URL="#Team"]
| + | |
− | | + | |
− | subgraph cluster_machine{
| + | |
− | node [style=filled];
| + | |
− | label = "Build Machine";
| + | |
− | URL="#Build_Machine"
| + | |
− |
| + | |
− | subgraph cluster_server{
| + | |
− | node [style=filled];
| + | |
− | BuildLoop -> Report;
| + | |
− |
| + | |
− | label = "CI Server";
| + | |
− | URL="#Continuous_Integration_сервер"
| + | |
− | color=blue;
| + | |
− | }
| + | |
− |
| + | |
− | ExtApps->BuildLoop; /*->Logs;*/
| + | |
− | ExtApps->Logs->Report;
| + | |
− | color=blue;
| + | |
− | }
| + | |
− | | + | |
− | Trigger->BuildLoop;
| + | |
− | BuildLoop->ExtApps;
| + | |
− | Report->Team;
| + | |
− | }
| + | |
− | </graph>
| + | |
− | | + | |
− | == Ручной процесс ==
| + | |
− | | + | |
− | Хотя решение с выделенным сервером для continuous integration кажется простым и дешевым, у него есть противники. Точнее, сторонники ручного процесса. Один из таких Джеймс Шор (James Shore) в своей статье [http://www.jamesshore.com/Blog/Continuous-Integration-on-a-Dollar-a-Day.html Continuous Integration on a Dollar a Day] пишет, как правильно организовать continuous integration процесс без специализированных приложений, вроде [[CruiseControl]]. В этой статье мы не касаемся данного вопроса.
| + | |
− | | + | |
− | = Процесс интеграции =
| + | |
− | | + | |
− | Continuous integration процесс состоит из нескольких этапов, некоторые из которых обязательны, другие нет:
| + | |
− | * [[#Trigger|Trigger]] — обязателен
| + | |
− | * [[#Update|Update]] — обязателен
| + | |
− | * [[#Analyse|Analyse]] — не обязателен
| + | |
− | * [[#Build|Build]] — а как без него?
| + | |
− | * [[#UnitTest|UnitTest]] — крайне желателен
| + | |
− | * [[#Deploy|Deploy]] — нужен по обстоятельствам
| + | |
− | * [[#Test|Test]] — не обязателен, но крайне желателен
| + | |
− | * [[#Archive|Archive]] — желателен
| + | |
− | * [[#Report|Report]] — обязателен
| + | |
− | | + | |
− | == Trigger ==
| + | |
− | | + | |
− | Цикл интеграции начинается со срабатывания триггера. Это может быть одно из следующих событий:
| + | |
− | * изменение в системе контроля версий
| + | |
− | * изменение в файловой системе
| + | |
− | * определенный момент времени
| + | |
− | * сборка другого проекта
| + | |
− | * нажата «красная» кнопка
| + | |
− | * изменение на веб сервере
| + | |
− | | + | |
− | Стоит отметить, что не все CI сервера поддерживают все возможные варианты триггеров, но основные (система контроля версий и файловая система) поддерживаются большинством.
| + | |
− | | + | |
− | Характерным примером будет случай, когда один из разработчиков делает коммит в систему контроля версий. Для интеграционного сервера это означает, что в исходном коде проекта произошли изменения и необходимо провести сборку для проверки того, что эти изменения ничего не испортили и согласуются с ранее сделанными. После этого наступает следующий этап.
| + | |
− | | + | |
− | == Update ==
| + | |
− | | + | |
− | На данном этапе CI сервер делает update своей локальной копии исходного кода проекта. В процессе update выясняются изменения в коде (и не только) произошедшие с последненй интеграции. Выяснение изменений необходимо для того, чтобы в случае сбоя можно было легко выяснить причину и найти ответственного.
| + | |
− | | + | |
− | == Analyse ==
| + | |
− | | + | |
− | После того, как свежая версия проекта вытащена из системы контроля версий, но сборка еще не начата, можно провести статический анализ кода.
| + | |
− | Существует множество автоматических средств, для различных языков программирования, позволяющих провести такой анализ. Обычно измеряются следующие характеристики кода:
| + | |
− | * наличие типичных ошибок
| + | |
− | * статические характеристики кода: сложность, размер, прочее
| + | |
− | * соответствие принятым стандартам кодирования
| + | |
− | * другое
| + | |
− | | + | |
− | Данный этап является необязательным для процесса continuous integration, но в случае его наличия можно получить дополнительный преимущества от введения практики в виде метрик по коду. Данный этап подразумевает не только получение статических характеристик кода, но и их включение в отчеты создаваемые сервером интеграции (о отчетах смотрите [[#Report|здесь]]).
| + | |
− | | + | |
− | == Build ==
| + | |
− | | + | |
− | Один из основных этапов процесса это сборка проекта. Здесь происходит компиляция (трансляция) исходных кодов в исполнимые файлы или какой-то другой результат. Поскольку сервер интеграции представляет собой специально выделенную машину (смотрите [[#Интеграция_на_специальной_машине|здесь]]) со строго определенной конфигурацией, результат только этой сборки можно считать конечным. Больше никаких «Проект собирается на моей машине!». Есть только одно место, где проект может собираться — это интеграционный сервер.
| + | |
− | | + | |
− | Естественно сборка является обязательным этапом интеграции.
| + | |
− | | + | |
− | == UnitTest ==
| + | |
− | | + | |
− | В методологии Extreme Programming модульное (unit) тестирование является неотъемлемой частью разработки приложения. Модульные тесты изначально автоматизированы, их включение в процесс интеграции крайне желательно. Поскольку часто у разработчиков нет времени или желания запускать такие тесты до того как изменения отправлены в систему контроля версий, дополнительное их исполнение никогда не будет лишним.
| + | |
− | Дополнительную информацию можно извлечь, измеряя покрытие модульных тестов. Эта метрика поможет лучше контролировать качество выпускаемого продукта.
| + | |
− | | + | |
− | Естественно, при отсутствии самих тестов в проекте этот этап не выполним. Хотя наличие поставленного процесса непрерывной интеграции без модульных тестов заставляет задуматься об их необходимости.
| + | |
− | | + | |
− | == Deploy ==
| + | |
− | | + | |
− | После того как мы убедились в некоторой работоспособности проекта — он собирается (этап [[#Build|Build]]) и все модульные тесты проходят ([[#UnitTest|UnitTest]]) проект необходимо «развернуть». В случае веб-приложения это выкладывание на веб-сервер (сервер приложений) и запуск. Для GUI приложений это (пере)установка в системе.
| + | |
− | | + | |
− | Этап развертывание должен проходить как можно более «чисто», подробнее смотрите [[#Интеграция_на_специальной_машине|здесь]]. При этом для последующего тестирования часто необходимо привести приложение в некое «стандартное» состояние:
| + | |
− | * «залить» дамп базы
| + | |
− | * настроить в стандартном режиме
| + | |
− | * убрать следы предыдущей деятельности приложения
| + | |
− | | + | |
− | == Test ==
| + | |
− | | + | |
− | После того ка приложение «развернуто» необходимо его протестировать. Здесь имеются ввиду автоматические функциональные тесты, иначе говоря на данном этапе проводиться регрессионное тестирование.
| + | |
− | | + | |
− | После прохождения регрессионных тестов можно считать, что интеграция прошла успешно и в проект не внесено правок, которые могут привести к его неработоспособности (здесь все зависит от вашего набора тестов модульных и функциональных). В противном случае интеграция не успешна — код содержит ошибки и требуется его исправление/доработка.
| + | |
− | | + | |
− | Тестирование это один из «фатальных» этапов процесса, ошибка на котором означает сбой сборки. Всего есть несколько таких «фатальных» этапов:
| + | |
− | * [[#Build|Build]] — проект не собирается
| + | |
− | * [[#UnitTest|UnitTest]] — модульные тест не прошли или покрытие упало ниже заданного уровня
| + | |
− | * [[#Test|Test]] — регрессионные тесты не прошли или покрытие упало ниже заданного уровня
| + | |
− | | + | |
− | Иногда к ним присоединяют этап [[#Analyse|Analyse]] — если в коде обнаружено несоответствие стандартам кодирования, то это является ошибкой.
| + | |
− | | + | |
− | == Archive ==
| + | |
− | | + | |
− | После того как достигнута максимальная уверенность в качестве исходного кода необходимо сохранить его. Это можно сделать, например, посредством меток в системе контроля версий. Так же необходимо сохранить бинарные файлы проекта. Они могут понадобиться, если нужно будет воспроизвести ошибку в конкретной версии и для ручного тестирования.
| + | |
− | | + | |
− | Continuous integration процесс можно использовать как формализацию процесса передачи версии проекта на тестирование. К примеру можно настроить сервер публиковать свежую версию каждые две недели и сообщать об этом тестировщикам по электронной почте. Тестировщики всегда будут знать откуда брать свежую и «правильную» версию. А наличие регрессионных и модульных тестов является своего рода первичным (smoke) тестированием и гарантирует (в некоторой степени конечно) работоспособность данной версии. Таким образом на тестирование не попадет версия, которая имеет существенные недостатки препятствующие тестированию.
| + | |
− | | + | |
− | == Report ==
| + | |
− | | + | |
− | В конце идет важный этап генерации и публикации отчетов. Отчеты включают в себя следующее:
| + | |
− | * причина сборки — например изменения в репозитории
| + | |
− | * изменения в исходных кодах — здесь возможны два варианта изменения от последней сборки или от последней успешной сборки
| + | |
− | * отчеты по статическому анализу кода — все результаты какие есть
| + | |
− | * лог сборки
| + | |
− | * лог модульных тестов — какие тесты прошли и, что важнее, какие не прошли
| + | |
− | * лог регрессионных тестов — аналогично модульным тестам
| + | |
− | * статистика сборок проекта:
| + | |
− | ** общее число удачных/провальных сборок
| + | |
− | ** распределение удачных/провальных сборок во времени
| + | |
− | ** статистика результатов статического анализа кода
| + | |
− | * все другие метрики используемые и собираемые в проекте — это поможет менеджеру проекта видеть все и сразу
| + | |
− | | + | |
− | Механизм публикации отчета может быть разный и даже не один. Это может быть IRC или jabber бот, рассылка по электронной почте, публикация на web или ftp сервере, специализированные клиенты позволяющие узнать статус сборки.
| + | |
− | | + | |
− | Наиболее эффективна публикация результатов несколькими различными методами сразу. Например рассылка короткого письма команде, только в случае провала сборки, и публикация полного отчета на веб сервере.
| + | |
− | | + | |
− | Для правильной организации данного этапа важно понимать кого и как необходимо оповещать о результатах интеграции. Здесь надо выбрать между двумя крайностями — оповещать всегда или никогда. Примерное решение этой задачи будет таким:
| + | |
− | * разработчики — минимум при сбое интеграции, в противном случае, как разработчик узнает, что внесенные им изменения сломали код? Конечно, можно оповещать и всегда, это зависит от частоты сборок.
| + | |
− | * тестировщики — если они входят в команду, то оповещать тогда же, когда и разработчиков, ведь иногда ошибки могут быть и в тестах. Если практикуется независимое тестирование вообще не оповещать их или оповещать при окончании интеграции.
| + | |
− | * менеджер проекта — сугубо по желанию
| + | |
− | | + | |
− | = Профиты =
| + | |
− | | + | |
− | Так какую пользу можно получить о внедрения непрерывной интеграции в своем проекте?
| + | |
− | | + | |
− | В первую очередь это безболезненная интеграция всего проекта. Интеграция различных модулей и правок разных программистов перестает быть делом в принципе, она происходит «сама» без участия людей и если что-то не так, вы об этом узнаете. Конечно, сейчас редкость, что проект имеет особую стадию интеграции, когда из кучи разных модулей пытаются сделать приложение, но все же не надо недооценивать пользу от непрерывной интеграции.
| + | |
− | | + | |
− | Больше никаких «Это работает на моей машине!». Если что-то не работает на сборочном сервере — значит оно не работает вообще. Аргументы программиста, что у него все работает в данном случае не помогут. Сервер интеграции становиться судьей в таких вопросах и этот судья беспристрастен.
| + | |
− | | + | |
− | Все анализаторы кода и тесты, которые вы используете и написали, обязательно запускаются над каждой сборкой. Если в систему контроля версий попал «плохой» код — вы об этом узнаете. И не важно, нарушен ли один из стандартов кодирования, или статический анализатор кода показывает, что в код попала потенциальная ошибка или тесты не прошли, а может просто покрытие кода модульными тестами упало ниже необходимого минимума. Вы об этом узнаете и сможете принять меры.
| + | |
− | | + | |
− | Более того, запуск всех этих анализаторов полезен не только для определения состояния в текущий момент времени, но и для анализа тенденций. Можно увидеть, когда ваш код стал сильно больше, сложнее, в каких модулях эта сложность сконцентрирована. Да, это требует наличия и использования соответствующего инструментария.
| + | |
− | | + | |
− | Чем больше и серьезней проведена работа по настройке сервера интеграции, тем больше пользы можно получить. Если ваш сервер просто собирает проект после каждого изменения в коде, то пользы от него почти нет, но и усилий на него почти не потрачено.
| + | |
− | | + | |
− | = Continuous Improvement =
| + | |
− | | + | |
− | После того как вы наладили процесс непрерывной интеграции вам может показаться, что дело сделано: сервер работает, билды собираются, почта идет и все хорошо, пока нет никаких ЧП (вроде поломки сервера). Но это не так. Сам процесс требует постоянной наладки, подстройки. Если сначала у вас не было никаких тестов, то их нужно сделать. После вы захотите собирать информацию о покрытии вашего приложения тестами, затем изменение такого покрытия во времени, возможно какие-то еще специфичные метрики. Ну, а если оказалось, что больше улучшать нечего, подождите какое-то время и такая необходимость появится.
| + | |
− | | + | |
− | = Ссылки =
| + | |
− | | + | |
− | == Публикации ==
| + | |
− | | + | |
− | * [http://www.martinfowler.com/articles/continuousIntegration.html Continuous Integration] — статья Мартина Фаулера (Martin Fowler) по Continuous Integration
| + | |
− | * [http://www.jamesshore.com/Blog/Continuous-Integration-on-a-Dollar-a-Day.html Continuous Integration on a Dollar a Day] — статья Джеймса Шора (James Shore) о ручном методе интеграции
| + | |
− | * [http://blogs.msdn.com/mswanson/articles/169058.aspx Automated Continuous Integration and the Ambient Orb] — статья Майка Свонсона (Mike Swanson)
| + | |
− | * [http://c2.com/cgi/wiki?ContinuousIntegration c2.com] — статья по Continuous Integration в wiki на c2.com
| + | |
− | * [http://en.wikipedia.org/wiki/Continuous_Integration en.wikipedia.org] — статья по Continuous Integration в Wikipedia
| + | |
− | * [http://ru.wikipedia.org/wiki/Непрерывная_интеграция ru.wikipedia.org] — статья по непрерывной интеграции в Википедии
| + | |
− | | + | |
− | == Инструменты ==
| + | |
− | | + | |
− | === Сервера интеграции ===
| + | |
− | * [http://cruisecontrol.sourceforge.net CruiseControl] — сервер интеграции для Java (см. так же [[CruiseControl]]).
| + | |
− | * [http://studio.thoughtworks.com/cruise-continuous-integration ThoughtWorks Cruise] — коммерческий сервер интеграции от компании ThoughtWorks (есть бесплатная версия).
| + | |
− | * [http://ccnet.sourceforge.net CruiseControl.NET] — сервер интеграции для .NET (см. так же [[CruiseControl.NET]])
| + | |
− | * [http://cruisecontrolrb.thoughtworks.com CruiseControl.rb] — сервер интеграции для Ruby.
| + | |
− | * [http://hudson.dev.java.net Hudson] — open-source сервер интеграции, создан как альтернатива [[CruiseControl]]. Функциональность расширяется плагинами.
| + | |
− | * [http://bitten.edgewall.org Bitten] — open-source сервер интеграции написанный на [[Python]], интегрируется с [[Trac]].
| + | |
− | * [http://www.jetbrains.com/teamcity/index.html TeamCity] — коммерческий сервер интеграции от компаниии JetBrains для java и .NET (есть бесплатная версия).
| + | |
− | | + | |
− | === Инструменты сборки ===
| + | |
− | * [http://ant.apache.org Ant] — средство сборки для Java
| + | |
− | * [http://maven.apache.org Maven] — средство сборки для Java
| + | |
− | * [http://nant.sourceforge.net/ NAnt] — аналог Ant под .NET
| + | |
− | | + | |
− | === Статический анализ ===
| + | |
− | * [http://pmd.sourceforge.net PMD] — анализ кода Java
| + | |
− | * [http://findbugs.sourceforge.net Findbugs] — анализ кода на типичные ошибки
| + | |
− | * [http://www.redhillconsulting.com.au/products/simian/ Simian] — поиск повторов (copу+paste) в коде Java
| + | |
− | * [http://www.gotdotnet.com/team/fxcop/ FXCop] — анализ кода .NET
| + | |
− | * [http://qalab.sourceforge.net/index.html QALab] — объединение логов нескольких инструментов анализа кода, сбор статистики
| + | |
− | * [http://www.panopticode.org/ Panopticode] — объединение логов нескольких инструментов анализа кода для Java, графическое представление результатов
| + | |
− | | + | |
− | === Модульное тестирование и покрытие ===
| + | |
− | * [http://junit.org JUnit] — де-факто стандарт модульного тестирования Java
| + | |
− | * [http://testng.org TestNG] — инструмент нового поколения для модульного тестирования Java
| + | |
− | * [http://www.nunit.org/ NUnit] — модульные тесты для приложений .NET
| + | |
− | * [http://cobertura.sourceforge.net Cobertura] — измерение покрытия кода модульными тестами для Java
| + | |
− | * [http://www.atlassian.com/software/clover/ Clover] — анализ покрытия кода тестами для Java
| + | |
− | * [http://www.cenqua.com/clovernet/ Clover.NET] — анализ покрытия кода тестами под .NET
| + | |
− | | + | |
− | | + | |
− | [[Категория:Программирование]]
| + | |
− | [[Категория:Тестирование программного обеспечения]]
| + | |
− | {{replicate-from-custiswiki-to-lib}}
| + | |