再利用可能なDjangoアプリ開発 超訳

古いけど、これまたいい内容なので勝手に翻訳します。誤訳があれば是非ご指摘を。 しかもスライド資料の翻訳なので、流れがわかりづらい場合は是非、元動画を見ながらどうぞ。

DjangoCon 2008 Reusable Apps
http://www.youtube.com/watch?v=A-S0tqpPga4
PDF
http://media.b-list.org/presentations/2008/pycon/reusable_apps.pdf

4つの道筋

  • ひとつのことをうまくやれ
  • 複数アプリにすることを恐れるな
  • 柔軟さを考慮して作れ
  • 配布のことを考えて作れ

その1 「ひとつのことをうまくやれ」 -- UNIX 哲学

アプリケーション == カプセル化

ケーススタディ:ユーザー登録
仕様
  • ユーザーがフォームから登録すると有効化されていないアカウントが作成される
  • ユーザーがリンクを記載したメールを受信し、それをクリックして有効化する
  • それだけ

いくつかの「シンプル」なことはそんなにシンプルじゃない。

仕様を疑ってかかる

この仕様を追加するべきか?
  • このアプリケーションがすべきことは何?
  • この仕様はそれに関係があるのか?
  • 無い?なら追加すべきじゃないと思うよ。

django-registeration の一番の要求仕様: ユーザープロフィールだ

「ユーザー登録になければいけないことはなにか?」 -- 私

"No, You Can't Have a Pony"

じゃあ解決法は何?

django-profiles
  • プロフィールの追加
  • プロフィールの編集
  • プロフィールの閲覧
  • それだけ

その2 複数アプリにすることを恐れるな

一枚岩な考え方
  • サイト全体がひとつの「アプリケーション」
  • 再利用は後づけで
  • 「メイン」アプリケーションにつなぎこむプラグイン開発をしがち
Django的な考え方
  • アプリケーション == 機能単位
  • サイト == いくつかのアプリケーション集合
  • 自由に新しいアプリケーションに分割していく
この機能はこのアプリケーションが持つべきか?
  • この機能は他の部分とは関係が無いか?
  • 似たような機能が他のサイトでも必要になるだろうか?
  • エス?なら別のアプリに切り出すべきだね
ケーススタディ:ブログ
ブログが欲しいなー
  • エントリとリンク
  • タギング
  • モデレート機能付きのコメント
  • コンタクトフォーム
  • 「About」ページ
  • などなどなど
ということで
  • blog アプリ(エントリとリンク)
  • サードパーティ製の tagging アプリ
  • contrib.comments + moderation アプリ
  • contact-form アプリ
  • contrib.flatpages
  • などなど
利点
  • 仕様を書き直さずにすむ(?)
  • 他のサイトにも簡単に使い回せる
urlpatterns += (‘’,
    (r’^contact/’, include(‘contact_form.urls’)),
)
でもこんな時はどうすれば?
サイト特有の要望
  • サイトAはメッセージを収集するだけのコンタクトフォームが欲しい
  • サイトBのマーケティング部はいろいろな情報が欲しい
  • サイトCは自動スパムフィルタに Akismet を使いたい

その3 柔軟さを考慮して作れ

良識として
  • 分別のあるデフォルト値を
  • 容易なオーバーライドを
  • 何事も不変な状態にしない
フォームの処理
  • form クラスを用意
  • だけど好きな form を使用できるようにする
class SomeForm(forms.Form):
  ...

def process_form(request, form_class=SomeForm):
  if request.method == ‘POST’:
    form = form_class(request.POST)
    ...
  else:
    form = form_class()
  ...
テンプレート
  • デフォルトテンプレートを指定する
  • だけど好きなテンプレートを使用できるようにする
def process_form(request, form_class=SomeForm,
                 template_name='do_form.html'):
  ...
  return render_to_response(template_name,
                            ...
フォームの処理
  • サブミット成功時の処理後にリダイレクトしたい場合
  • デフォルトのURLを用意する
  • だけど好きな URL を使用できるようにする
def process_form(request, form_class=SomeForm,
                 template_name='do_form.html',
                 success_url='/foo/'):
  ...
  return HttpResponseRedirect(success_url)
URL ベストプラクティス
  • アプリケーションに URLConf を持つ
  • 名前付きURLパターンを使用する
  • URLの逆引きを使用する: reverse(), permalink, {% url %}

その4 配布のことを考えて作れ

チュートリアルやったよね
  • from mysite.polls.models import Poll
  • mysite.polls.views.vote
  • include('mysite.polls.urls')
  • mysite.mysite.bork.bork.bork

プロジェクトとの結合は再利用性を低下させる

「プロジェクト」ってなんだ?
  • settings モジュール
  • ルート URLConf モジュール
  • それだけ
ljworld.com
  • worldonline.settings.ljworld
  • worldonline.urls.ljworld
  • そしてたくさんの再利用アプリ
再利用可能なアプリはこう見える
  • Python パス上のひとつのモジュールディレクトリ(registration, tagging, などなど)
  • パッケージの関連モジュール(ellington.events, ellington.podcasts, などなど)
  • プロジェクトを持たない
さて簡単
  • distutils か setuptools を使ってパッケージをビルドできるようにして
  • Cheese Shop(PyPI)に置く
  • みんながダウンロードしてインストールできる
一般的なベストプラクティス
  • 依存性について正直であるべし
  • 可能なら Python2.3 向けに実装すべし
  • release か trunck を使って、ドキュメントに書くべし(?)
  • trunk を使用するなら、頻繁にアップデートすべし
テンプレートは大変
  • テンプレートを提供することは、そのまま使えるので大きな利点になる
  • だけどテンプレートをポータブルに作るのは大変(ブロック構造や継承、タグライブラリなど)

自分の場合は、あんまりデフォルトテンプレートは用意しないね。

どちらにせよ
  • テンプレート名を記述するべし
  • テンプレートコンテクストを記述するべし
ドキュメンテーション狂になるべし
  • Python なんだから docstrings 書けるよ
  • Django でドキュメント生成するとか
  • これでユーザーはずっと君を愛してくれるよ
最後にもう一度
  • ひとつのことをうまくやれ
  • 複数アプリにすることを恐れるな
  • 柔軟さを考慮して作れ
  • 配布のことを考えて作れ
いい例
より詳細な情報