Непрерывная интеграция (CI)
Оглавление
- Определение
- Источники
- Зачем CI
- Базовая договоренность команды
- Ключевые практики CI
- Вспомогательные практики
- Ежедневный цикл разработчика в CI
- Коротко
- Вопросы и ответы
Определение
Непрерывная интеграция (Continuous Integration, CI) — это практика разработки ПО, при которой участники команды часто интегрируют свои изменения в общую основную ветку, а каждая интеграция сразу проверяется автоматической сборкой и тестами, чтобы как можно раньше находить ошибки интеграции и не накапливать «интеграционный ад».
В двух словах
CI = частые маленькие интеграции в одну основную ветку + самопроверяемая автоматическая сборка после каждой интеграции + немедленная починка сломанной сборки.
Источники
- Перевод статьи Мартина Фаулера на Scrum.ru: scrum.ru
- James Shore: jamesshore.com — на русском: «Непрерывная интеграция за доллар в день» (Хабр)
- Martin Fowler — “Continuous Integration Certification”: martinfowler.com
- LeSS (Less.works) — Technical Excellence / Continuous Integration: less.works
- Trunk-Based Development: trunkbaseddevelopment.com — на русском: trunkbaseddevelopment.ru

Extreme Programming Explained — Kent Beck (Pearson — на русском: «Экстремальное программирование»)
Continuous Integration: Improving Software Quality and Reducing Risk — Paul M. Duvall, Steve Matyas, Andrew Glover (MartinFowler.com (Books) — на русском: Лабиринт)
Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation — Jez Humble, David Farley (Addison-Wesley / InformIT — на русском: Вильямс)- Видео: “What is Continuous Integration?”
- Видео: “Top 10 Rules For Continuous Integration”
Зачем CI
- Ранний сигнал: ошибки интеграции проявляются через часы, а не недели.
- Стабильная база: команда работает от «известно хорошего» состояния системы.
- Дешевле исправлять: чем меньше разрыв между интеграциями, тем проще локализовать причину.
- Предсказуемость: «то, что в репозитории, собирается и проходит тесты» становится реальным обещанием.
Базовая договоренность команды
CI начинается не с инструмента, а с договорённости:
Код в репозитории всегда должен успешно собираться и проходить тесты.
Если этот принцип не является нормой, ни CI‑сервер, ни «ночные сборки» не дадут эффекта.
Практичный способ “проверить, что у вас действительно CI, а не CI‑театр” — быстрый тест (в пересказе Фаулера):
- каждый в команде коммитит/пушит в общую mainline минимум ежедневно;
- каждый такой коммит запускает автоматическую сборку и тесты;
- при падении сборки она обычно возвращается в “зелёное” состояние в течение ~10 минут (или выполняется откат до последней зелёной).
Если сборка и проверки выполняются только на изолированных feature‑ветках, а интеграция в общую mainline происходит редко, команда часто попадает в «CI‑театр»: инструмент есть, а ценность CI (минимизация рискованных интеграций) — нет.
Ключевые практики CI
- CI — это практика разработки, а не “настроенный сервер”
- Инструменты помогают, но CI живёт в ежедневных привычках: маленькие шаги, частая интеграция, локальная проверка и дисциплина быстро чинить дефекты.
- Опасная ловушка — “CI‑театр”: пайплайн есть, но разработчики интегрируются редко и избегают основной ветки.
- Единый репозиторий
- В репозитории хранится всё, что нужно для сборки и запуска: скрипты сборки, тесты, конфигурация, схемы/миграции БД, зависимости и т. п.
- Идеал: взять «чистый» компьютер → скачать код → запустить одну команду → получить работающую систему.
- Одна основная ветка (mainline)
- Большую часть времени разработка идёт в одной общей ветке; ветвление — минимально и по необходимости.
- Автоматизированная сборка “одной командой”
- Сборка должна быть воспроизводимой и запускаться одинаково локально и на интеграционной машине/сервере.
- Самопроверяемая сборка
- Сборка включает автоматические тесты.
- Падение тестов = падение сборки.
- Частые коммиты небольшими порциями
- Ориентир: минимум ежедневно, на практике — несколько раз в день.
- Частые коммиты стимулируют дробить работу на изменения длительностью в несколько часов.
- Если интеграции откладываются из‑за “накладных расходов” (длинные согласования/процедуры) — это сигнал снижать транзакционные издержки интеграции.
- Проверка основной ветки после каждого коммита
- После каждого изменения основная ветка должна пройти сборку/тесты на интеграционной машине/сервере.
- Сборки «по ночам» — это не CI: они дают слишком поздний сигнал.
- Сломанная сборка чинится немедленно
- Когда основная ветка “красная”, приоритет №1 — вернуть её в “зелёное” состояние.
- Часто самый быстрый путь — откатить последний коммит и разбираться в рабочем окружении.
- Важно: не превращайте это в “культуру наказаний” — стыд/обвинения обычно приводят к тому, что люди интегрируются реже и копят изменения.
- Быстрая обратная связь
- Сборка+тесты должны быть достаточно быстрыми, чтобы их можно было запускать часто.
- Практический ориентир для «commit build» (компиляция + unit‑тесты): ≤ 10 минут (лучше — ≤ 5).
- Если не получается быстро вернуть mainline в «зелёное» состояние — часто лучше откатить последний коммит и разбираться отдельно.
Вспомогательные практики
Эти практики помогают сохранить частые интеграции даже при больших изменениях и/или росте команды.
- Короткоживущие ветки и PR (если вы используете PR‑флоу)
- Ветки создаются для ревью и проверки сборки, но живут минимально возможное время.
- Цель — как можно быстрее вернуть изменения в общую mainline, не накапливая риск интеграции.
- Если обязательное ревью до слияния делает интеграции редкими и “пачками”, рассмотрите альтернативы: парное/mob‑программирование (ревью “в момент написания”), усиление автоматических проверок, а ревью делайте на более медленном цикле уже интегрированного кода небольшими порциями.
- Источник: Vincent Driessen — A successful Git branching model.
- Визуальный менеджмент статуса сборки
- Сделайте состояние mainline видимым: общие экраны/дашборды “зелёный/красный”, уведомления, явный сигнал “сборка в починке”.
- Смысл не в контроле менеджером, а в том, чтобы команда ежедневно реагировала на сигнал и училась на причинах падений.
- Многоэтапная CI‑система (для больших продуктов)
- Разделяйте проверки на уровни по скорости обратной связи: очень быстрый уровень (компиляция + unit + smoke) и более медленные уровни (интеграционные/приёмочные/системные/нагрузочные).
- Думайте о механике “продвижения”: запуск следующих уровней автоматически после успешного прохождения предыдущих (а не вручную “когда решим”).
- Слишком сложная многоэтапность — тоже потери: оставляйте только те уровни, которые реально нужны вашему продукту.
- Feature flags
- Что это: переключатели поведения (feature toggles), которые позволяют держать код новой функциональности в mainline, но управлять её включением через конфигурацию, а не через ветки.
- Позволяют вливать код «частями» и включать функциональность позже.
- Снижают потребность в долгоживущих ветках.
- Типичные сценарии: «выключено по умолчанию» для незавершённой фичи, поэтапное включение (canary/процент/роль), быстрый «рубильник» для отключения проблемной функциональности.
- Практика: делайте маленькие инкременты, которые безопасно мержить в trunk, даже если UI/эндпоинты ещё не готовы — флаг закрывает «незавершённое» от пользователей.
- Важно: флаг — это временный механизм. Нужны правила жизненного цикла: дата удаления, владелец, и регулярная чистка, иначе флаги накапливаются и усложняют код.
- Риски: много условий в коде («if‑ад»), сложнее тестировать комбинации. Минимизируйте число активных флагов и избегайте вложенных/пересекающихся условий.
- Материал: Trunk-Based Development — Feature flags.
- Branch by abstraction
- Что это: способ делать крупные замены (БД/сервис/библиотека/модуль) без долгоживущей ветки — через введение промежуточной абстракции.
- Как выглядит: добавляете интерфейс/фасад, подключаете новую реализацию параллельно старой, затем постепенно переводите вызовы/потоки на новую реализацию и удаляете старую.
- Зачем: позволяет продолжать часто интегрироваться в mainline, не блокируя команду «большим мержем» в конце.
- Материал: Trunk-Based Development — Branch by Abstraction (есть также перевод: trunkbaseddevelopment.ru).
- Stop the line (остановить линию)
- Если mainline «красная», команда останавливает поток: новые интеграции откладываются, пока сборка не станет «зелёной».
- Приоритет №1 — сразу исправить или откатить изменения, которые сломали сборку.
- Практически это работает, когда есть понятные правила: кто берёт инцидент, как быстро принимается решение об откате и что считается «достаточно зелёным» (обычно — commit build).
- Статья: «Stop the line или прокачай свой pipeline, йоу» (Dodo Engineering, Хабр).
- Разделяйте быстрые и долгие проверки
- Commit build должен быть быстрым и достаточным, чтобы mainline оставалась «безопасной для разработки».
- Более долгие проверки (интеграционные, e2e, безопасность, производительность) выносите в последующие стадии конвейера.
- Материал: Martin Fowler — Deployment Pipeline.
Ежедневный цикл разработчика в CI
- Обновиться до актуальной основной ветки.
- Сделать небольшое изменение (включая обновление/добавление тестов).
- Запустить сборку и тесты локально.
- Перед коммитом ещё раз обновиться, разрешить конфликты, снова прогнать сборку/тесты.
- Закоммитить в основную ветку.
- Убедиться, что интеграционная сборка основной ветки прошла; если нет — сразу исправить или откатить.
Коротко
CI = частые маленькие интеграции в одну основную ветку + самопроверяемая автоматическая сборка после каждой интеграции + немедленная починка сломанной сборки.
Вопросы и ответы
Нужен ли жёсткий запрет «не ломать сборку» и публичный поиск виноватых?
Цель CI — быстро обнаруживать дефекты и быстро их устранять. Жёсткие запреты и стыжение обычно приводят к обратному: люди начинают бояться интегрироваться и копят изменения. Лучше сделать обратную связь быстрой, убрать барьеры для «остановиться и исправить», и договориться: если mainline красная — это приоритет №1 для команды.
Совместимо ли обязательное code review до merge с CI?
Может быть, но часто это увеличивает “стоимость” интеграции и провоцирует слияние большими пачками. Если это начинает мешать частой интеграции, используйте альтернативы: парное/mob‑программирование (ревью в процессе), сильные автоматические проверки, а часть ревью выполняйте позже на небольших порциях уже интегрированного кода.
С чего начинается CI в команде?
Не с инструмента, а с договорённости: код в репозитории всегда должен успешно собираться и проходить тесты. Без этого ни CI‑сервер, ни ночные сборки не дадут устойчивого эффекта.
Почему «ночные сборки» — это не CI?
Потому что сигнал приходит слишком поздно. В CI основная ветка проверяется после каждого коммита (или с минимальной задержкой), чтобы ошибки интеграции находились сразу.
Как часто стоит интегрироваться?
Ориентир — минимум ежедневно, на практике часто несколько раз в день небольшими порциями изменений.
Чем «CI‑сервер на feature‑ветках» отличается от CI?
В CI команда регулярно интегрируется в общую mainline и держит её зелёной. Если проверки крутятся в изоляции на feature‑ветках, а интеграция в mainline происходит редко, то ошибки интеграции всё равно копятся и проявляются поздно — это часто называют «CI‑театром».
Что делать, если commit build стал дольше 10 минут?
Обратная связь становится слишком медленной для частых интеграций. Типичные меры: параллелизация тестов, отделение долгих проверок в отдельные стадии конвейера, кеширование зависимостей/артефактов, пересмотр объёма проверок именно в commit build.
Как масштабировать CI, когда продукт большой и тесты медленные?
Обычно помогает сочетание: (1) ускорение сборки (параллелизация, улучшение зависимостей, рефакторинг медленных тестов, более мощное железо), (2) многоэтапный пайплайн с очень быстрым “нижним” уровнем и более медленными уровнями выше, (3) визуальный сигнал статуса сборки, чтобы команда реагировала быстро и не копила интеграции.
Как делать большие изменения без долгоживущих веток?
Чаще всего помогает комбинация feature flags (сливать код, не включая функциональность) и branch by abstraction (вводить новый слой/интерфейс и постепенно переводить вызовы). Это позволяет продолжать часто интегрироваться в mainline.