Книга Дж. Хамбла и Д. Фарли «Непрерывное развертывание ПО»

neprerivnoe_razvertivanie_po

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

В этом посте речь пойдет о книге, которую я прочитал последней, и которая заставила по-новому взглянуть на разработку проектов, которыми я занимаюсь. Это книга Джеза Хамбла и Дэвида Фарли «Непрерывное развертывание ПО. Автоматизация процессов сборки, тестирования и внедрения новых версий программ». Сама книга уже довольно старая, ее русский перевод вышел в 2011 году и, похоже, что оригинал был издан в том же году, но почему-то до этого я про нее ничего не слышал и наткнулся на нее случайно.

Основная идея книги заключается в том, что при разработке программного обеспечения (не важно, пишете вы десктопные приложения или веб-сервисы), сборке и развертыванию программ нужно уделять не меньшее внимание, чем написанию основного кода. Главная мысль в книге, которую пропагандируют авторы — это создание конвейера сборки и развертывания приложений. Что представляет из себя этот конвейер? После каждого изменения, отправленного, в репозиторий, сервер непрерывной интеграции (Continuous Integration, CI) должен выполнять последовательность определенных действий, тестируя код на каждом шаге, и немедленно сообщать об обнаруженных проблемах программистам. Последовательность действий выглядит таким образом (картинка взята из книги).

conveyer

Когда программист отправляет код в репозиторий, сервер CI сначала компилирует программу, и дальнейшие тесты выполняются уже на этой скомпилированной версии (важно, чтобы тестировались именно те бинарные сборки, которые потом попасть на продакшн или пользователям). Первыми запускаются модульные тесты (unit tests), которые должны выполняться быстро, не дольше 5-10 минут, окончания которых должен дождаться программист, отправивший изменения на сервер. Если тесты провалились, то вся команда должна остановить работу или, по крайней мере, не отправлять новые изменения на сервер, пока прохождение модульных тестов не будет исправлено. Если программист, сломавший тесты, за короткий промежуток времени не исправит ошибку, приводящую к провалу теста, то администратор сборки должен иметь право отменить исправление, внесенное этим программистом.

При использовании непрерывной интеграции один из смертных грехов — регистрация изменений в нерабочей сборке.

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

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

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

Если строго придерживаться принципов непрерывной интеграции, приложение всегда должно находиться в работоспособном состоянии.

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

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

Главная цель создания конвейера непрерывного развертывания — это избежать проблем при выпуске новой версии ПО. В любой момент проект должен быть готов к тому, чтобы стать финальной версией. Именно поэтому такое внимание уделяется проваленным тестам. Это нормально, если тесты иногда будут показывать наличие ошибок, главное, чтобы они быстро исправлялись. Авторы часто ссылаются на методики, предложенные гибкими методологиями разработки и экстремальным программированием, авторы во многом им симпатизируют, поскольку в этих методологиях также пропагандируется идея быстрых релизов, когда новая версия поставляется заказчику не реже, чем раз в две недели.

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

Но для того, чтобы достичь четкой работы конвейера нужна, в первую очередь, дисциплина разработчиков: как я уже говорил, они должны останавливать работу при появлении тревожного сигнала с сервера непрерывной интеграции, и стараться командной работой как можно скорее все исправить. Во-вторых, это касается управлением версий. Авторы честно признаются, что это тема спорная, им нравятся распределенные системы контроля версий (в книге достаточно интересно описана история развития различных систем контроля версий), но они не одобряют методологии, которую они продвигают, когда плодится много веток, которые лишь через какое-то время сливаются с главной веткой (они называют ее стволом или магистралью). Авторы считают, что для правильной работы идеологии непрерывного развертывания, программисты сразу же должны вносить изменения в основную ветвь исходников, чтобы сразу же получать обратную связь — сломали они что-нибудь своим изменением или нет. В крайнем случае программисты должны вносить изменения в основную ветвь хотя бы раз в день, а ветви хороши для экспериментов. Авторы признают, что такая организация работы не всегда возможна, если речь идет об удаленных командах программистов (в качестве примера они приводят процесс написания ядра Linux).

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

Единственное, что мы не рекомендуем хранить в системе управления версиями, — двоичные результаты компиляции приложения.

Такой процесс разработки просто вынуждает отказываться от ручной работы, все должно быть максимально автоматизировано. Особенно это касается поставки новых версий ПО на сервер. Часто процесс развертывания новой версии — это болезненный процесс, который длится несколько дней, а то и недель, когда вылезают на свет не известные до сих пор баги, которые впервые обнаруживаются уже в продакшне. Такого быть не должно, в идеале развертывание должно осуществляться нажатием одной кнопки, а откат в случае возникновения аварийных ситуаций должен осуществляться нажатием другой кнопки. Но в целом процесс развертывания любой версии должен быть полностью автоматизирован и протестирован множество раз на тестовых серверах, а лучше не только на тестовых, чему способствуют частые релизы. Для этого на разных системах процесс развертывания ПО и необходимых ему библиотек должен выполняться одинаково, разница может быть только в настройках вроде прописанных IP серверов и портов. Все изменения в настройках также должны фиксироваться в системе контроля версий.

Автоматизированное развертывание следует использовать всегда; оно должно быть единственной технологией выпуска ПО.

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

Любопытно, что отдельные идеи, описанные в этой книге, уже повсеместно применяются (идеи во многом пересекаются с гибкими методологиями разработки), но в «Непрерывном развертывании ПО» авторы их органично объединили в общую идеологию.

Как я уже сказал в начале, на меня эта книга произвела сильное впечатление. Когда я ее читал, постоянно прикидывал, как можно применить описанные в ней идеи к своим проектам и, в частности, к OutWiker, выкладывание новой версии которого сейчас занимает более двух часов, включая тестирование под Windows и Ubuntu, создание сборок и выкладывание их на сайт. У меня есть чек-лист, который описывает список действий, которые нужно выполнить при выкладывании очередной версии, я его для себя нарисовал в виде алгоритма и увидел, что многие его части можно автоматизировать. И некоторые запланированные пункты уже выполнил. Да и вообще эта книга заставляет задуматься о том, как правильно организовать тестирование и развертывание приложений.

В общем, книге ставлю твердую пятерку, хотя в ней есть моменты, с которыми можно поспорить. В общем, must read.

PS. Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.

Пожалуйста, оцените запись

УжасноПлохоТак себеХорошоОтлично (Количество голосов: 2, средняя оценка: 5,00)
Загрузка...

Leave a comment

Subscribe without commenting