こんにちは!
7月からインターン生として株式会社Hajimariに入社した、難波 慧人です。
現在は、TUKURÜS事業部で受託開発の業務を行っています! 今行っている案件では、サブスクリプション型動画配信サイトの、新規機能開発・運用保守を担当しています!
開発言語に関しては、 バックエンドはPHP(laravelフレームワーク)を用いており、アーキテクチャはADR(Action Domain Responder)を採用しています。
案件にジョインした当初、MVCアーキテクチャしか知らない私でしたが、ADRの有用性が少しずつ理解できてきました!
そこで今回は、MVCアーキテクチャと、ADRアーキテクチャの違いについてご紹介したいと思います!!
また、各項目にサンプルコード(ユーザーの一覧、詳細機能)を示していきます!!
■MVC(Model View Controller)とは??
引用元(
https://white-t007.com/tech/it%E5%9F%BA%E7%A4%8E/mvc/
)
ユーザーインターフェイスを持つアプリケーションを、モデル(Model)、ビュー(View)、コントローラー(Controller)の3つの責務に分割して、実装していく手法です。
モデル(Model)
モデルとは、アプリケーションの中で、ビジネスロジック、データベースとのアクセスを担っています。例えば、計算、データ取得、データ管理などが挙げられます。
Laravelフレームワークでは、Eloquent ORMと呼ばれる、モデルとデータベースの紐付けを行う機能があります。
Eloquent ORMにより、アプリケーションとデータベース間のデータのやりとりをより円滑にすることができます!!
readouble.com
- サンプルコード
Models/User.php class User extends Model { /** * usersテーブルから全てのユーザーを取得 * * @return Collection */ public function fetchAllUsers(): Collection { return User::all(); } /** * usersテーブルから指定ユーザーを取得 * * @return ?User */ public function fetchUser($userId): ?User { return User::where('id', $userId)->first(); } }
ビュー(View)
ビューとは、webサイト上のレイアウトを作成する役割を持っています。主にHTMLで記述されます。また、ビューから生成されたレイアウトはアプリケーションとユーザーのインターフェイスになっています。
ユーザーはこのweb上のレイアウトを通して、アプリケーションにリクエストを送信、アプリケーションからのレスポンスを閲覧することができます。
コントローラー(Controller)
コントローラーとは、ユーザーからのリクエストに応じて、モデルとビューの制御を担う部分です。 実際のユーザーインターフェイスはこのコントローラーになります。アプリケーションとユーザー間のやり取りは全てここを経由します。
ユーザーがwebサイト上で商品一覧をみたい時を例にします。 ユーザーから「商品一覧がみたい」というリクエストが来たら、モデルに商品データを取得するように依頼します。次に取得データをビューに渡し、ビューが作成したレイアウトを、webサイト上に表示しています。これによって、ユーザーがweb上で、商品一覧を閲覧することができます。
- サンプルコード
Controllers/UserController.php class UserController extends Controller { /** * ユーザー一覧 * * @return \Illuminate\View\View */ public function index(): View { // Userクラス(モデル)のインスタンス作成 $userModel = new User(); // Userクラス(モデル)のメソッドを使って、ユーザーを取得 $users = $userModel->fetchAllUsers(); return view('users.index', ['users' => $users]); } /** * ユーザー詳細 * * @param int $userId * * @return \Illuminate\View\View */ public function show(int $userId): View { // Userクラス(モデル)のインスタンス作成 $userModel = new User(); // Userクラス(モデル)のメソッドを使って、ユーザーを取得 $user = $userModel->fetchUser($userId); // 対象ユーザーが存在しなかったら、404ページを返す if(is_null($user)) { abort(404); } else { return view('users.show', ['user' => $user]); } } }
MVCの問題点
コントローラーの肥大化
コントローラーは基本的に、ユーザーインターフェイスとしてアプリケーションの入出力のみを担う責務ですが、コントローラーにビジネスロジックやデーターベースのやり取りを記述される場合があります。モデルの肥大化
モデルとは、ビジネスロジック・データベースアクセスを書く場所である。しかし、アプリケーションの規模が大きくなると、ビジネスロジック・データベースアクセスも必然的に増えていき、結果モデルは肥大化していきます。。。
ADRの導入
以上の問題点を踏まえ、MVCの改良版でもあるADR(Action Domain Responder)を導入しています!!
■ADR(Action Domain Responder)とは??
上記のMVCモデルの改良版として、Paul M. Jonesによって提案されたソフトウェアアーキテクチャパターンです。
引用元:( https://en.wikipedia.org/wiki/Action%E2%80%93domain%E2%80%93responder )
ADRでは、アクション(Action)、ドメイン(Domain)、レスポンダー(Responder)の3つの責務に分割して、実装していく手法です!
アクション(Action)
ユーザーからのHTTPリクエストを受け取り、ドメインの処理結果をレスポンダーに渡す役割です。MVCでいうコントローラー的な位置付けです。
全てのHTTPリクエストはここで処理されます。
HTTPリクエストとは
- サンプルコード
Actions/User/UserIndexAction.php class UserIndexAction extends Controller { /** * Instance of the Responder property. * * @var UserRepository * @var UserIndexResponder */ protected $userRepository; protected $userIndexResponder; /** * Instantiate the class. * * @param UserRepository $userRepository * @param UserIndexResponder $userIndexResponder */ public function __construct( UserRepository $userRepository, UserIndexResponder $userIndexResponder ) { $this->userRepository = $userRepository; $this->responder = $userIndexResponder; } /** * Invoke our action, handle domain, respond. * * * @return View */ public function __invoke(): View { $users = $this->userRepository->fetchAllUsers(); return $this->responder->response($users); } }
Actions/User/UserShowAction.php class UserShowAction extends Controller { /** * Instance of the Responder property. * * @var UserRepository * @var UserShowResponder */ protected $userRepository; protected $userShowResponder; /** * Instantiate the class. * * @param UserRepository $userRepository * @param UserShowResponder $userShowResponder */ public function __construct( UserRepository $userRepository, UserShowResponder $userShowResponder ) { $this->userRepository = $userRepository; $this->responder = $userShowResponder; } /** * Invoke our action, handle domain, respond. * * @param Request $request * * @return View */ public function __invoke(Request $request): View { $user = $this->userRepository->fetchUser($request->user_id); return $this->responder->response($user); } }
ドメイン(Domain)
アクションから受け取った依頼をもとに、ビジネスロジック、データベースアクセスを担当する役割です。MVCでいうモデル的な位置付けです。
ビジネスロジックとは
今回は、Domainをさらにサービス(Service)、リポジトリ(Repository)、モデル(Model)に分けています。
サービス(Service)
主にアプリケーションビジネスルールを記述する。
(アプリケーションビジネスルール = システムであるがゆえに発生するビジネスルール)
例)データに対する複合処理、データ加工などリポジトリ(Repository)
データベースとのインターフェイスとして使用。
例)データベースアクセスのみ(加工はサービスの責務)モデル(Model)
主にエンタープライズビジネスルールを記述する。
(エンタープライズビジネスルール = アプリケーション都合でないビジネスルール)
例)野球 勝敗:点数が多い方が勝ち 時間:9回で終了 試合人数:各チーム9人ずつ
Domain/User/UserRepository.php class UserRepository { /** * usersテーブルから全てのユーザーを取得 * * @return Collection */ public function fetchAllUsers(): Collection { return User::all(); } /** * usersテーブルから指定ユーザーを取得 * * @param int $userId * * @return ?User */ public function fetchUser($userId): ?User { return User::where('id', $userId)->first(); } }
レスポンダー(Responder)
ドメインの処理結果を受け取り、HTTPレスポンスを作成、処理を担当します。MVC モデルのビューとは異なり、httpステータスの変更、クッキー操作も行います。
- サンプルコード
Responders/User/UserIndexResponder.php class UserIndexResponder { protected $view; public function __construct(ViewFactory $view) { $this->view = $view; } /** * 単体動画の表示 * * @param Collection $users * * @return View */ public function response(Collection $users): View { return $this->view->make( 'users.index', compact('users') ); } }
Responders/User/UserShowResponder.php class UserShowResponder { protected $view; public function __construct(ViewFactory $view) { $this->view = $view; } /** * 単体動画の表示 * * @param ?User $user * * @return View */ public function response(User $user): View { if (is_null($user)) { return \App::abort(404); } else { return $this->view->make( 'users.index', compact('users') ); } } }
MVCからの改善点
コントローラーの肥大化
MVCのコントローラーでは、ユーザーインターフェイスとして、全てのリクエスト、レスポンスを処理していました。
しかし、ADRではリクエストをアクション、レスポンスをレスポンダーといったように、責務を分けることで改善されています。
また、ADRでは、1アクションに対し1クラスしか作成しません。これにより、1つのコントローラーにメソッドが集中することを避けれます!!モデルの肥大化
MVCのモデルでは、全てのビジネスロジックの責務を担当していましたが、サービス(Service)、リポジトリ(Repository)、モデル(Model)という責務に細分化することで、モデルの肥大化を防ぎます。保守性、可読性の向上
実際、コードリーディングを行う際に、処理の流れが明確なので追いやすいです。
また、データーベースアクセスが一目でわかる、追いたい処理を探す時にもファイル特定がしやすい(サービス層の処理ならDomain配下のserviceファイルを探せばいい)などの利点がありました!
■まとめ
最初は、「ADRってなんぞや??」と戸惑いましたが、
MVCをある程度理解していれば、ADRのキャッチアップもやりやすいと思います!
是非ともADR(Action Domain Responder)を導入してみてはいかがでしょうか?
Fatなコントローラー 、モデル内で、無限スクロールする開発生活から解放されるはずです。。。
株式会社Hajimariでは、Laravelをメイン言語として自社開発・受託開発を行なっており、
一緒に開発を行なっていただけるエンジニア募集しています!
長野拠点の立ち上げメンバーも大募集しています!
興味のある方は以下の記事をぜひご覧ください!
みなさまとお会いできるのを心からお待ちしております!
www.wantedly.com www.wantedly.com www.wantedly.com www.wantedly.com