包丁一本さらしに巻いて

Django Best Practiceへの道 #1

2014.04.01

DjangoのWebアプリを開発している際、リファクタ/テスト拡充のために集めた情報をまとめます。

戦略よりも、自分が入社した時既にあった前提に対応する為に考えた戦術を中心に書いていきます。また、自分の思考をダンプして記録しておくという目的もあるので、記述が冗長な部分もありますがご容赦ください。

前提

プロジェクト/アプリケーション構成

アプリケーション構成に何を求めるか

Djangoにはプロジェクトとアプリケーションという思想がある。Djangoが生まれた時からある概念で、1つのプロジェクトの中に、複数のアプリケーションを入れ、各アプリケーションの依存は可能な限り少なくし、取替え可能な形にする事を目指している。では実戦レベルでどのように分割するのが良いのか、という指針を実例を交えながら語ってくれているのが以下の資料。2008年の資料だけど、Djangoの根本的な思想は変わっていないので未だ有効だと思う。あと、”Do one thing, and one thing well”って本当にすごいかっこいいし、この思想を実装しているGNUやUNIX的なものはさらにかっこいいと思う。

DjangoCon 2008: Reusable Apps

上の資料を参考に設計する利点は主に2つ。

メンテナンスしやすくなる

このアプリケーション分割をすることで、「巨大な1ファイルのコード」が存在し得ない構成となる。誰かが意識してメンテしにくい巨大な1ファイルを作らないようにする、ではなく、そもそもそんなものが発生し得ない構成にすることが肝要だと思った。

各モジュールの再利用可能性向上

普通の単独自社サービスであれば、そこまで再利用性を高める為に時間をかける必要はない気がするけど、Djangoを使った自社サービスが複数ある中でのライブラリ作成や、個別のお客さんによってカスタマイズが必要なパッケージ、というシチュエーションであればある程度時間をかけて設計する価値はあると思う。実際上の資料内でJamesさんが自社パッケージを各お客さん用にカスタマイズする際に、プラガブルに設計してて助かったぜ、という話がある。

プロジェクト構成に何を求めるか

実装

他の流派もあるのですが、一旦現在は以下のような形に落ち着いています。まだまだ継続改善中。

project
├── apps
│   ├── appA
│   ├── appB
│   └── appC
├── core
│   └── settings
├── docs
│   ├── files
│   └── styleguide
├── fixtures
├── libs
│   └── management
│       └── commands
├── requirements
├── server-config
├── static
├── templates
└── tests

上から順に概要を説明します。

この辺りはDjangoのテンプレート系ライブラリをかなり参考にしました。 有名なものになると、色々な知見が凝縮されており、読んでいるだけで楽しくなれます。

Two Scoops of Djangoで紹介されていた構成。これも非常に参考になる。

参考になるライブラリ群

設定ファイル構成

設定ファイル構成に何を求めるか

1番目と2番めが非常に重要だと思ってます。可能な限り1番目と2番めの目標が達成できるようにする、という指針で以下のようにしました。

設定ファイル実装

common.py以外は大体以下のような形になってます。

# -*- coding: utf-8 -*-
from core.settings.common import *  # NOQA

DEBUG = True
TEMPLATE_DEBUG = True
ENVIRONMENT = 'staging'
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django2',
        'USER': 'hoge_user',
        'PASSWORD': 'hoge_password',
        'HOST': 'hogehost',
        'PORT': '',
    }
}

try:
    from core.settings.local import *  # NOQA
except ImportError:
    pass

以下若干わかりにくそうな部分を解説します。

local.sample.py

各開発者がローカルで開発/テストする際に独自で入れる設定用ファイル。 local.sample.py内には特に何も設定されておらず、以下のようなコメントがあるのみ。

# -*- coding: utf-8 -*-
# ローカル環境用設定ファイル。以下のようにコピーして利用すること。
# cp local.sample.py local.py

core/settings/local.pyは.gitignoreに記載しておき、リポジトリからは無視しておく。このlocal.pyに各開発者用の独自設定を入れていきます。Two Scoops of Djangoでは各開発チームメンバーの独自設定もVCSに入れる事を推奨しています。理由としてあげているのは、「有害な設定を入れていたら指摘できる」「便利な設定を入れていたら共有できる」という事でしたが、正直独自設定を入れなくとも上記2点は達成可能なのであまりしっくり来ていませんので弊社では採用していません。

local_test.py

ローカルでテストを実行する時に利用する設定で、PASSWORD_HASHERSとかを変更、DBをsqliteのインメモリにしたり、テストを高速化するための工夫が施してある。この中身についてはテスト戦術で詳細に書きます。

その他の設定ファイルは大体名前の通りの内容が入ってます。

設定ファイル切り替え実装

manage.pyにはcore.developmentを直書きで指定し、開発用サーバ(manage.py runserver)は開発用設定がデフォルトで動くようにしています。これでローカルには特に環境変数設定せずともシンプルにmanage.py runserverすれば開発用サーバを起動できるようになってます。

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings.development")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

各環境(CI、ステージング、本番)用に作成したファイルは、アプリケーション実行ユーザの環境変数にDJANGO_SETTINGS_MODULEを設定して切り替える方式としています。

export DJANGO_SETTINGS_MODULE=core.config.staging

参考文献

次回はDjangoにおけるテスト戦術について書きます。

このエントリーをはてなブックマークに追加
comments powered by Disqus