MVCモデルにおけるサービスの役割について教えて下さい


サービスの役割について教えて下さい。

CakePHPでMVCを学んだのですが、CakePHPにはサービスというものがないのでどういう役割なのかがわかりません。

コントローラはユーザからの要求に対して必要な処理を抽出し、  
ビューは結果などを伝えるために表示するもの、  
モデルはコントローラから要求される処理をまとめておくものだと認識しています。  
(間違っていますでしょうか)

最近サービスという概念があることを知ったのですが、これはモデルの中に更に分けられるものなのでしょうか。それともモデルのことを言ってるのでしょうか?

わかりやすくサービスというものについて教えていただけると嬉しいです。




CakePHPという、1つのフレームワークの中での、1つのとらえ方については
他の方の回答が参考になると思いますが、一歩引いて一般的に`MVC`と`サービス`というのがどういう関係にあるのか、それぞれの言葉の意味という点で回答します。

質問ではMVCについて、次のように書かれています。

> コントローラはユーザからの要求に対して必要な処理を抽出し、  
>  ビューは結果などを伝えるために表示するもの、  
>  モデルはコントローラから要求される処理をまとめておくものだと認識しています。

この分類はそんなに間違っているということはありません。しかし、実際「コントローラから要求される処理」にはいろいろな種類のものがあります。たとえば、

  * DBに情報を保存する／DBから情報を取得する
  * メールを送信する
  * アップロードされた画像ファイルのサムネイルを作成する

があります。これらの何がモデルで、何がビジネスロジックで、何がサービスなのか、パッと分からないですよね。言葉を整理しましょう。

## モデルとは？

一般的に「モデル」というのは、`仕組みや構造を分かりやすく表したもの`を指します。業務のためのシステムであれば、その業務で扱っている「情報の構造」だったり、「情報の作り方のルール」「手順」だったりします。

### CakePHPのModelは？

CakePHPのModelの場合、データベースのスキーマを自動的に読み取って、そのテーブルのレコードを簡単に扱えるようになっているため、一見Modelの役割が「DB入出力のためのコード置き場」のように見えてしまいます。しかし、このようなActiveRecordの本来の目的は、アプリケーションコードから、`情報の形`
を統一した形式で扱えるようにする点にあります。

他のMVC系のフレームワークでも、Modelと名付けられている部分には、このように「情報の形」を表現するという目的が与えられています。この情報の形に付随する処理（情報の入出力や、形の整合性のチェック、形の多少の変形・合成）は、Modelに記述するということになるでしょう。

### ルールや手順は？

最初に挙げた例のうち、ルールや手順といったものもありました。これらはModel、つまり情報の形に付随するものなのでしょうか？

良くある例としては、例えば会員が商品を購入する時の手続き（手順）があります。会員ごとの購入限度額をチェックし、その後在庫をチェックする、といった具合です。何らかの手順の中で、複数の情報のカタマリを横断して扱わなくてはなりません。

「複数のものを扱う」という基準でModelに記述していたものを何らかの別の形に切り出す、という方策もありますが、より正しくは、「手順＝ユースケースを表わす部分を独立させる」ということになります。これが、次に説明するサービスの使い方の1つの形です。

## サービスとは？

サービスというのは、`処理をするモノ`のことです。

たとえば、アプリケーションでユーザーのパスワードをハッシュ化して記録する場合、そのハッシュ化処理を1つのクラスに独立させたとしましょう。このクラスは「PasswordEncoderサービス」です。要するに、ライブラリでも何でも、処理を提供するクラスはサービスだと言ってしまえます。また、このPasswordEncoderサービスは、ユーザーの情報を保存する時に、Modelの内部で利用されることもあれば、他の理由でControllerから使われることもあり得ます。

### サービスを利用する場面

サービスをどう使うのかという点では、先ほどのPasswordEncoderでもそうでしたが、いくつか考えられます

  * Controllerに記述していた共通処理を何かの観点でまとめるのに使う
  * Modelに記述していた共通処理を何らかの観点でまとめるのに使う
  * テンプレートのために必要な共通処理を何らかの観点でまとめるのに使う

Controllerの共通処理のためには、Controllerの基底クラスを作り、そこに共通メソッドを作るという方法もありますが、これはあまり良い方法ではありません。個々のControllerからコードが減る代わりに、基底クラス側に複雑性が集中してしまったりします。

「サービス」というものを直接扱えるフレームワークであれば、単に個々の処理に対応するクラスを作り、必要な箇所で利用できうようにフレームワークに指示する、という共通した手順で使えます（例えばSymfonyのサービスコンテナ）。CakePHPの場合は、使う箇所によってヘルパーだったり、と個別の仕組みが用意されていたりしますが、そういったものを超えて、自分で作ったクラスを使えるようにすれば、いろいろと対応の幅が広がります。

  * [CakePHPにDIコンテナを統合してサービスを扱いやすくした例](http://blog.yagni.jp/archives/419)

### サービスはModelなのか？

前節のように、MVCのパーツのどの部分の処理でも、それをサービスにまとめることは可能です。サービスというのは、単なる「処理を提供するもの」だからです。この意味で、サービスというのは、ModelだとかControllerだとか、そういった構造とは基本的に関係のないものということになります。

### サービスレイヤー（ユースケースレイヤー）

  * ControllerとModelの間に挟んで、Modelの操作をまとめる層のように使う

という使い方もあります。これは部品として使うというよりも、MVCというアーキテクチャ（作り方）に構造を追加するという目的になります。専門的な言葉では、サービスレイヤー、またはユースケースレイヤーと呼ばれます。こういった作り方で、プロダクションコードの見通しを良くすることができます。

## マイクロサービス？

昨今話題になる「マイクロサービス」という言葉で表されるサービスは、ここで説明した「1つのクラス」というのよりももっと大きな単位を指しています。例えば1つの企業の中の「会員管理サービス」などを1つのサービスというカタマリで捉えます。

「サービス」という言葉はとても汎用的で、この言葉を基準にして調べても膨大な事柄がでてきてしまいます。なので、`何のために使うのか`という目的から理解されていくのが、よいと思います。

# まとめ

  * サービスというのは単なる処理／クラス
  * MVCの「モデル」とサービスとは、直接的には関係がない
  * 「サービス」は用語として混乱しているので、目的から理解しよう

# 参考情報

  * [PofEAA's Wiki - ServiceLayer](http://capsctrl.que.jp/kdmsnr/wiki/PofEAA/?ServiceLayer)
  * [サービスコンテナ | Symfony2日本語ドキュメント](http://docs.symfony.gr.jp/symfony2/book/service_container.html)
  * [モデルもしくはサービスレイヤーに関する補足 - noopな日々](http://d.hatena.ne.jp/noopable/20100309/1268103347)

