令和になってもDjangoを選ぶ理由・GoやTSとの比較

WebバックエンドAPIの開発にGo,TypeScript等々、いろんな言語・いろんなフレームワークやライブラリを利用していたが、結局Djangoに戻ってきた。その理由を比較を含めて、現時点での所感を書いていく。

前提条件として、動作させるインフラはオンプレ・Linux仮想マシンにデプロイするWebアプリケーション。この環境下においては、特定のフレームワークによってデプロイが手軽になる訳ではない。開発は、少ない人員で広い分野をカバーする必要の有る(または、その方が効率の良い)事業の初期段階を想定している。継続的に運用を行う必要があり、ハッカソンのような作り捨てを想定しない。

この記事は kb advent calendar 2日目の記事です。 https://adventar.org/calendars/10241

Django

最近は主に業務で利用している。

  • Good
    • Django Adminはエンジニア・非エンジニア向け両方の運用画面を提供することができ、高度にカスタマイズすることが可能
    • DB関連機能ORM,Migrationが非常に充実しており、他のコンポーネント(OpenAPI出力, Admin, テスト, etc…)にも密に統合されており利用しやすい
    • ローカル環境にSQLite、本番環境にMySQL,Postgresqlを利用することも容易に可能
    • 認証機能が標準提供され、拡張も容易
    • OpenAPI定義の出力がうまく機能する
    • 設定ファイル・テストなどの仕組みなども提供され、プロジェクト毎のディレクトリ構成の差異が少ない
    • テストケース毎にDB Rollbackが自動的に行われるなど、個々の機能に対する非常にサポートが厚い
    • REST APIを構築する際にはDjango REST Framework(通称DRF)ライブラリが非常に便利
    • 公式サイトのチュートリアル資料は非常に充実している
    • 標準でセキュリティが安全側に倒されている(CSRF,XSS,SQL Injection,Session Hijack等々)
  • Bad
    • Pythonなのでビルド時に検出できるエラーは少ない
    • Djangoのコード単位Appの分割単位がいまだに分からないし、後から分けるのは非常に難しい
    • フレームワークが提供する機能の幅が広く、初期の学習にハードルを感じる
    • デプロイ方法で提供されるWSGI,ASGIは実行モデルが古臭く、Go等と比較すると同時実行数等の面で見劣りする
    • PIP等で提供されるパッケージやそのドキュメントは、他の言語のものより未熟でリリースが活発で無いものが多い

他の環境でORM,Migrationを触ってからDjangoに触れると本当に良く出来ていると感動する。モデルを記述すると、その情報をもとにORM, マイグレーションの自動生成, Admin画面, REST API実装, OpenAPI出力等々、全てが少ない設定やコード記述でうまく動く。

密結合されているからと言ってカスタマイズ性が下がっているとも感じない。例えばRESTエンドポイントを実装する際に必要なコードは基本的に、urlsへのパスパターンの登録・viewsでのモデル登録・serializerでの出力フィールドの選択の3つとなる。既存のモデルであれば、各ファイル数行の記述で良い。ページングも1行書くだけで動作する。しかし、POSTだけ特殊な処理を行いたいという事も、特殊な認証・認可を記述する事も、ユーザによって行をフィルタして表示したいという事も、それぞれ1つのメソッドを上書きするだけで実現できる。

標準的なWebシステムに必要なパーツは、ほぼ全て標準で提供されている。プロジェクト間で構成も似るので、多数のプロジェクトが同時に走るような会社においては認知負荷を下げる事ができる。コミュニティのライブラリが手出しできる範囲が広くなるというメリットも有る。

Flask(Python), Express(Node.js), Sinatra(Ruby)等との比較

Flask, Expressについては何度も触っているが、Rubyはほぼ未経験という立場。

  • Good
    • 機能が少なく、最低限動かすために必要な知識は少なく済む
    • DynamoDB等のKVSを利用するケース、機械学習フレームワークを利用するケースなど、単機能のマイクロサービスを構築する際には見通しが良くなる
  • Bad
    • データベース・認証等、多くのサービスで実装が必要な部分に対するサポートが無いに等しい
    • エコシステムの不足
    • 管理画面を提供するコストが非常に大きい

これらは基本的なHTTPサーバを構築するための薄い機能のみを提供する。データベースアクセスはSQLAlchemy, TypeORMなどの他のライブラリに任せられ、それぞれの機能の統合具合は低い。さらに多くの場合、ORMにDBマイグレーション機能は付属しないか、あまり自動生成の質が良くなくRDBMSに依存したSQLのDDLを手書きする必要があり、本番環境で継続的に運用するにはかなり神経を尖らせる必要がある。

認証もプラグインなどの形で提供される事が多いが、フレームワーク毎に標準的なORMが存在しないので永続化に関わる部分はすべて手で実装する必要がある。

また、ユーザに直接提供しないもののサポートの際などに必要になる事が多い管理画面は提供しない。React-Admin等を使って画面を作り、それに必要なAPIをすべて手作業で実装するという途方もない作業が発生することも多く、管理画面を作らない選択をする場面も多くなる事が想像できる。

Djangoの場合はView,ORM,Migrationなど、基本的なWebアプリケーションに必要なパーツがすべて提供されている。多くの場合Webサーバなんて言ってしまえば、DBを操作するためのラッパーに過ぎない。モデル定義を1箇所に書くだけで、過去の内容と差分を取ってマイグレーションファイルを作成してくれるし、これらは特定のRDBMSに依存しないDSLで出力される。SQLでないDSLが出力される点については好みが割れる部分だとは思うが、ローカル環境ではSQLiteを利用して高速・手軽にテストを実行できるなど、享受できるメリットも非常に大きい。

また、すべて標準提供されているのはインストールや設定の手間が減る以上に、エコシステムの親和性が一段階上の物になるというメリットが大きい。例えばDjango REST Frameworkは、モデル定義を元に基本的なGET,POST,PUT,PATCH,DELETEエンドポイントを自動的に提供するし、drf-spectacularライブラリを併用すればモデル定義を元にしたOpenAPI定義を自動生成する。

Flask等にはORM等の組み合わせるライブラリを選べるというメリットは存在するが、選べること自体には技術的好奇心を満たす以外の価値が無い場合も多々あると思っている。選択肢が多い場合ライブラリ等は多くの環境をサポートする必要があり、相対的にできることは狭くなり、結果的に標準化が行われない。多くの場合自分は暇な選択肢であったとしても、Djangoのエコシステムを評価するべきケースが多いのでは無かろうかと考える。

Goのecho, gin + oapi-codegen, ogen + ent, GORMの組み合わせとの比較

大きなWebシステムを記述しようとしていた時期もあるが、最近はマイクロサービスを中心に業務で記述している。

  • Good
    • Goroutineや言語標準ライブラリの品質が非常に良く、並列処理を非常に簡潔に記述できる
    • コミュニティで開発されるライブラリの品質は高く種類も多い
    • Python等と比べると実行モデルも新しく、パフォーマンスが良い
    • DynamoDB等のKVSを利用するケース、機械学習フレームワークを利用するケースなど、単機能のマイクロサービスを構築する際には見通しが良くなる
  • Bad
    • ORMが発展途上で複雑なクエリ等を記述するには機能不足を感じる
    • データベース・認証等、多くのサービスで実装が必要な部分に対するサポートが無いに等しい
    • 管理画面を提供するコストが非常に大きい

欠点については先のFlask ,Express, Sinatraと共有される部分が多い。ただし、Goroutineが使えたり、活発に開発されているライブラリの豊富さなどは非常に魅力。

自分の考えとしては、ユーザの管理や認証などはDjangoに任せた上で、直接ユーザのデータにアクセスする部分などPythonで書くには厳しい部分についてGoで開発するのが良い塩梅かなと思う。社内でも概ねそんな感じ。

Laravel(PHP), Ruby on Railsとの比較

あまり真面目に触ったことがなく、友人から話を聞いたり表面的な情報を調べた事に留まる。

  • Good
    • 基本的にはDjangoに近い目的で作られているので共有されるメリットは多い
    • コードの自動生成機能が充実している
  • Bad
    • DB Migrationはサポートされているが、ある程度手動の記述・コマンド発行を要求する

単に個人的な言語の好みで避けている部分も否定できないが、主にDBマイグレーション・Admin・コード生成などの考えがDjangoの方が合っていると思うことが多い。

DBマイグレーションについては、Laravel, RoR共にモデルとは別にDDLをラップしたコードを開発者自身が記述する問うスタイルを基本としている。一方で、Djangoはフレームワーク側が今まで生成したマイグレーションファイルと現在のモデルファイルの差分を自動で検出し、マイグレーションを自動で生成する。手で記述することは非常に稀で、ほとんどすべてのケースで自動生成されたものをそのまま適用することが可能。必要に応じて、Up,DownのロジックをPythonで詳細に記述することも可能。

特にRoRが顕著だが、Scaflod機能は大量のファイルを生成するが、Djangoではそのような生成コマンドを利用する場面は少なく、手で明示的に各Viewを定義していくことになる。しかしながら、Djangoは適切なクラスを用意しており、数行のコードでエンドポイントを追加可能なので、特に面倒だと思うことはない。標準で提供される機能をカスタマイズすることも大抵の場合容易に行える。

Admin画面については、Laravelは有償のNova, RoRはActive Adminが提供されているようだが、両方周りで使っている話をあまり聞かないのでよくわからないが、Django Adminは標準提供された上に、公開するModel定義を選択する程度で実用的なサイトが提供されるので非常に利便性が高い。

所感

最近導入されつつ有る、Type hintingによって以前よりはエディタのサポートを手厚く受けることができるようになった。それでも局所的に見れば、Go, TypeScriptの型が恋しいと思う時は多い。

新しいORMなどが開発されたり機能追加されるたびにRedditなどで「それはDjangoで10年前から出来てる」とコメントが付くのがお約束になっているだけあって、完成度はめちゃくちゃ高い。TypeScriptのORM”drizzle”はトップページにユーザの声のような形で”Django had it in 2008”と書いているのが味わい深い。 https://orm.drizzle.team/

個人的にPythonという言語やPIPエコシステム等は好きというわけではないが、広い視点で見たときにWebアプリケーションを作るためのフレームワークとしての質はDjangoが頭一つ出ているように感じる。最初に学ぶべきことは他の選択肢に比較すると多くなるかもしれないが、慣れればプロジェクトの初期に必要なコード記述・設定・ディレクトリ構成の決定などが大幅に削減できると考えている。

技術の選択というのは、「型がきれいに記述できる」「並列処理が強い」「デプロイが容易」等の個々で判断するのではなく、全体の開発フローがどうなるかという視点も重要なのではないかと感じる。その観点で今更ながらDjangoへの個人的な評価はこの1,2年でかなり上がった。

有名企業・インフルエンサー的な人物が利用しているからと言って、人員などの面で状況が似ているとも限らない。エンジニアは大域的な視点でもって技術導入を行うべきだろう。