X. Паритет окружений разработки и продуктива (Dev/prod parity)
Держите окружения разработки, промежуточного развёртывания (staging) и рабочего развёртывания (production) максимально похожими
Исторически существуют значительные различия между разработкой (разработчик делает живые изменения на локальном развёртывании приложения) и работой приложения (развёртывание приложения с доступом к нему конечных пользователей). Эти различия проявляются в трёх областях:
- Различие во времени: разработчик может работать с кодом, который попадёт в рабочую версию приложения только через дни, недели или даже месяцы.
- Различие персонала: разработчики пишут код, OPS инженеры разворачивают его.
- Различие инструментов: разработчики могут использовать стек технологий, такой как Nginx, SQLite, и OS X, в то время как при рабочем развёртывании используются Apache, MySQL и Linux.
Приложение двенадцати факторов спроектировано для непрерывного развёртывания благодаря минимизации различий между разработкой и работой приложения. Рассмотрим три различия, описанных выше:
- Сделать различие во времени небольшим: разработчик может написать код, и он будет развёрнут через несколько часов или даже минут.
- Сделать небольшими различия персонала: разработчик который написал код, активно участвует в его развёртывании и наблюдает за его поведением во время работы приложения.
- Сделать различия инструментов небольшими: держать окружение разработки и работы приложения максимально похожими.
Резюмируя сказанное выше в таблицу:
Традиционное приложение | Приложение двенадцати факторов | |
---|---|---|
Время между развёртываниями | Недели | Часы |
Автор кода/тот кто разворачивает | Разные люди | Те же люди |
Окружение разработки/работы приложения | Различные | Максимально похожие |
Сторонние службы, такие как базы данных, системы очередей сообщений и кэш, являются одной из областей, где паритет при разработке и работе приложения имеет важное значение. Многие языки предоставляют библиотеки, которые упрощают доступ к сторонним службам, включая адаптеры для доступа к различных типам сервисов. Некоторые примеры, в таблице ниже.
Тип | Язык | Библиотека | Адаптеры |
---|---|---|---|
База данных | Ruby/Rails | ActiveRecord | MySQL, PostgreSQL, SQLite |
Очередь сообщений | Python/Django | Celery | RabbitMQ, Beanstalkd, Redis |
Кэш | Ruby/Rails | ActiveSupport::Cache | Память, файловая система, Memcached |
Иногда разработчики находят удобным использовать лёгкие сторонние службы в их локальном окружении, в то время как более серьёзные и надёжные сторонние сервисы будут использованы в рабочем окружении. Например используют SQLite локально и PostgreSQL в рабочем окружении; или память процесса для кэширования при разработке и Memcached в рабочем окружении.
Разработчик приложения двенадцати факторов сопротивляется искушению использовать различные сторонние сервисы при разработке и в рабочем окружении, даже когда адаптеры теоретически абстрагированы от различий в сторонних сервисах. Различия в используемых сторонних сервисах означают, что может возникнуть крошечная несовместимость, которая станет причиной того, что код, который работал и прошёл тесты при разработке и промежуточном развёртывании не работает в рабочем окружении. Такой тип ошибок создаёт помехи, которые нивелируют преимущества непрерывного развёртывания. Стоимость этих помех и последующего восстановления непрерывного развёртывания является чрезвычайно высокой, если рассматривать в совокупности за всё время существования приложения.
Установка локальных сервисов стала менее непреодолимой задачей, чем она когда-то была. Современные сторонние сервисы, такие как Memcached, PostgreSQL и RabbitMQ не трудно установить и запустить благодаря современным менеджерам пакетов, таким как Homebrew и apt-get. Кроме того, декларативные инструменты подготовки окружения, такие как Chef и Puppet в сочетании с легковесным виртуальным окружением, таким как Vagrant позволяют разработчикам запустить локальное окружение которое максимально приближено к рабочему окружению. Стоимость установки и использования этих систем ниже по сравнению с выгодой, получаемой от паритета разработки/работы приложения и непрерывного развёртывания.
Адаптеры для различных сторонних сервисов по-прежнему полезны, потому что они позволяют портировать приложение для использования новых сторонних сервисов относительно безболезненно. Но все развёртывания приложения (окружение разработчика, промежуточное и рабочее развёртывание) должны использовать тот же тип и ту же версию каждого из сторонних сервисов.