Одна кодовая база, отслеживаемая в системе контроля версий
- Проще делать крупномасштабный рефакторинг кода. Все в одном месте, сразу видно, что может сломаться.
- Более гибкое владение кодом. Любой может сделать Pull Request в твой код. Все видят код друг друга
- Проще обеспечить совместимость систем, которые всегда релизятся вместе
- Легче управлять общими зависимостями. Не нужен пакетный менеджер
Явно объявляйте и изолируйте зависимости. Приложение двенадцати факторов никогда не зависит от неявно существующих, доступных всей системе пакетов.
- Добавьте в ваш репозиторий скрипт для скачивания нужной версии используемой системы сборки
- Храните зависимости в приватном репозитории артефактов
- Запускайте сборку в docker контейнере
- Инструкция по сборке должна находиться в readme файле проекта
Сохраняйте конфигурацию приложения в переменных окружения
Внешнее хранилище настроек позволяет:
- Менять настройки без перезапуска, преключать фитча флаги
- Совместно использовать настройки несколькими сервисами
- Упростить администрирование настроек множества приложений
- Логировать доступ к настройкам
- Централизовано хранить и управлять секретами
Считайте сторонние службы подключаемыми ресурсами. Не делайте различий между локальными и сторонними сервисами.
- Любой вызов внешнего сервиса может закончиться неудачей
- Внешний сервис может стать недоступным на неопределенное время
- При запросе всегда устанавливайте таймаут на ответ
Разделяйте стадии сборки и выполнения. Одна сборка разворачивается на любые контура с возможностью отката к старому релизу
Приложения не должны сохранять свое внутреннее состояние. Это позволит добиться:
- Возможность горизонтального маштабирования
- Перезапуск не приводит к потери информации
Приложение двенадцати факторов является полностью самодостаточным, HTTP сервер встроен в приложение.
- Требуют установки, что замедляет онбординг разработчика
- Из коробки не работают. Необходимы уникальные знания для поддержки и настройки конкретного сервера
- Поддерживают ограниченный набор технологий. Вы не запустите C# на WebLogic или Tomcat
- Конфигурация расползается между приложением и контейнером
Приложение должно уметь горизонтально маштабироваться при необходимости
- Ресурсы можно добавлять бесконечно
- Нет остановки сервера при добавлении ресурсов
- Надежнее за счет одновременного запуска приложения на разных машинах
- Случайный запуск двух экземпляров приложения не вызывает проблем
Максимизируйте надёжность с помощью быстрого запуска и корректного завершения работы. Приложения могут быть запущены и остановлены в любой момент.
- При штатном завершении работы закройте все соединения и освободите ресурсы
- Убедитесь, что приложение корректно обрабатывает сигнал SIGTERM
- Приложение должно быть готово к экстренному завершению в любой момент
Решение
- Outbox Pattern
- Change Data Capture
Решение:
- Идемпотентность API
Минимизируйте разрыв между разработкой и работой приложения
- **Различие во времени:** разработчик может работать с кодом, который попадет в рабочую версию приложения только через дни, недели или даже месяцы.
- **Различие персонала:** разработчики пишут код, OPS инженеры разворачивают его.
- **Различие инструментов:** разработчики могут использовать стек технологий, такой как Nginx, SQLite, и OS X, в то время как при рабочем развертывании используются Apache, MySQL и Linux.
- **Stream-aligned team** — команда нацелена на создание и доставку ценности пользователем как можно быстрее. Должна стремиться к максимальной автономности. Цель других типов команд в том, чтобы сократить когнитивную нагрузку на stream-aligned teams.
- **Enabling team** — технические консультанты, помогают stream-aligned teams в повышении их возможностей. Разрабатывают библиотеки, рекламируют новые подходы.
- **Complicated-subsystem team** — отвечают за особую часть системы, которая требует специальных знаний. Например, сопровождение особо сложной математической модели внутри приложения.
- **Platform team** — предоставляют внутренний сервис для снижения когнитивной нагрузки, которая ложится на stream-aligned команды во время работы над их сервисами.
Поднимайте локально в docker необходимые сервисы. Используйте библиотеки типа Testcontainers для интеграционного тестирования
@Testcontainers
public class RedisBackedCacheIntTest {
@Container
public GenericContainer redis = new GenericContainer(
DockerImageName.parse("redis:5.0.3-alpine")).withExposedPorts(6379);
@Test
void redisIntegrationTest() {
// ...
}
}
Рассматривайте логи как поток событий. Приложение только должно выводить логи в stdout, за сбор и хранение отвечает среда выполнения.
До:
2021-07-29 14:54:55.1623|INFO|New report created by user 4253
После:
{
"TimeStamp": "2021-07-29 14:52:55.1623",
"Level": "Info",
"Message": "New report created",
"UserId": 4253,
"ReportId": 4567,
"TraceId": "a58fef40-90a3-4c40-a918-e1506e10bc3e"
}
- Позволяет искать логи по конкретным полям
- Нет уникальных паттернов разбора логов для каждого источника
- Добавление сквозного идентификатора процесса позволит связать логи с нескольких систем
Код и скрипты для администрирования должны поставляться вместе с приложением, чтобы избежать проблем с синхронизацией
- Скрипты миграции схемы БД должны храниться в репозитории приложения
- Все разовые скрипты должны запускаться из контекста приложения
Следование 12 факторам позволяет добиться:
- Минимизации времени подключения нового разработчика к проекту
- Максимальной переносимость приложения между средами выполнения
- Возможности горизонтального маштабирования
- Использования непрерывного развертывания
- Готовности к разворачиванию в облаке