суббота, 13 мая 2017 г.

Continuous Integration is Dead

Несколько дней назад статья Егора Бугаенко «Почему непрерывная интеграция не работает» была опубликована на DevOps.com. Почти в тот же день были получены несколько негативных критических замечаний в Twitter. Вот ответ Егора на заданный вопрос: "Почему, непрерывная интеграция мертва, ведь это такая блестящая и популярная идея"?


Опыт Егора включает пять лет использования Apache Continuum, Hudson, CruiseControl и Jenkins в более чем 50 проектах с открытым исходным кодом и коммерческими проектами. Кроме этого, еще хостинг непрерывной службы интеграции fazend.com, переименованный в rultor.com в 2013 году. А также, активный опыт Travis и AppVeyor.

Как должна работать непрерывная интеграция

Идея проста и очевидна. Каждый раз, когда вы делаете новый фикс от главной ветви (или / trunk в Subversion), сервер непрерывной интеграции (или служба) пытается построить весь продукт. «Построение» означает компиляцию, модульный тест, интеграционный тест, анализ качества и т.д.

Результатом является либо «успех», либо «сбой». Если это удастся, мы говорим, что «сборка чиста». Если это провал, мы говорим, что «сборка нарушена». Сборка обычно ломается, потому что кто-то ее нарушает, внося новый код, который превращает ранее сделанные модульные тесты в неудачные.

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

Давайте же посмотрим на организационную сторону.

Непрерывная интеграция - это не только сервер, но и процесс управления

«Надежные релизы программного обеспечения с помощью автоматизации построения, тестирования и развертывания» на практике дополняются пожарными методами, если сборка не удалась. Команда разработчиков останавливает всю работу и немедленно устраняет проблему. 
 
Как мы видим, непрерывная интеграция предполагает настройку всей команды разработчиков на паузу и исправление неработающей сборки. Позвольте мне повторить. После того, как сборка будет нарушена, все должны сосредоточиться на ее фиксации и совершении коммита, который возвращает сборку в стабильное состояние.
Теперь вопрос: кому это нужно в активно работающей команде?

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

Кому нравится такая непрерывная интеграция и кому она нужна? Никому. Что же происходит в реальности?

Я видел это несколько раз. Сценарий всегда один и тот же. Мы просто начинаем игнорировать этот статус непрерывной интеграции. Либо сборка чиста, либо она сломана, и мы продолжаем делать то, что мы делали раньше.

Мы не останавливаемся и не исправляем сборку, как рекомендует Джез Хамбл. Вместо этого мы игнорируем информацию, поступающую от сервера непрерывной интеграции.

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

Что относительно дисциплины?

Да, есть и другая сторона монеты. Мы можем попытаться обеспечить соблюдение дисциплины в команде. Мы можем сделать это через строгое правило - наша сборка всегда должна быть чистой! А тот, кто его нарушает, получит наказание.

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

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

Когда же придет время все-таки вливать их код в проект, то количество изменений кода будет  настолько велико, что слияние станет очень трудным, а иногда и невозможным. В результате вы получаете много выбрасываемого кода из-за простого фактора страха.
Хорошо, какое решение?

Я писал об этом раньше; Оно называется «основная ветка - только для чтения».

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

Другими словами: поднимите красный флаг, прежде чем код попадет в master ветку.

Это решает все проблемы.

Во-первых, сборка всегда чиста. Мы просто не можем ее нарушить.

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

Кстати, попробуйте использовать rultor.com для внедрения изложенной концепции в вашем проекте.



Комментарии и отзывы:

Удивлен никто не упомянул Gerrit - ПО для совместной инспекции кода (или любой другой подобный инструмент). 


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

Если вы делаете что-то плохо, оно и не будет работать. Это касается не только CI, но и всего остального. Делайте же то что нужно должным образом, и инструмент не умрет... название статьи вводит в заблуждение!

CI нельзя «сделать правильно» без предварительных сборок и запретить доступ к главной ветке. Технически это не может быть сделано правильно. Как бы мы ни хотели. Вот о чем статья.
 

Если возникают конфликты, автору ветки приходится синхронизироваться с мастером, но слияние его в свою ветку. Только «чистая» личная ветка может войти в мастера, только без каких-либо конфликтов.

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


В этой статье есть несколько неправильных вещей. Все аспекты, которые упоминаются, не имеют ничего общего с непрерывной интеграцией, они связаны с людьми. Первым и наиболее важным элементом, который лежит в основе любой среды непрерывной интеграции, является приверженность построению тестов. Когда TDD является Обязательным, то каждый разработчик в команде должен знать и использовать его преимущества. А, если некоторые разработчики не хотят или не знают, как писать тесты, то им нужно или уйти, или учиться. Если же вы говорите, что ваши разработчики не пишут модульные тесты, и вы ничего не можете с этим поделать, то у вас на самом деле проблема больше, чем техническая. Другой момент, с которым я полностью не согласен, - это стратегия ветвления. В статье говорится только про мастер-ветку. Но где ветка разработки (develop) или ветви (feature) фич? Почему разработчики должны бояться совершать что-то, когда на самом деле цель ветвления - это как раз убрать этот страх?

Если недостатки CI появляются из-за недостатков людей, то это CI имеет недостатки.

«Обязательство строить тесты» походит на обязательство в браке? Тогда нам понадобятся мотивирующие плакаты и детекторы, чтобы узнать, кто все-таки обманывает нас :) а заодно самые строгие наказания...

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

Позволять разработчикам самим делать правильный выбор - это еще одно определение «беспорядка» и «отсутствия управления».

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

CI - это не только мастер ветка: вы можете настроить его для создания ветвей разработки, и это, вероятно, более полезно, так как проблемы будут отловлены, прежде чем достигнут мастер ветки. Кроме того, CI также должен запускать модульные тесты, анализ статического / динамического кода, плагины DRY и все, что помогает вам поддерживать проект как можно более чистым и стабильным

Все это не будет иметь смысла, если ваша основная ветвь не доступна только для чтения

Если у команды нет надлежащего процесса разработки, это не означает, что CI не работает. Мастерская ветвь только для чтения является хорошей практикой, и многие команды применяют ее, но какова связь между этим рабочим процессом и непрерывной интеграцией вообще? Основная идея CI понятна, но это не то, что вы упомянули выше. Для меня CI означает «сохранение приложения стабильным с течением времени», а не «проверка, является ли текущая версия приложения стабильной или нет».

«ваше решение» описано в книге «Непрерывная интеграция: повышение качества программного обеспечения и снижении рисков», выпущенной почти 10 лет назад в эпилоге «Будущее CI»

Название статьи походит на шутку. Может лучше сменить его: «Почему CI - это не просто построение мастер-ветки»?

Я работал в средах CI, где разработчики:
1) Кодят, тестируют и заливают в сборку
2) Работают через скрипт сборки и тестирования
3) Нет сценария, они просто заливают код

Мой опыт показывает, что 3 не работает, если у вас более 5 активных разработчиков. Сборка / тесты сломаются, и никто не позаботится об этом, как говорится в статье.

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

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

Это именно то, о чем говорится в этой статье - предотвращение перехода в нестабильное состояние. Чтобы этого не произошло, мы должны запретить определенные действия. Если вы хотите, чтобы люди не пили, вы прекратите продавать им выпивку. Вы не проверяете, пьют ли они и не сообщают им «пожалуйста, прекратите пить». Ты просто прекращаешь продавать алкоголь и все. Тоже самое. Чтобы предотвратить нестабильную сборку, мы запрещаем им прикасаться к сборке.



Комментариев нет:

Отправить комментарий