Паттерн: Управление конфигурацией
Этот кейс демонстрирует правила централизованного чтения конфигурации, валидации типов через Pydantic и безопасного
извлечения секретов с помощью SecretManager.
Что не так в bad_pattern.py?
- Прямое обращение к
os.getenv:python self.host = os.getenv("DB_HOST", "localhost")Обращение к переменным окружения разбросано по коду бизнес-логики. Из-за этого невозможно составить полный список поддерживаемых настроек, а также сложно организовать их централизованное переопределение. - Отсутствие валидации и приведения типов:
Переменная
DB_PORTчитается как строка (str). Если вызывающему коду нуженint, придется делать ручное приведение типов (int(port)), что приведет к ошибкам при некорректных значениях (например,DB_PORT="invalid"). - Небезопасное чтение секретов:
Пароль читается из обычного окружения
os.getenv("DB_PASSWORD"). В Docker/CI/CD окружениях открытые переменные могут логироваться или утекать, что небезопасно. - Нарушение принципа Dependency Inversion:
Класс
DatabaseConnectionсам отвечает за чтение своей конфигурации. Это мешает тестированию (сложно подменить параметры в юнит-тестах) и повторному использованию класса.
Что сделано правильно в good_pattern.py?
- Схема настроек через Pydantic:
python class DatabaseConfig(BaseModel): host: str = Field(...) port: int = Field(...)Создана строгая декларативная схема конфигурации. Pydantic гарантирует, что если порт передан в неверном формате или выходит за пределы[1-65535], приложение упадет с понятной ошибкой на этапе инициализации, а не в процессе работы. - Централизованное чтение через
get_config_section:python db_config = get_config_section("Database", model=DatabaseConfig)Конфигурация читается один раз. При этом автоматически поддерживается многоуровневое слияние:- Файл
config.yml - Локальный оверрайд
config.local.yml - Переменные среды (например,
CH_DATABASE_PORT=5432автоматически приведется кintи запишется в модель).
- Файл
- Безопасное извлечение секретов:
python secret_mgr = SecretManager(service_name="my_app") db_password = secret_mgr.get_secret("db_password")Секреты извлекаются через специализированныйSecretManager. На локальной машине разработчика он использует безопасный системный менеджер паролей (keyring), а в контейнерах Docker или CI/CD плавно переключается на защищенные файлы окружения. - Разделение ответственности (Dependency Inversion):
Класс
DatabaseConnectionпринимает готовые настройкиDatabaseConfigиpasswordчерез конструктор. Он не знает, откуда они были прочитаны (из файла, из памяти или из моков в тестах), что делает его легко тестируемым.
Ключевой совет для ИИ
[!IMPORTANT] Никогда не используйте
os.getenvилиos.environнапрямую посреди бизнес-логики. Всегда объявляйте конфигурационные Pydantic-модели и загружайте их черезget_config_section(model=...). Секреты (пароли, API ключи) извлекайте исключительно с помощьюSecretManager.