【初心者向け】あれもこれもコントローラー任せ?MVCのコントローラーとサービスレイヤーでスッキリ整理術!

こんにちは!プログラミング学習、楽しんでいますか?

先日、職場の後輩と「MVCのコントローラーって、どこまで仕事させるのがいいんですかね?」なんて話になりました。確かに、Webアプリケーション開発でよく聞くMVCパターンですが、コントローラーの役割って意外と悩ましいポイントですよね。

特にプログラミングを始めたばかりの頃は、「とりあえず動けばOK!」とコントローラーに色々な処理を詰め込んでしまいがち。でも、それだと後でコードが複雑になって、読みにくくなったり、修正が大変になったりすることも…。

そこで今回は、後輩との会話をきっかけに、MVCの「コントローラー」の役割と、コードをスッキリ整理するための「サービスレイヤー」という考え方について、初心者の方にも分かりやすく解説してみたいと思います!

MVCのコントローラーって、どんな仕事をしてるの?

まず、MVCパターンについて簡単におさらいしましょう。

  • M (Model): アプリケーションのデータやビジネスロジック(中心的な処理)を担当。
  • V (View): ユーザーに見える部分(画面表示)を担当。
  • C (Controller): ユーザーからのリクエストを受け取り、ModelとViewの橋渡しをする「司令塔」。

今回の主役であるコントローラーは、例えるならレストランのウェイターさんのような存在です。

  1. お客さん(ユーザー)から注文(リクエスト)を受け取ります。
  2. 厨房(モデル)に注文内容を伝えます。
  3. 厨房で作られた料理(処理結果)をお客さんの元へ運び、提供(レスポンス)します。

具体的にコントローラーが担当する主な仕事はこんな感じです。

  • リクエストの受付と解釈: ユーザーが「このページが見たい!」「このデータを登録したい!」といったリクエストを送ってきたら、まずコントローラーがそれを受け取ります。そして、そのリクエストが何をしたいのかを理解します。
  • バリデーション (入力チェック): ユーザーが入力したデータが正しい形式か(例えば、メールアドレスの形になっているか、必須項目が入力されているかなど)をチェックします。不備があれば「ここが間違っていますよ」と伝えます。
  • 認証・認可: 「この操作をする権限がある人かな?」といった確認をします。例えば、ログインしているユーザーだけが見られるページだったり、管理者だけが使える機能だったりする場合ですね。
  • ビジネスロジックの呼び出し: 実際のデータ処理や計算といった「メインの仕事」は、多くの場合、モデルや後述する「サービスレイヤー」にお願いします。コントローラーは「この仕事をお願いします!」と指示を出す役割です。
  • レスポンスの準備と返却: モデルやサービスから処理結果を受け取ったら、それをユーザーに見せる形(HTMLのページだったり、JSONデータだったり)に整えて、「はい、どうぞ!」と返します。

コントローラーが「何でも屋さん」になると…?

コントローラーは色々な役割を担っていますが、ここで注意したいのが「何でもコントローラーに書いちゃう」ことです。

例えば、ユーザー登録処理を考えてみましょう。 コントローラーで、

  1. 入力されたユーザー名やパスワードを受け取る
  2. 入力内容が正しいかチェックする (バリデーション)
  3. パスワードを暗号化する
  4. ユーザー名が既に使われていないかデータベースで確認する
  5. 問題なければデータベースに新しいユーザー情報を保存する
  6. 「登録完了しました!」というメッセージを画面に表示する

…といった処理を全部コントローラーに書いてしまうと、コントローラーのコードがどんどん長くなってしまいます。これが「太ったコントローラー (Fat Controller)」と呼ばれる状態で、以下のような問題が起こりやすくなります。

  • コードが読みにくい: どこで何をしているのか把握しづらくなります。
  • テストがしにくい: 一つの機能が色々な処理と密接に絡み合っていると、部分的なテストが難しくなります。
  • 同じような処理が色々な場所に…: 例えば、「パスワードの暗号化」処理が、ユーザー登録コントローラーにも、パスワード変更コントローラーにも書かれてしまう、といったことが起こりがちです(DRY原則: Don’t Repeat Yourself に反します)。
  • 変更の影響範囲が大きい: ちょっとした修正が、思わぬところに影響してしまう可能性があります。

そこで登場!「サービスレイヤー」で仕事を分担しよう!

コントローラーが「何でも屋さん」になってしまうのを防ぐために役立つのが、サービスレイヤー (Service Layer) という考え方です。先ほどのMVCに「S」を加えた「MVC+S」なんて呼ばれたりもします。

サービスレイヤーは、コントローラーとモデルの間に位置して、ビジネスロジック(アプリケーションの核となる処理)を専門に担当する層です。

先ほどのレストランの例えで言うと、コントローラーがウェイターさんなら、サービスレイヤーはシェフのようなイメージです。

  • ウェイターさん(コントローラー)は、お客さんからの注文を受け付け、シェフに伝えます。
  • シェフ(サービスレイヤー)は、その注文内容に基づいて、食材(モデルのデータ)を調理し、料理を完成させます。
  • ウェイターさん(コントローラー)は、シェフが作った料理をお客さんに届けます。

サービスレイヤーを導入するメリット

  1. コントローラーがスリムになる!: コントローラーは、リクエストの受付、入力チェック、サービスレイヤーへの処理依頼、レスポンスの準備といった「交通整理」の役割に集中できます。複雑なビジネスロジックはサービスレイヤーにお任せするので、コントローラーのコードがスッキリします。
  2. ビジネスロジックを再利用しやすくなる!: 例えば、「ユーザー情報を取得する」という処理をサービスレイヤーに書いておけば、Web画面用のコントローラーからも、スマホアプリ用のAPIコントローラーからも、同じサービスを呼び出して利用できます。バッチ処理など、画面を介さない処理からも呼び出せるので便利です。
  3. テストがしやすくなる!: ビジネスロジックがサービスレイヤーにまとまっているので、その部分だけを独立してテストしやすくなります。「この入力に対して、期待通りの処理結果が返ってくるか」といったテストがシンプルに書けます。
  4. 関心の分離が明確になる: 「どこに何を書くべきか」がよりハッキリするので、チーム開発もしやすくなります。

具体的にどう分担するの?

先ほどのユーザー登録処理を、サービスレイヤーを使って分担してみましょう。

コントローラーの役割:

  1. 入力されたユーザー名やパスワードを受け取る。
  2. 入力内容が正しいかチェックする (バリデーション)。
  3. ユーザー登録サービスに「この情報でユーザー登録をお願いします!」と依頼する。
  4. ユーザー登録サービスから結果を受け取り、「登録完了しました!」というメッセージを画面に表示する。

ユーザー登録サービスの役割:

  1. コントローラーから受け取ったユーザー情報をもとに、
    • パスワードを暗号化する。
    • ユーザー名が既に使われていないかデータベースで確認する (モデルを利用)。
    • 問題なければデータベースに新しいユーザー情報を保存する (モデルを利用)。
  2. 処理結果(成功したか、失敗したかなど)をコントローラーに返す。

このように、コントローラーはあくまで「窓口」と「指示出し」に徹し、実際の複雑な処理はサービスレイヤーが担当することで、それぞれの役割が明確になります。

まとめ:コントローラーとサービスを上手に使って、分かりやすいコードを目指そう!

今回は、MVCのコントローラーの役割と、サービスレイヤーを導入するメリットについてお話ししました。

  • コントローラーは、ユーザーからのリクエストとアプリケーションの処理をつなぐ司令塔
  • でも、何でもかんでもコントローラーに詰め込むと、コードが複雑になって大変!
  • そこでサービスレイヤーを導入して、ビジネスロジック(中心的な処理)を専門家にお任せする。
  • そうすることで、コントローラーはスリムになり、コードの見通しが良くなり、再利用性テストのしやすさもアップ!

プログラミングを始めたばかりの頃は、色々な概念が出てきて大変かもしれませんが、一つ一つ理解していくと、より良いコードが書けるようになっていきます。

今回の話が、皆さんの「コントローラー、どうしよう?」という悩みを少しでもスッキリさせるお手伝いができれば嬉しいです。ぜひ、実際のコードでサービスレイヤーの導入を試してみてくださいね!

現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法

動かして学ぶ! Laravel開発入門