
こんにちは!
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