X. Паритет між розробкою та експлуатацією

Прагніть максимальної ідентичності development, staging та production середовищ

Історично склалося, що є суттєві відмінності між development середовищем (розробник вносить живі зміни в локально розгорнутий застосунок) і production середовищем (до якого мають доступ кінцеві користувачі). Ці відмінності проявляються в трьох областях:

  • Різниця в часі: Розробник може працювати над кодом, який потрапить у production через дні, тижні або навіть місяці;
  • Різниця в персоналі: Розробники пишуть код, Ops-інженери розгортають його;
  • Різниця в інструментах: Розробники можуть використовувати стек технологій такий, як Nginx, SQLite та OS X, в той час, як на production використовується Apache, MySQL та Linux.

12-факторний застосунок проєктується для безперервного розгортання, завдяки мінімізації різниці між production і development середовищами. Розглянемо три відмінності, описані вище:

  • Зменшення різниці в часі: розробник може написати код і він буде розгорнутий через декілька годин або навіть хвилин;
  • Зменшення різниці в персоналі: розробники, які писали код, беруть активну участь в його розгортанні та спостерігають за його поведінкою на production;
  • Зменшення різниці в інструментах: зберігайте середовище розробки та експлуатації якомога подібнішими.

Узагальнимо сказане вище в таблицю:

Традиційний застосунок 12-факторний застосунок
Час між розгортаннями Тижні Години
Автор коду/Той хто розгортає Різні люди Ті ж люди
Dev/Prod розгортання Різні Якомога подібніші

Сторонні служби, такі як бази даних, системи черг повідомлень або кеш, є однією з областей, де dev/prod паритет має важливе значення. Багато мов програмування мають бібліотеки, які спрощують доступ до сторонніх служб, в тому числі адаптери для різних видів сервісів. Деякі приклади наведені в таблиці нижче.

Тип Мова Бібліотека Адаптери
База даних Ruby/Rails ActiveRecord MySQL, PostgreSQL, SQLite
Черга повідомлень Python/Django Celery RabbitMQ, Beanstalkd, Redis
Кеш Ruby/Rails ActiveSupport::Cache Памʼять, файлова система, Memcached

Іноді розробники бачать переваги у використанні "легких" сторонніх служб в їхньому локальному середовищі, в той час, як більш серйозні та надійні сторонні служби будуть використовуватися у production. Наприклад, локально використовують SQLite, а на production PostgreSQL; або локально памʼять процесу для кешування, а на production Memcached.

Розробник 12-факторного застосунку уникає використання різних сторонніх служб в development і production середовищах, навіть якщо адаптери теоретично абстраговані від будь-яких відмінностей у сторонніх службах. Відмінності між сторонніми службами означають, що може виникнути крихітна несумісність, в результаті чого код, який працював і пройшов тестування в development та staging середовищах, після розгортання не працює в production середовищі. Такий тип помилок створює перешкоди, які нівелюють переваги безперервного розгортання. Ціна цих перешкод і подальшого відновлення безперервного розгортання надзвичайно висока, якщо розглядати в сукупності за весь час експлуатації застосунку.

Встановлення локально "легких" сторонніх сервісів вже не є таким привабливим, як було раніше. Сучасні надійні сторонні сервіси, такі як Memcached, PostgreSQL і RabbitMQ, досить легко встановити та запустити завдяки сучасним менеджерам пакунків, таким як Homebrew і apt-get. Крім того, декларативні інструменти підготовки середовища, такі як Chef і Puppet, у поєднанні з "легким" віртуальним середовищем, таким як Docker та Vagrant, дозволяють розробникам запускати локальні середовища, які наближені до production. Ціна встановлення і використання цих систем є низькою у порівнянні з користю dev/prod паритету і безперервного розгортання.

Адаптери для різних сторонніх сервісів все ж корисні, тому що вони роблять перенесення застосунку для використання з іншими сторонніми сервісами відносно безболісним. Але всі розгортання застосунку (development, staging та production середовища) мають використовувати один і той самий тип і версію кожного зі сторонніх сервісів.