Обеспечивая согласованность сред независимо от изменений (изменения конфигурации, установка исправлений, модернизация и так далее), необходимо реплицировать их повсюду в производственных, предпроизводственных, а также в любых вновь создаваемых средах.
Вместо входа на серверы вручную и внесения изменений в конфигурацию мы должны внести изменения таким образом, чтобы все они автоматически реплицировались всюду и автоматически же фиксировались в системе контроля версий. Мы можем полагаться на нашу систему управления конфигурацией для обеспечения согласованности сред (например, Puppet, Chef, Ansible, Salt, Bosh и др.). Можно создавать новые виртуальные машины или контейнеры с помощью механизма автоматизированной сборки и развертывать их в производство, уничтожая старые машины или выводя их из ротации [69].
Последняя модель — так называемая постоянная инфраструктура: в ней внести изменения в производственную среду вручную невозможно, единственный способ — внести изменения в систему контроля версий и создать код и среду «с нуля». При таком подходе вариабельность никак не сможет «вползти» в производственную среду.
Во избежание неконтролируемых вариаций конфигурации мы можем отключить удаленный вход на производственные серверы [70]или регулярно уничтожать экземпляры и заменять их новыми, чтобы обеспечить удаление вместе с ними всех изменений, внесенных вручную. Такой подход мотивирует всех членов команд вносить изменения как положено, через систему контроля версий. Применяя такие меры, мы систематически уменьшаем возможность того, что инфраструктура отклонится от рабочего состояния (например, из-за смены конфигураций, повреждаемости отдельных компонентов, чьих-то сознательных усилий и так далее).
Также мы должны поддерживать в актуальном состоянии предпроизводственные среды — в частности, необходимо сделать так, чтобы разработчики максимально обновленный вариант среды. Разработчики часто стремятся работать в старых средах, поскольку не любят изменений: так можно нарушить работу имеющихся функций. Однако мы хотим обновлять среды часто, чтобы можно было обнаруживать проблемы на как можно более ранней стадии жизненного цикла проекта [71].
Измените для разработчиков определение состояния «выполнено», чтобы оно включало выполнение в среде, приближенной к производственной
Теперь, когда наши среды могут быть созданы по требованию и все вносится в систему контроля версий, наша цель — обеспечить, чтобы в повседневной деятельности разработчиков использовались именно эти среды. Необходимо убедиться, что приложение работает в среде, приближенной к производственной, так, как и ожидалось, задолго до окончания проекта или до его первого развертывания в производстве.
Большинство современных методик разработки программного обеспечения предписывают короткие интервалы разработки и итеративность процесса в отличие от подхода big bang (например, модели водопада). В целом чем больше интервал между развертываниями, тем хуже результаты. Например, в методологии Scrum есть понятие спринт — некоторый интервал разработки фиксированной продолжительности (обычно один месяц или менее), в течение которого мы обязаны сделать то, что в широком смысле называется «работающий и потенциально готовый к поставке код».
Наша цель — обеспечить, чтобы разработчики и тестировщики регулярно интегрировали код в среду, близкой к производственной, с интервалами, постепенно сокращающимися по мере выполнения проекта [72]. Мы делаем это путем расширения определения «выполнено» за границы правильного функционирования кода: в конце каждого интервала разработки мы должны иметь интегрированный, протестированный, работающий и потенциально готовый к поставке код, указанные характеристики которого продемонстрированы в среде, близкой к производственной.
Другими словами, мы будем считать задачу разработчиков выполненной, если она будет успешно собрана, развернута и подтвердится, что она работает, как и ожидалось, в среде, близкой к производственной, а не тогда, когда разработчик считает ее сделанной. В идеале она работает в среде, близкой к производственной, с набором данных, близким к производственному, задолго до окончания спринта. Это предотвращает ситуации, когда функцию называют сделанной лишь потому, что разработчик может успешно запустить ее на своем ноутбуке и нигде больше.
Читать дальше