このBlogは移転しました。今後は aish.dev を御覧ください。

許されざる悪事

djangoの中に、こんな処理がある。

def get_cache(backend_uri):
    scheme, host, params = parse_backend_uri(backend_uri)
    …
    …
    …
    return getattr(module, 'CacheClass')(host, params)

cache = get_cache(settings.CACHE_BACKEND)

(http://code.djangoproject.com/browser/django/trunk/django/core/cache/__init__.py)

私はこの

cache = get_cache(settings.CACHE_BACKEND)

を許さない。モジュールのグローバルスコープで、他のモジュールの値を参照するという悪行を許すことはできない。

この行は、どこかで

import django.core.cache

と書かれただけで実行されてしまう。そして、djangoのような複雑なフレームワークでは、どのモジュールがいつimportされるか、予測することは不可能だ。django.core.cacheが、常にsettingsの初期化後にimportされるという想定は、妥当なものではないのである。

こういう処理を書きたければ、面倒でもかならず

def init_cache():
    global cache
    cache = get_cache(settings.CACHE_BACKEND)

とし、適切なところからdjango.core.cache.init_cache() を呼び出すようにするべきだ。何が不愉快といって、importの順番に依存した処理ほど不愉快なものはない。こういった依存性を持つ処理は非常に脆弱で、ちょっとしたことですぐエラーとなってしまい、メンテナンスしにくいコードになってしまうものなのである。