Djangoのアプリはどういう単位で作るべきか?

tell-k
DjangoCongress JP 2022 (2022.11.12)

おまえ誰よ?

_images/tell-k_300x300.png

BeProudの紹介

  • 私は主にTRACERYを開発しています
_images/beproud.png

個人でお手伝い

目的/動機

対象

今日話さないこと

基本的に Djangoアプリどう作るか、分けるか という話だけをします

対象とするプロジェクトの規模

体感的に適用できそうな規模は以下のようなイメージです

Q1. 開発チームの規模(人数)はどれくらいですか?

_images/graph_Q1.png

Q2. 開発チームのあなたの役割は?

他は

Djangoで最初に困った話

だいたいこんな感じのレイアウト

project
  ├── controllers
  │   ├── FugaContorller
  │   └── HogeContorller
  ├── models
  │   ├── Hoge
  │   └── User
  └── views
      ├── hoge_detail.html
      └── hoge_list.html

Django触り始めた時

_images/illust_komari.png

Djangoのアプリとは?

Django アプリケーション は単なる Python パッケージで、 Django プロジェクトで使うことのみを意図したものです。 アプリは一般的な Django の慣例に則っているでしょう。 例えば models, tests, urls, views のサブモジュールがあることなどです。

via https://docs.djangoproject.com/ja/4.1/intro/reusable-apps/

Djangoのアプリとは?

Django apps are small libraries designed to represent a single aspect of a project. A Django project is made up of many Django apps. Some of those apps are internal to the project and will never be reused; others are third-party Django packages.

Djangoアプリは、プロジェクトの1つの側面を表現するために設計された小さなライブラリです。 Djangoのプロジェクトは、多くの Djangoアプリで構成されています。 それらのアプリの中には、プロジェクト内部のもので決して再利用されることのないもの もあれば、 サードパーティの Django パッケージのものもあります。

via 4 Fundamentals of Django App Design | Two Scoops of Django 3.x

Djangoのアプリとは?

_images/django-apps-image-two-scoops-django.png

via 4 Fundamentals of Django App Design | Two Scoops of Django 3.x

Djangoのアプリとは?

ではDjangoのアプリを作る、分ける基準は?


It's not uncommon for new Django developers to become understandably confused by Django’s usage of the word “app”.

新しいDjango開発者が、 "app"という単語の使い方に戸惑うことはよくあることです。

via 4 Fundamentals of Django App Design | Two Scoops of Django 3.x

Q3. アプリを作る、分ける時の方針や、ガイドラインはチームにありますか?

_images/graph_Q3.png

アプリは分けないとダメなのか?

一つの大きなアプリの問題点

While common for small Django projects, larger projects typically don’t follow this pattern.

There are positives to this approach. Specifically, migrations are easier and table names follow a simplified pattern. It has to be said that other frameworks such as Rails embrace this technique and are quite successful.

However, while Rails and other tools are designed to follow this pattern, Django isn't optimized for this design.

via 4.5.2 The Large Single App Project | Two Scoops of Django 3.x

一つの大きなアプリの問題点

小さな Django プロジェクトではよくあることですが、大きなプロジェクトでは一般的にこのパターンに従いません。

このアプローチには利点があります。具体的には、移行がより簡単になり、テーブル名は単純化されたパターンに従います。Rails のような他のフレームワークもこの手法を取り入れ、かなり成功していると言わざるを得ません。

しかし、Rails や他のツールはこのパターンに従うように設計されていますが Django はこの設計のために最適化されていません

via 4.5.2 The Large Single App Project | Two Scoops of Django 3.x

Django的な思考

Django的な思考

一つのアプリでやっている例

アプリをどう作るべきか

"Do one thing, and do it well"

"ひとつのことをうまくやれ"

一つのことにフォーカスしてアプリを作る

Two Scoops of Django 3.x の例

よくフォーカスできている例

via DjangoCon 2008: Reusable Apps

フォーカスできていない例

via DjangoCon 2008: Reusable Apps

直交性(Orthogonality) があるか考える

とはいえなかなか難しい

アプリを複数作るのを躊躇しない

アプリを複数作るのを躊躇しない

小さいアプリを複数作ればそれでいいのか?

疎結合(Loose Copling)

Djangoスタックの基本的な目標は、疎結合と高い凝集度を実現することです。フレームワークの各レイヤーは絶対に必要でない限り、相手をお互いに「知る」べきではありません。

例えば、テンプレートシステムはWebリクエストについて何も知らず、データベース層はデータ表示について何も知らず、ビューシステムはプログラマがどのテンプレートシステムを使っているかを気にしません。

Django は利便性のためにフルスタックとなってはいますが、スタックのどのコンポーネントも、可能な限り独立させてあります。

via https://docs.djangoproject.com/ja/4.1/misc/design-philosophies/#loose-coupling

密結合の問題点

循環参照エラー

_images/circular_import_1.png

回避するために、メソッドの中でインポートしてしまう

_images/circular_import_2.png

アプリが相互依存していると壊れやすい

_images/circular_apps.png

via https://seddonym.me/2018/05/04/django-signals/#project-dependency-flow

アプリ間の依存関係を少なくするためにどうするべきか

_images/encapsulated_apps.png

via https://seddonym.me/2018/05/04/django-signals/#project-dependency-flow

チームで依存関係のフローを意識する

_images/real_dependecy_flow.png

相互に依存しないためにはどうすればいいか?

依存しても良いアプリに分ける

_images/sougo_depend_1.png

依存しても良いアプリに分ける

_images/sougo_depend_2.png

Djangoの仕組みを使う

他のアプリと相互依存してまうケース

_images/auditlog_model.png

他のアプリと相互依存してまうケース

_images/auditlog_logger.png

他のアプリと相互依存してまうケース

_images/auditlog_graph_1.png

(GenericForeignKeyを使うことを依存と表現するべきではないかもしれない)

シグナルを使い依存関係を単方向にする

_images/auditlog_signal.png

シグナルを使い依存関係を単方向にする

_images/auditlog_signal_graph.png

ミドルウェアを使う

_images/auditlog_middleware.png

ミドルウェアを使う

_images/auditlog_middleware_graph.png

アプリとURL構造を一致させない

_images/url_depend_1.png

アプリとURL構造を一致させない

_images/url_depend_2.png

それでも循環インポートはさける

Djangoの仕組みでモデルを取得する

頻繁に必要になるであろう、AUTH_USER のモデル get_user_modelで取れる

from django.contrib.auth import get_user_model
User = get_user_model()

それ以外のモデルも、django.apps.apps.get_model() 取得できる

from django.apps import apps
Blog = apps.get_model("blog.Blog")

オープン・クローズドの原則

オープン・クローズドの原則

_images/open_closed_apps.png

まとめ1

  • アプリはひとつのタスクにフォーカスしましょう
  • アプリ間が直交になるか考えてみましょう
  • 循環インポートを避けましょう
  • 依存関係が単方向になるよう整理しましょう

まとめ2

  • 依存しても良いアプリを作りましょう
  • DJangoの仕組みを使いましょう (シグナル、ミドルウェア, モデル取得)
  • アプリとURL構造を一致しないようにしましょう

Q5. Djangoの開発で参考にしている書籍やWebサイトは?

Q6. Djangoを最初に学び始めた時にどんなことに困った?

Q6. Djangoを最初に学び始めた時にどんなことに困った?

Q6. Djangoを最初に学び始めた時にどんなことに困った?

参考

参考

ご静聴ありがとうございました

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)