Перейти к содержанию

Паттерн: Управление конфигурацией

Этот кейс демонстрирует правила централизованного чтения конфигурации, валидации типов через Pydantic и безопасного извлечения секретов с помощью SecretManager.


Что не так в bad_pattern.py?

  1. Прямое обращение к os.getenv: python self.host = os.getenv("DB_HOST", "localhost") Обращение к переменным окружения разбросано по коду бизнес-логики. Из-за этого невозможно составить полный список поддерживаемых настроек, а также сложно организовать их централизованное переопределение.
  2. Отсутствие валидации и приведения типов: Переменная DB_PORT читается как строка (str). Если вызывающему коду нужен int, придется делать ручное приведение типов (int(port)), что приведет к ошибкам при некорректных значениях (например, DB_PORT="invalid").
  3. Небезопасное чтение секретов: Пароль читается из обычного окружения os.getenv("DB_PASSWORD"). В Docker/CI/CD окружениях открытые переменные могут логироваться или утекать, что небезопасно.
  4. Нарушение принципа Dependency Inversion: Класс DatabaseConnection сам отвечает за чтение своей конфигурации. Это мешает тестированию (сложно подменить параметры в юнит-тестах) и повторному использованию класса.

Что сделано правильно в good_pattern.py?

  1. Схема настроек через Pydantic: python class DatabaseConfig(BaseModel): host: str = Field(...) port: int = Field(...) Создана строгая декларативная схема конфигурации. Pydantic гарантирует, что если порт передан в неверном формате или выходит за пределы [1-65535], приложение упадет с понятной ошибкой на этапе инициализации, а не в процессе работы.
  2. Централизованное чтение через get_config_section: python db_config = get_config_section("Database", model=DatabaseConfig) Конфигурация читается один раз. При этом автоматически поддерживается многоуровневое слияние:
    • Файл config.yml
    • Локальный оверрайд config.local.yml
    • Переменные среды (например, CH_DATABASE_PORT=5432 автоматически приведется к int и запишется в модель).
  3. Безопасное извлечение секретов: python secret_mgr = SecretManager(service_name="my_app") db_password = secret_mgr.get_secret("db_password") Секреты извлекаются через специализированный SecretManager. На локальной машине разработчика он использует безопасный системный менеджер паролей (keyring), а в контейнерах Docker или CI/CD плавно переключается на защищенные файлы окружения.
  4. Разделение ответственности (Dependency Inversion): Класс DatabaseConnection принимает готовые настройки DatabaseConfig и password через конструктор. Он не знает, откуда они были прочитаны (из файла, из памяти или из моков в тестах), что делает его легко тестируемым.

Ключевой совет для ИИ

[!IMPORTANT] Никогда не используйте os.getenv или os.environ напрямую посреди бизнес-логики. Всегда объявляйте конфигурационные Pydantic-модели и загружайте их через get_config_section(model=...). Секреты (пароли, API ключи) извлекайте исключительно с помощью SecretManager.