「LaravelのModel」=「モデル」ではない、という話
はじめに
「LaravelのModel」は、LaravelというWebアプリケーションフレームワークの世界の中ではもちろん「モデル」なのですが、Laravelの世界の外では「モデル」とはならないことが多々あります。Laravelでの開発しか経験していないと、ついつい「LaravelのModel」=「モデル」と捉えてしまいがちですが、具体的に何を「モデル」とするのかは、設計やアーキテクチャー、フレームワークなどによって変わるものです。
ドメイン駆動設計で見る「LaravelのModel」
では、「LaravelのModel」はLaravelの世界の外では何になるのか、という具体例として、ドメイン駆動設計に登場する用語を使うと「LaravelのModel」が何になるのかを見ていきます。
話を単純化するため、以下の2つのことができるだけの極めてシンプルなアプリケーションを作成することを考えてみてください。
- 記事を作成する
- 指定されたIDの記事を返す
ここでいう「記事(=Article)」も、「題名(=title)」と「本文(=body)」というただの文字列のプロパティを持っているだけのような、極めてシンプルなオブジェクトとしてください。
第1段階
上記のアプリケーションをLaravelで作成する場合、まずは \App\Models\Article という「LaravelのModel」を作り、その上で以下のような流れの処理を作ることになるはずです。
- 記事を作成する
- ユーザーが作成したい「記事」の「題名」と「本文」を入力し、入力した内容を送信する
- コントローラーがユーザーが送信した内容を受け取る
- 受け取った内容で
\App\Models\Articleのインスタンスを作成し、保存する - 保存した
\App\Models\Articleのインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
- 指定されたIDの記事を返す
- ユーザーが取得したい「記事」のIDを入力し、入力したIDを送信する
- コントローラーがユーザーが送信したIDを受け取る
- 受け取ったIDに対応する
\App\Models\Articleのインスタンスを取得する - 取得した
\App\Models\Articleのインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
第2段階
Laravelのアプリケーションのコードとしては上記のような処理を書けば十分だと思いますが、 3. の \App\Models\Article のインスタンスの保存や取得は、実際はデータベースに対して行われます。そしてこのデータベースに対して行われる操作は「Laravelのモデル」が内部的に行っているわけですが、このときの処理を分解すると、以下のようになります。
- 記事を作成する
- ユーザーが作成したい「記事」の「題名」と「本文」を入力し、入力した内容を送信する
- コントローラーがユーザーが送信した内容を受け取る
- 受け取った内容で
\App\Models\Articleのインスタンスを作成する \App\Models\Articleのインスタンスから、データベースにレコードを追加するSQL文を生成する- 生成したSQL文を実行し、データベースにレコードを追加する
- 保存した
\App\Models\Articleのインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
- 指定されたIDの記事を返す
- ユーザーが取得したい「記事」のIDを入力し、入力したIDを送信する
- コントローラーがユーザーが送信したIDを受け取る
- 受け取ったIDに対応するレコードをデータベースから取得するSQL文を生成する
- 生成したSQL文を実行し、データベースからレコードを取得する
- 取得したレコードの内容で
\App\Models\Articleのインスタンスを作成する - 作成した
\App\Models\Articleのインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
第3段階
ドメイン駆動設計では、「記事」のようなオブジェクトのことを 「エンティティ」 と呼び、この「エンティティ」の保存や、保存した「エンティティ」の取得をする役割のものとして、 「リポジトリ」 というオブジェクトが登場します。
これらの用語を使って上記の処理を言い換えると、以下のようになります。
- 記事を作成する
- ユーザーが作成したい「記事」の「題名」と「本文」を入力し、入力した内容を送信する
- コントローラーがユーザーが送信した内容を受け取る
- 受け取った内容で「記事エンティティ」のインスタンスを作成する
-
作成した「記事エンティティ」のインスタンスを「記事リポジトリ」に渡し、保存させる
- 「記事リポジトリ」が、受け取った「記事エンティティ」からデータベースにレコードを追加するSQL文を生成する
- 生成したSQL文を実行し、データベースにレコードを追加する
- 保存した「記事エンティティ」のインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
- 指定されたIDの記事を返す
- ユーザーが取得したい「記事」のIDを入力し、入力したIDを送信する
- コントローラーがユーザーが送信したIDを受け取る
-
受け取ったIDを「記事リポジトリ」に渡し、対応する「記事エンティティ」を取得させる
- 「記事リポジトリ」が、受け取ったIDに対応するレコードをデータベースから取得するSQL文を生成する
- 生成したSQL文を実行し、データベースからレコードを取得する
- 取得したレコードの内容で「記事エンティティ」のインスタンスを作成し、作成した「記事エンティティ」を返す
- 取得した「記事エンティティ」のインスタンスを使ってHTMLやJSONのデータを生成し、ユーザーに返す
\App\Models\Article という「LaravelのModel」がすべて「エンティティ」と「リポジトリ」に置き換わっていますが、処理の内容は本質的には何も変わっていません。このことから「LaravelのModel」は、ドメイン駆動設計の「エンティティ」と「リポジトリ」の性質や役割を1つにまとめたものだ、ということができます。
最後に
同じものを別の単語で表現する、別のものを同じ単語で表現する、あるいは1つのものを複数のものに分割して表現する、複数のものを1つにまとめて表現する、ということは日常生活でもよくありますが、ソフトウェアの開発では「モデル」という単語がよく登場し、何を「モデル」とするのかは設計やアーキテクチャー、フレームワークなどによってまちまちです。更に「モデル」はその中でもかなり根幹となる要素になることが多いので、「LaravelのModel」のイメージに縛られることなく「モデル」という単語の意味を捉えることが必要になります。
Discussion