【プログラミング】MVC,MVPを理解するためのレイヤーアーキテクチャ
少しだけ長いので、根気を持ってお読みください。
レイヤーアーキテクチャについて
言葉で表現すると
- 個々のオブジェクトの設計に依存しない、概念的な部分の設計思想
- 各機能の「置き場所」の定め方
- あるいは、各機能の依存先を決める手段
- 責務を明確化する思想
この記事を読んでいるということは、MVPやMVCについては聞いたことがある、実践したことがある人は多そう
前提知識としてあると理解しやすい、かも
詳しく説明してくれている記事がありました
引用
"レイヤアーキテクチャというのはアプリケーションを責務に応じたいくつかの層としてとらえる設計手法のことです。"
表面的にはまさにこの通りですが、層という概念に当てはめてしまうのはいささか語弊があります
この記事のMVCの部分はすっ飛ばして(失礼ではありますが)レイヤーアーキテクチャの部分だけを読んでいただけると良いと思います
今回伝えたいことは、プレゼンテーション層、ドメイン層などで固定化されたレイヤーの話ではなく、必要な責務を考え、自身のアプリケーションに応じて必要なレイヤーを考え出すことをレイヤーアーキテクチャの知識として定義したいという話です
アーキテクチャの歴史
レイヤーアーキテクチャの理解のために、過去のアーキテクチャの歴史をまず振り返ってみます
オブジェクトアーキテクチャの歴史
いわゆる、個々の機能の設計です、大まかに3つの進化がありました
goto statement programming
プログラムの要所要所にラベルを定義し、goto文を使用して指定したラベルに飛ぶことで、ロジックを全て縦に記述しながらも強引にモジュール化を図るプログラミング手法です
あっちこっちに処理が飛び、人間の脳内キャッシュを膨大に使用するので今見ると非常にスパゲッティコードに見えるでしょう
なぜgoto文が悪であるのかはこちらの記事を読むとわかりやすいと思います
structured programming
構造化プログラミングのことです、かなり端折った説明をしますので本来の意味合いを知りたいのであれば書籍などを購入すると良いと思います
構造化プログラミングはgoto-lessとも呼ばれ、ロジックを上流(状態)、下流(処理)に分けることで上流の状態に応じた下流の処理を呼び出すという概念が生まれました
しかし、処理を分割すればするほど上流の状態が増えることになり、完全なロジックの分離はほとんど不可能でした
しかし、goto statementにはなかった、処理の記述に流れを作るという点において、近代のプログラミング思想の根底に関わっています
object oriented programming
皆大好きオブジェクト指向です、もはや呪いと言っても過言ではなさそうです
「データとロジックを一つのまとまりとして記述し、処理の関心を内側にのみ向け、処理に応じたメッセージを発行することで、他のオブジェクトの処理のトリガーとして影響を与えつつ、その影響に関心を持たない」
という概念になるかと思います
これを端的に表したものがオブジェクトという言葉であり、またクラスという機能として表現されているものです
この概念を用いることで、structured programmingだけではなしえなかったロジックの完全な分離が可能になりました
オブジェクトアーキテクチャのまとめ
goto statement programmingで処理を記述するという行為を行い
structured programmingで処理の流れの概念ができ
object oriented programmingでロジックの分離を行った
しかし、これでは処理の置き場所はオブジェクトで定義できましたが、オブジェクトの置き場所が定義できていません
ここからはオブジェクトのまとまりをレイヤーとして定義するアーキテクチャについてです
多層アーキテクチャ
近代的な設計思想は多数ありますが、そこから多層アーキテクチャを抜粋します
独立したモジュールとして層を定義し、差し替え、機能改善などを容易にすることが可能な設計思想です
代表的なものとして三層アーキテクチャが存在します
三層アーキテクチャは、Webアプリケーションが
- データベース
- ミドルウェア(インターフェース)
- ユーザー(ユーザー操作)
という要素で構成されるようになった際に提唱された概念です
データ、ロジック、プログラミング的な構成要素としては
- データベース・DB
- データベース操作のためのビジネスロジック
- ユーザーインターフェース
の三種類が必要になります
データベース
データを保持、管理します
ビジネスロジック
ユーザー操作に応じた処理のロジック、及びデータベースの操作を記述し公開します
ユーザーインターフェース
ユーザーの操作を検知し、操作に応じた処理をビジネスロジックに問い合わせます
(APIを叩くということと同義です)
ビジネスロジックの結果を使用して自身を更新します
以上のように、各レイヤーに対して明確に責務が割り当てられており
また、依存関係が単方向になっています
ビジネスロジック -> データベース
データベースは自身以外を知りませんし、ビジネスロジックはデータベース以外知りません
ユーザーインターフェースはビジネスロジック以外知りません
単方向ですね
責務を明確化すると、その責務を果たすために必要な情報を持つレイヤーに対してのみ依存する形になるため、結果として関連するロジックを持つオブジェクトの凝集度が上がり、依存関係を簡潔に定義することができます
レイヤーアーキテクチャのおさらい
- 個々のオブジェクトの設計に依存しない、概念的な部分の設計思想
- 各機能の「置き場所」の定め方
- あるいは、各機能の依存先を決める手段
- 責務を明確化する思想
です
重要な部分は責務の明確化です
MVC,MVPとは一体なんなのか?
Model - View - Controller
Model - View - Presenter
さらにはMVVM,CleanArchitectureまで様々な概念が存在します
これらはすべて、レイヤーアーキテクチャに基づいた責務の割り当て方の一つの形です
一般的に普及していると思われるMVCの例
Modelの責務
- データを管理する
- データを更新するためのロジックを公開する
- (必要であればサーバーと通信する)
- データの更新を通知する
Viewの責務
- ユーザー操作を提供する
- Modelの通知、データを元に自身を公開する
Controllerの責務
- ユーザー操作を監視する
- 操作に対応したModelの更新ロジックを呼ぶ
こういった形で責務が割り振られています
MVPも同じく、責務が割り振られています、MVVMもCleanArchitectureも同じです
こういった責務を捉える力を持つことで、MVCやMVPなどの既存のレイヤーに縛られない責務の洗い出し、割り振りが可能になります
例.MVCを、サーバーとの通信部分を踏まえて責務の割り振りを改善する
一般的なMVCの責務は前述しましたが、Modelがサーバーと通信する場合、しない場合を踏まえて、サーバーと通信するという責務を切り出し、別のレイヤーとして定義します
名前はServiceレイヤーとし、SMVCと定義します
Serviceの責務
- Modelを更新するためのロジックを公開する
- Model更新のためのデータをサーバーから取得する
Modelの責務
- データを管理する
- データを更新するためのロジックを公開する
- データ更新の際に必要であればServiceのロジックを呼ぶ
- データの更新を通知する
Viewの責務
- ユーザー操作を提供する
- Modelの通知、データを元に自身を公開する
Controllerの責務
- ユーザー操作を監視する
- 操作に対応したModelの更新ロジックを呼ぶ
切り出しました
MVCにはないメリットとして
このServiceレイヤーはサーバー側にのみ依存し、またローカル用のモックと差し替えることでローカル環境での更新も可能になりました
結果、Modelはシンプルな記述のみになったと思います
他にもあるかもしれません
こういった形で設計を改善することもできます、参考になったでしょうか
まとめ
責務を洗い出し、責務の一つ一つをオブジェクトの集合体となるレイヤーに割り振ることを
レイヤーアーキテクチャ
として定義し、広く理解され普及すると良いなと思います
知識の部分は厳密には間違いがあるかもしれませんが、伝えたいことが伝わっていれば幸いですね