🔰

参画した案件のアーキテクチャを調べた

2024/07/19に公開

エンジニア歴1年程、Laravelを主に使用しています。
新規参画した案件のアーキテクチャを学習もかねて解説していきます。
執筆者は浅浅エンジニアです。ご了承ください。

対象者

  • 初学者の方
  • 駆け出しエンジニアの方

はじめに

結論から話すと、Usecase、Services、Repositoriesなどを採用したクリーンアーキテクチャに近しい構成を採用していました。
ServicesやRepositoriesを解説する記事は公式含め多数ありましたが、
現場の環境にドンピシャで同じな記事はありませんでした。
自分が参考にした中で一番理解が深まったと感じた記事は以下です。

5年間 Laravel を使って辿り着いた,
全然頑張らない「なんちゃってクリーンアーキテクチャ」という落としどころ

上記の記事はとても勉強になったのですが、
まだまだLaravel歴の浅い自分には実環境で想定できない内容も多数ありました。
以降では、今の自分が学ぶべき内容を学習も兼ねて解説していきます。

大まかなディレクトリ構成は以下のような感じです。
(実際の自分の現場環境とは少し異なります)

app/
├─┬ Http/
│ ├─┬ Controllers/
│ │ ├── hoge1Controller.php
│ │ ├── hoge2Controller.php
│ │ └── Controller.php
├─┬ Models
│ ├── hoge1.php
│ └── hoge2.php
├─┬ Services
│ ├── hogehoge1Service.php
│ └── hogehoge2Service.php
├─┬ Repositories
│ ├── hoge1Repository.php
│ └── hoge2Repository.php
└─┬ UseCases/
  ├─┬ hoge1/
  │ ├── IndexAction.php
  │ ├── StoreAction.php
  └─┬ hoge2/
    ├── IndexAction.php
    └── StoreAction.php

Controller

Serviceなどを解説する前に、Controllerから先に触れる必要があります。

まず、”Controllerにはビジネスロジックを書きたくない”という考え方がメジャーであり、
”次の流れだけ書く”ような記述で内容は構成されています。
内容としては、以下の3点しかほとんどありません。

  • 例外処理
  • ログ出力
  • UseCaseへ参照(後述します)

自分の現場でも、基本的には同様の構成で書いておりました。

自分が感じたこととして、新規で参画した際にControllerを見る必要がほとんどありません。
前職の環境は個人個人の裁量でController盛り盛りになっているリポジトリもあったのしたのでこの構成のわかりやすさには驚きました。笑(統一されているって素晴らしい)

上記の内容は、単一責任の原則やスキニーコントローラーなどにあたり、
Laravelの公式のベストプラクティスにも載っております。
見たことがない方がいれば非常に有益なので見てみてください。
laravel-best-practices

UseCase

Controllerの処理の内容はここで記述します。(viewの表示もここで)

メソッドの名前は"execute"などで統一することで、全てのControllerで共通した記述をすることができます。(それぞれのContorllerで参照先のクラスを変えるだけ)

class IndexAction
{
    public function execute()
    {
        try {
            ~~~~~~~~
            処理を書く
            ~~~~~~~~
            //画面出力
            return view('/hoge1');

        } catch (LogicException $e) {
            
        }
    }
}

個人的に感じたこととして
ここに処理が集約されているのため、各画面の処理がUseCase配下を見ればわかる点が構成として非常にわかりやすいと感じました。

しかし、処理をこのクラスだけに記述するようにした場合、
当然ですがコード量がかなり多くなってしまいます。
また、メソッドを切り出した方がいい処理も出てくると思いますが、
(例えばファイルのダウンロード処理だったり)
前述で記した単一責任の原則などを考慮するとexecute以外のメソッドは極力増やしたくありません。

そこでServiceクラスの出番です。

Services

このクラスでは、独立した処理(ビジネスロジック)や繰り返し利用する処理などを記述します。
(前述の例でいくと、ファイルのダウンロード処理をこちらで記述します)

このクラスを取り入れることでUseCaseの内容がよりシンプルになり、
ロジックを切り出して書くことで、保守性が高まります。(バグがでた際に特定しやすい)

ここまで文字だけで説明してきましたが、流れにすると以下のような形です。

Controller(処理を渡すだけ)

UseCase(処理の流れ)

↓→→Service(ビジネスロジック)

viewへ

Repositories

さて、最後にRepositoryですが、
これはModel版のServiceクラスと認識していただいて大丈夫です。

ServiceやUseCaseからDB操作を行う処理を書く際、
Modelには記述せず、Repositoryに記述し参照させるようにします。
(前述の例に習えば、ダウンロードの対象データを取得する処理はこちらで書きます)

これを採用することで、処理の細分化、また重複しますが保守性が高まります。

まとめ

読んでいる間に自分も改めて感じましたが、フォルダが多くなってしまうことが一番に挙げられるかなと思います。
またどの処理をどのレベルで切り出すかなど、メンバー間でコーディング規約等などで認識を併せないといけないなどのハードルもあるかと思います。(自分は2,3人程度だったのでこのあたりは問題ありませんでした)
ですが、慣れてみるとこの構成が非常に扱いやすく感動しました。
アーキテクチャ系の本は自分にはまだ早いと思い手を付けていませんでしたが、これを機にさらに深く理解したいと感じました。

最後に

今回初めて記事を書いてみた率直な感想ですが、
題材が大きすぎたなと感じました。笑
掘り下げる箇所が多くありますが、掘り下げてしまうと1つの分量が多くなり、題材からずれてしまうのではないかなどを思っていましたが、逆に広く浅い記事になってしまったと感じています。
実際に記事を書いてみることで、このあたりの程感や難しさを感じました。
以降の経験に活かせるようこれも一つ学びとしたいと思います。

Discussion