Case Study: Непрерывный деплоймент
November 6, 2011 | Posted by admin under Практики, Статьи |
Автор: Ash Maurya
Blog: http://www.ashmaurya.com/
http://www.startuplessonslearned.com/2010/01/case-study-continuous-deployment-makes.html
В данной статье приводится пример (case study) перехода от традиционного цикла разработки к непрерывному деплойменту. Многие люди все еще считают эту идею сложной, даже те компании, которые работают исключительно в web. В этом примере все даже сложнее: разбирается ситуация непрерывного деплоймента для настольного приложения. Возможно ли обеспечить деплоймент на постоянной основе в этом случае? Читайте далее.
Ash Maurya основатель WiredReach. Это startup, которым он управлял в течение семи лет. Недавно он увлекся темой Lean Startup и начал писать о своем опыте применения принципов lean startup и customer development. Его пост Achieving Flow in a Lean Startup я назвал одним из моих любимых постов за 2009 год.
Ниже описан его личный опыт, возникшие проблемы и решения, которые он для них находил. Если вы хотите опубликовать статью о своем опыте, можно начать с добавления ее в секцию Lean Startup Wiki case study section. –Eric
Eric Ries, автор блога Startup Lessons Learned
Из всех методов Lean Startup-а наиболее спорным является непрерывный деплоймент. Непрерывный деплоймент это процесс, по которому программное обеспечение выпускается несколько раз в день: минуты в противовес дням, неделям или месяцам. Непрерывный поток производства – это Lean метод. Производительность повышается за счет перестройки производственных процессов таким образом, что продукт создается от начала и до конца, один за раз (цельный поток производства), в отличие от более распространенного подхода с партиями и очередями.
Непрерывный деплоймент – это непрерывный поток в применении к производству программного обеспечения. В обоих случаях задача – ликвидировать потери. Самые крупные потери в производстве создаются из-за необходимости перевозить продукцию из одного места в другое. Самые крупные потери в разработке ПО создаются из-за ожиданий, пока ПО переходит из одного состояния в другое: ожидание кода, результатов тестирования, деплоймента. Уменьшение или исключение этих ожиданий ведет к ускорению итераций, что является ключом к успеху.
Мой переход к непрерывному деплойменту
До перехода на непрерывный деплоймент у меня был недельный график релизов. Я считал это достаточно подвижным, дисциплинированным и агрессивным процессом. В понедельник я идентифицировал код, который нужно будет обязательно поставить. Четверг был официальным днем отсечки кода для релиза. Пятница была днем релиза. Процесс релиза занимал по крайней мере полдня, а иногда и весь день. 20 процентов времени в неделю уходило на процесс релиза, что очень расточительно для маленькой команды. Это не считая усилий по координации, необходимых для приоритезации постоянно меняющегося состава релиза. Несмотря на эти проблемы, я боролся с искушением перейти на более длинный двухнедельный или ежемесячный цикл релизов, потому что я хотел быстро реагировать на запросы клиентов (что они очень ценят). Управление еженедельными релизами стало намного сложнее, когда я начал customer development. Я проводил больше времени вне своего офиса, что означало – меньше времени для кодирования, тестирования и деплоймента. Некоторые вещи начали ускользать от меня. Тогда я разработал набор мер (описанных здесь), что в итоге привело меня к непрерывному деплойменту.
Мой переход к непрерывному деплойменту занял примерно 2 недели. Для начала я прочитал статью Eric Ries 5 step primer . Я обнаружил, что у меня уже есть многое из того, что необходимо для реализации непрерывного деплоймента. Непрерывная интеграция, скрипты для деплоймента, мониторинг и система оповещений – это хорошие практики (best practices) для процесса релизов любого типа (поэтапного или непрерывного).
Основная сложность непрерывного деплоймента – освоиться с постоянными релизами.
С непрерывным деплойментом релизы перестают быть событиями, а добавление кода в базу становится триггером для создания нового релиза. С одной стороны это позволяет моментально реагировать на запросы заказчиков. С другой стороны это очень пугает. В поэтапных релизах время обеспечивает (в чем-то иллюзорную) безопасность. Более комфортно разделять ответственность за тестирование с кем-то еще (с командой тестировщиков). Никто не хочет отвечать в одиночку за то, что рабочая система “упала”. Мне не нужно было рассматривать эти аргументы. У меня не было времени и команды тестировщиков.
Я пошел простым путем – делал небольшие изменения и маниакально проверял процесс релиза. Я начал полагаться на функциональные тесты (а не на unit тесты), что позволяло мне тестировать изменения так, как это сделал бы сам пользователь. Я определил набор событий, которые могли бы сигнализировать когда что-то идет совсем не так (например, в системе нет пользователей) и создал систему оповещения о них в реальном времени (используя nagios/ganglia). Наша уверенность росла, и мы начали вносить (commit) все бОльшие изменения, состоящие из нескольких частей. Каждый раз мы дополняли набор наших тестов и скриптов для мониторинга системы. После нескольких итераций наш уровень страха стал ниже, чем был на поэтапных (staged) релизах. Поскольку мы вносили меньше кода за релиз, мы могли точнее связывать появление проблем с произошедшей выкладкой.
Мы не удивляемся непредвиденным ошибкам, которые могли произойти из-за слияния больших кусков кода (поскольку нет ветвления – branching). Мы полагаемся на автоматизацию тестирования и мониторинга, это более надежно и последовательно, чем то, что мы делали до этого.
У нас бывают ошибки, и иногда мы вносим плохой код. Но все это не приводит к падению системы. Вместо того, чтобы считать это недостатком процесса, мы рассматриваем это как возможность построить нашу Кластерную Иммунную Систему. Мы стараемся следовать подходу Пяти почему (Five Whys) и не повторять ошибки.Вот что это значит для нас: больше тестов, больше мониторинга, больше оповещений, больше кода и больше процесса.
Мне было необходимо сбалансировать активности “внутри здания” и “вне здания”. Применение непрерывного деплоймента позволило мне построить свой день так, чтобы успевать и то и другое. Ранние релизы это не единственное преимущество непрерывного деплоймента. Небольшие релизы ведут к более быстрым циклам построения/измерения/обучения. Я использовал эти циклы для оптимизации потока активации пользователя (User Activation flow). Также это позволило мне радовать заказчиков почти мгновенным исправлением ошибок, и даже исключать фичи, которыми никто не пользуется.
Конечно легче настроить непрерывный деплоймент для web-приложения. Однако, используя некоторую дисциплину, можно построить процесс непрерывного деплоймента и для настольного приложения. Далее описано, как я реализовал непрерывный деплоймент для своего настольного приложения (CloudFire).
Мой процесс непрерывного деплоймента
Вытягивание против выталкивания фичи (features)
Обнаруженная проблема стоит того, чтобы ее решили. Необходимо построить минимальный жизнеспособный продукт (minimum viable product – MVP). Не нужно добавлять новые фичи, пока вы не определили MVP. Ненужные фичи это потери. Они не только создают больше работы, они еще и бесполезно усложняют продукт.
В идеале, каждая новая фича должна потребоваться более чем одному заказчику, прежде чем попасть в релиз.
Стройте систему в ответ на сигналы от заказчика, а если их нет, то занимайтесь улучшениями.
Как технолог, я очень люблю измерять прогресс базируясь на том, насколько разрослась система. Но я направляю свою энергию не на появление новых фич, а в основном (80%) на измерения и оптимизацию существующих фич. Я не выступаю против того, чтобы совсем не добавлять новые фичи. Обычно пользователи просят больше, и ваш MVP по определению минимальный, и требует больше внимания. Просто не выталкивайте фичи.
Небольшие куски кода (small batches)
Я уже описывал свои двухчасовые блоки работы для максимизации своего рабочего процесса.Перед тем, как начать блок работы, я четко определяю, что нужно сделать (цель) и как (дизайн).
Важно отметить, что целью не обязательно является фича, видимая пользователю, и не обязательно фича целиком. Добавление небольших кусков кода в систему позволяет постепенно решать проблемы интеграции. В течение блока работы я кодирую, делаю unit тестирование, создаю или меняю функциональные тесты. В конце я вношу код (check-in), что автоматически запускает создание билда на сервере. Затем этот билд проходит через unit-тесты и функциональные тесты. В конце создаются следующие артефакты: инсталляции для mac и windows (для новых пользователей) и Eclipse P2 репозиторий (OSGI) для автоматических обновлений (для текущих пользователей). Процесс релиза занимает 15 минут и идет в фоновом режиме.
Предпочитайте функциональные тесты unit тестам, когда это возможно
Я не верю в слепое написание unit тестов для достижения 100% покрытия кода, что обещают некоторые инструменты. Чтобы сделать это, мне нужно было бы смоделировать слишком много критически важных компонентов. Я считаю чрезмерное unit-тестирование напрасной тратой. Когда это возможно, я полагаюсь на функциональные тесты, чтобы проконтролировать действия пользователя. Я использую Selenium, он позволяет контролировать работу приложения на нескольких браузерах и под несколькими операционными системами.Нужно с осторожностью относится к следующему: функциональные тесты работают дольше unit тестов, и это постепенно увеличивает время релиза. Это решается распараллеливанием тестирования на нескольких машинах. Я еще не дошел до этой точки, но, думаю, подойдет Selenium Grid. То же самое делает Go Test It.
Всегда тестируйте путь активации пользователя (User Activation flow)
После прогона интеграционных тестов и после того, как собран программный пакет, я всегда проверяю путь активации пользователя. Путь активации пользователя – это наиболее критический путь для достижения удовлетворенности пользователей или для удовлетворения требований рынка. У меня путь активации пользователя автоматически тестируется на машинах под mac и windows.
Используйте авто-МАГИЧЕСКИЕ обновления
Главная проблема с настольными приложениями (в отличие от web-приложений) это распространение программных обновлений. Исследования показывают, что пользователям мешают диалоги программных обновлений.Чтобы преодолеть это, я использую другую стратегию: обновление происходит незаметно для пользователя, ему не надо прерывать свою работу. Подобная стратегия обновлений используется для Google Chrome. Правда, некоторые пользователи могут рассматривать такой подход как “навязывание”. Но пока что никто из пользователей не жаловался и многим пользователям нравятся авто-обновления. Помогает то, что приложение CloudFire имеет UI, работающий через браузер (это p2web app приложение).
Вот как работает процесс обновлений сейчас:
1. В конце каждого билда мы выкатываем репозиторий Eclipse P2 (OSGI), это набор версионированных plug-in-ов, которые составляют приложение. Поскольку приложение состоит из большого числа маленьких plug-in-ов, и мы добавляем небольшие куски кода, то размер каждого обновления небольшой и обновление быстро загружается.
2. Каждый раз, когда пользователь загружает приложение, оно проверяет, есть ли новое обновление, и если есть, загружает и устанавливает его. В зависимости от типа обновления, оно может начать действовать немедленно или требовать перезагрузки приложения. Если требуется перезагрузка приложения, мы ждем, пока пользователь в следующий раз запустит приложение, или же запускаем его, пока система бездействует.
3. Когда приложение работает, оно периодически проверяет наличие новых обновлений. Если есть обновление, оно загружается и устанавливается в фоновом режиме (как описано выше), не прерывая работу пользователя.
Оповещения и мониторинг
Я использую nagios и ganglia для реализации мониторинга и оповещений о любом ненормальном поведении системы.Примеры того, что попадает под мониторинг: число пользовательских активаций, число активных пользователей, число посещений страниц. Любое выходящее за норму падение этих показателей немедленно оповещает нас (через twitter/SMS) о потенциальной проблеме.
Диагностика уровня приложения
Несмотря на хорошее тестирование, все же бывают дефекты. Увеличение объема тестирования не всегда решает проблему, поскольку некоторые дефекты проявляются непостоянно и зависят от пользовательского окружения. Невозможно протестировать все комбинации аппаратного обеспечения, ОС, браузеров и других приложений (например, Norton anti-virus, Zone Alarm, и т.д.).
Пользователи не всегда сообщают о возникших ошибках. Поэтому нам пришлось встроить диагностику в приложение.Она сообщает пользователю и нам о неожиданных ошибках, и позволяет нам удаленно получить информацию о конфигурации и логи. В случае необходимости мы можем сделать откат обновления.
Допускайте неожиданные ошибки только раз
Неожиданные ошибки дают возможность изучить систему и проверить на прочность. Игнорирование их и создание быстрых и “грязных” патчей ведет к повторению ошибок, т.е. является еще одной формой потерь. Я пытаюсь следовать формализованному процессу Пяти почему (используя внутренний wiki) для каждой ошибки. Это заставляет нас остановиться, подумать и исправить правильную проблему (или проблемы).
Мой процесс непрерывного деплоймента можно представить так:
Так почему же непрерывный деплоймент является спорным?
В своем блоге Eric уже рассмотрел многие из возражений.Одно из них, это то, что для реализации непрерывного деплоймента нужно иметь большую команду. Я бы сказал, что чем более ранняя стадия цикла разработки, и чем меньше команда, тем легче реализовать процесс непрерывного деплоймента. Если вы являетесь start-up командой с MVP, то лучшего момента для внедрения непрерывного деплоймента не найти. У вас пока нет сотен заказчиков, и дюжин фич. Намного проще заложить фундамент сейчас, когда время на вашей стороне.
Pingback: Рубрика «Полезное чтиво». Выпуск 10 « XP Injection()