Анти-шаблон local_settings.py
В мире разработки есть анти-шаблон, который предлагает использовать исполняемый код в качестве средства хранения значений конфигурации разных стадий проекта: разработка, тестирование, рабочая версия. Во вселенной Python обычно это выглядит так:
# Внимание! Это анти-паттерн
try:
from .local_settings import *
except ImportError:
pass
Что означает использование файла local_settings.py
для хранения локальных настроек проекта, в то время как сам файл занесен в игнор-список системы контроля версий (например в .hgignore
или .gitignore
). В таком случае локальный проект в стадии разработки использует исполняемый код вне системы контроля версий.
Если вам такой подход кажется неправильным, то вы на верном пути.
Лучше будет включить локальные настройки, секретный ключ и другие настройки в переменные окружения. Если же переменные окружения вам не подходят, то можно использовать в качестве хранилищ своих настроек файлы в форматах JSON, XML, YAML или те форматы представления данных, которые вам нравятся.
Что может случится, если использовать анти-паттерн local_settings в своем проекте, спросите вы?
Анти-паттерн local_settings
Это означает, что вы используете исполняемый код в процессе разработки, в то время как этот код не доступен другим разработчикам, что может вылиться в кошмар во время отладки проекта.
Но это перкрасно у меня работает!
То, что работает локально и успешно проходит тесты, может генерировать мелкие ошибки, которые не будут обнаружены, пока не станет слишком поздно. Вот пример того, что может случиться (с чем автор столкнулся в работе):
-
в течение многих лет в проекте использовался сторонний пакет для «слугификации», конфигурация была в настройках.
-
разработчик решил написать собственный проект «слугификации», работал отлично локально, поэтому они внесли изменения на сайте, чтобы использовать новые возможности.
-
тесты не учитывали крайние случаи в новой библиотеке.
-
стал использоваться в локальной разработке, а также на рабочем сервере.
-
через несколько дней клиенты в некоторых регионах мира стали жаловаться на то, что записи недоступны.
-
никто не может понять, почему рабочий проект ведет себя по-другому.
Первое, что было проверено — этот печальный кусок (именно кусок, а не часть) кода в настройках модуля:
# Внимание! Это анти-паттерн
try:
from .local_settings import *
except ImportError:
pass
У них был исполняемый код вне контроля версий. Что хорошо работало у разработчика, больше нигде не работало. Хватило того, что происходили мелкие незаметные ошибки, которые не были замечены людьми или тестами. Мелкие ошибки разработчика превращаются в большие ошибки у реальных пользователей программного продукта.
И что действительно плохо, так это то, что серьезные ошибки не удается отладить вначале, потому что перенесенный код не соответствует коду из local_settings.py
.
Но я не ошибаюсь!
Люди часто говорят: «Я не так глуп, как другие и не совершу такую ошибку».
Но каждый раз в течение последних 20 лет я решаю или помогаю решить проблему, вытекающую из исполняемого кода, который не отслеживался в контроле версий.
Я считаю, что все мы, разработчики, независимо от того, насколько бы ни были талантливы и опытны, можем и будем делать глупые ошибки.
Учитывая все это, почему бы не сделать умную вещь и не включить весь исполняемый код в управление версиями? А уникальные, секретные данные и ключи можно перенести в переменные окружения или файлы конфигурации. Готово!
Как обрабатывать конкретные переменные
Используйте либо переменные среды, либо файлы конфигурации. В самом деле. И не верьте мне на слово, посмотрите на все инструменты развертывания и услуги хостинга, которые рекомендуют такой подход.
Для этого либо определите свой собственный процесс для их обработки, либо используйте сторонний пакет. Лично для Django мне нравится простота использования этой функции в моих различных настройках:
# Хороший код!
from django.core.exceptions import ImproperlyConfigured
def get_env_var(var_name):
try:
return os.environ[var_name]
except KeyError:
error_msg = f"Set the {var_name} environment variable"
raise ImproperlyConfigured(error_msg)
SECRET_KEY = get_env_var("SECRET_KEY")
Перевод статьи https://www.pydanny.com/using-executable-code-outside-version-control.html
Вернуться на верх