アーキテクチャ●●○○○

MVC

エムブイシー

アプリをモデル・ビュー・コントローラの3役に分けるUIアーキテクチャの古典パターン。

概要

MVC(Model-View-Controller)は、ユーザーインターフェースを持つアプリケーションを、データとビジネスロジックを担う「モデル」、画面表示を担う「ビュー」、入力を受け取り両者を仲立ちする「コントローラ」の3役に分けるアーキテクチャパターンです。個々のクラス設計の定石であるデザインパターンより一段大きな、アプリ全体の骨格を決めるパターンとして位置づけられます。

Ruby on Rails、Laravel、Spring MVC、Django(呼び名は MTV ですが同系)など、Webフレームワークの多くがこの構造を採用しているため、Web開発を学ぶとほぼ最初に出会う語彙です。「ロジックはモデルに、表示はビューに、その橋渡しはコントローラに」という役割分担の感覚は、フレームワークが変わっても通用する基礎体力になります。

なぜ生まれたか

MVC の起源は Web よりずっと古く、1979年頃、Trygve Reenskaug がパロアルト研究所で Smalltalk の GUI 研究のために考案したものです。当時、画面を持つプログラムでは、データの計算・画面の描画・マウスやキーボードの処理が1つのコードに混然と絡み合うのが普通でした。すると「同じデータを表とグラフの2画面で見せたい」だけで描画コードを二重に持つことになり、画面の見た目を変えるだけで計算ロジックまで壊れる、という事態が頻発します。

Reenskaug の洞察は、「ユーザーの頭の中にある対象(モデル)」と「その見え方(ビュー)」は別物であり、コード上でも分離すべきだ、というものでした。モデルは自分がどう表示されるかを知らず、ビューはモデルの変化を通知で受け取って画面を更新する。この分離により、1つのモデルに複数のビューをぶら下げることも、見た目だけを差し替えることも自由になりました。関心の分離によって変更の影響範囲を閉じ込める — MVC はこの原則を UI に適用した最初期の成功例です。

詳細

3つの役割と情報の流れ

モデルは、アプリが扱う対象そのもの — データと、それにまつわるルールや計算 — を表現します。ビューは、モデルの内容をユーザーに見える形へレンダリングします。コントローラは、クリックやフォーム送信といった入力を解釈し、モデルの操作に翻訳します。重要なのは依存の向きです。モデルはビューもコントローラも知りません。だからこそモデルは UI 抜きで単体テストでき、画面の都合と切り離して育てられます。

ユーザー入力と閲覧コントローラ入力を解釈し指示するモデルデータとルールの本体ビューモデルを画面に描く操作更新変更を通知表示依存はコントローラとビューからモデルへの一方向。モデルは表示の都合を知らない
MVCの3役と依存の向き — モデルはビューもコントローラも知らない

オリジナルの Smalltalk MVC では、モデルの変更はデザインパターンでいう Observer の仕組みでビューに通知されていました。「状態が変わったら見た目が追従する」というこの考え方は、後述するフロントエンドのリアクティビティまで一直線につながる系譜です。

Webでの変形 — MVC2

1990年代後半、この構造は Web に輸入されますが、そのまま移植はできませんでした。HTTP はリクエストとレスポンスの一往復で完結し、サーバからブラウザへ「モデルが変わったよ」と通知し続ける常時接続がないためです。そこで生まれたのが、リクエストごとに「コントローラが入力を処理し、モデルを操作し、結果を渡してビュー(テンプレート)がHTMLを生成して返す」という一方通行の変形で、Java 界隈で MVC2 と呼ばれた形が Rails 以降のWebフレームワークの標準形になりました。ルーティングで URL をコントローラに割り当て、モデルは ORM 経由でデータベースと対話し、ビューがページを組み立てる — 現在SSRと呼ばれる構成の古典的な姿です。

MVVMとフロントエンドフレームワーク

デスクトップやモバイルの世界では、ビューとモデルの間の「画面のための状態と変換ロジック」(入力途中の値、表示用フォーマット、ボタンの活性状態など)が肥大化する問題に応えて、MVP や MVVM といった派生が生まれました。MVVM(Model-View-ViewModel)は Microsoft の WPF で確立したパターンで、ViewModel が画面用の状態を持ち、ビューとはデータバインディング — 双方の変更が自動で同期される仕組み — で結ばれます。コントローラのような手続き的な橋渡しコードが消えるのが利点です。

SPA の隆盛とともに、この系譜はフロントエンドに主戦場を移しました。初期の Angular や Vue はまさに MVVM 的な双方向バインディングを掲げ、React は「UI は状態の関数である」と一歩進めて、仮想DOMによりDOM更新を自動化することでビュー層の手動同期を丸ごと消し去りました。一方でモデルに相当する部分は Redux などの状態管理ライブラリが担い、サーバ側は画面を返す代わりに REST APIGraphQL でモデルのデータだけを提供する分業が定着しています。名前は MVC でなくとも、「状態と表示を分け、依存を一方向に保つ」という設計原理は形を変えて生き続けているわけです。

実務での落とし穴

MVC 採用時の定番の失敗は、責務の置き場所の崩壊です。コントローラに業務ロジックが溜まり続ける「ファットコントローラ」、逆にモデルへ何でも押し込んで神クラス化する「ファットモデル」はどちらも頻出します。目安は「その処理は画面や HTTP が存在しなくても意味を持つか」で、持つならモデル側、持たないならコントローラかビューの領分です。また MVC の3分割はあくまで UI 周りの整理であり、複雑な業務領域そのものの整理にはドメイン駆動設計のような別レイヤの語彙が必要になります。MVC を「アプリ全構造の答え」ではなく「表示と入力をロジックから隔離する境界線」と捉えると、ちょうどよい距離感で使えます。