概略
MVC とか MVVM とかそういったものを耳にした人は多いと思いますが、それはそうと、オニオンアーキテクチャだ、クリーンアーキテクチャだと、設計の全体が見えず、何を学べば良いのか、どれがどう関連しているのか、が見えずに困っている人がいると思います。かくいう私もそうでした。
この文章はそんな人のために、システム設計を考えるための知の高速道路を敷設することを目的としています。
なので、鉞を歓迎します。
MVC とかの話
Model と View を分離しよう
最も良く聞くであろう設計パターンが MVC だと思います。これは
Model – View – Controller
の頭文字を取っていて、雑に説明すると
- Model : 内部ロジック
- View : 表示
- Controller : 入力
です。
簡単なものでイメージすると、ボタンを押すとカウントが1ずつ増える画面があったとすると、
- Model : カウントを1増やす
- View : 今のカウントを表示する
- Controller : 何らかのボタン
と言う具合です。
他に有名どころだと MVVM なんかも良く聞くと思いますが、これは
Model – View – ViewModel
の略です。丁度対称形になっているのでこういった名称になっています。
こちらの特徴は、View と ViewModel が Bind されていて、ViewModel への変更がそのまま View に伝播する作りになっていることでしょう。
これは、スマホアプリ等で良く採用されるのですが、理由は明確で、今時出力と入力って分離されてなくて、同じ画面上に配置されているよね、と言う理由が理解しやすい気がします。ガラケーの数字キーを上下左右に割り当てているのを MVC と捉えると比較しやすいですね。
で、MVVM の場合、ViewModel への変更を View に伝播させるために Observerパターン、View に置かれた UI要素への何らかのユーザー行動を入力とするために Commandパターンが使われたりします。
Unity を使っている方は MVP や、MV(R)P などを聞くこともあると思います。
これらはつまり、Model と View を分離したい、と言うパターンです。何かで聞いた FatModel にしよう!と言うやつです。MVWhatever なんてものもあります。これなんかはまさに、なんでも良いから Model と View を分離しろ!ってことですね。
そして皆さんは迷宮に迷い込むのです。
で、View と Model を分離したは良いけれど、Model の中はどう分けるの?と。
Model をどう分ける?
ここでは4層のレイヤードアーキテクチャを例として出します。
Presentation -> Application -> Domain <- Infrastructure
みたいなやつです。依存の方向を矢印で表しています。
これと MVC を対応させると、
- Model : Application, Domain, Infrastructure
- View : Presentation
- Controller : Presentation
何と言うことでしょう!MVC や MVVM 等で語られていることは、レイヤードアーキテクチャでいう Presentation層の話だったのです!
つまりは、FatModel にしよう、からの、Model をどう分ける?の答えがそのまま、レイヤードアーキテクチャ、オニオンアーキテクチャ、クリーンアーキテクチャ等、アーキテクチャ設計そのもので、ここまで読んだ方はもう各アーキテクチャの話に入っていけると思います。Model を分けているんです。
4層レイヤードアーキテクチャ
これを選んだのは話をするのに都合が良いからです。もう一度構造を見てみましょう。
Presentation -> Application -> Domain <- Infrastructure
横に並べてしまっているのでやや分かりにくいですが、依存の最下層に Domain層がいます。
Infrastructure層は DB や、外部API 等データの永続化やアルゴリズムの実体が入っていたりします。外部API が Infrastructure層?と思う方はクリーンアーキテクチャでいう Frameworks & Drivers層に含まれる External Interfaces がここに入っていると考えて良いです。
で、Model の分割の観点で見ると、Infrastructure層は一旦外して、Application層、Domain層が我々が実装するべき Model です。私が説明のために4層レイヤードアーキテクチャを採用した理由がここにあるのですが、Model を2つに分割しています。よく見る説明として、
- Application層 : Usecase を記述する
- Domain層 : ビジネスロジックやドメインモデルを記述する
なんて文章が出てきてビジネスロジック?ドメインモデル?となる訳です。
なので、ざっくり何に関心があるのかを説明すると
- Application層 : ユーザー視点での使い方(Usecase)を記述する
- Domain層 : システムが提供する機能(ビジネスロジック)を記述する
と読み替えます。こうすると Separation of Concerns(SoC, 関心の分離)が行われているのが分かります。
因みに依存の向きですが、矢印の先で変更があると、その元の方に連鎖的に変更が波及することを表しています。Infrastructure層を Domain に依存させるのは、DB や外部API と言った、自分たちでどうにかしにくい部分での変更の影響を Domain層に波及させたくないためです。ここで使われているものは SOLID の D である Dependency Inversion Principle で、実現するために Repository パターンがよく使われます。
そして、それぞれに Interface Segregation Principle(インターフェース分離)を用いて Liskov Substitution Principle(リスコフの置換)をしておくと、機能を追加しやすく修正が他に波及しにくい設計になります(Open/Closed Principle, 開放閉鎖の原則)。そして、それぞれのクラスの持つ責務は一つにする(Single-Responsibility Principle, 単一責任の原則)を守るとはい良い感じの Model 分割ができたぞ?となる訳です。
あら、アーキテクチャの話をしていたらSOLID原則の話になりましたね。はい、大事なんです。
まとめ
クリーンアーキテクチャをはじめとする各種アーキテクチャ論は難しいけど難しくない!
MVC 等の Presentation層を如何にきれいに分離させるか、と言う話とは見ている部分が違う。
なんでか知らんけど Model を分割しよう!となると本が DDD からになってしまう。この断絶の理由は良く分かりません!
と言う感じでした。