ビジネスロジックについて
ビジネスロジック
ビジネスチーム(仕様チーム)が知っているべき仕様(ロジック)の事
ビジネスチームだけでは決まらない事(UIのデザイン、データの扱い、Prefixの番号など)はビジネスロジックに含めない
ユースケース
ビジネスロジックを使う(ユース)ケースごとに分割したもの
ユースケースの集合体がビジネスロジックになる
「システムのコアの部分」とか「システムの目的になる処理をするところ」といった説明も正しいとは思います。
しかし、誤解を恐れずに簡単に言うと、
アプリケーションをプレゼンテーション・ビジネスロジック・データアクセスの 3 つに分けたとき、「プレゼンテーションでもデータアクセスでもない部分がビジネスロジック」
と考えるととっかかりやすいです。
裏を返せば、プレゼンテーションとデータアクセスが実行プラットフォームと不可分であればレイヤーを分ける必要がないということになる
後述しますが、ビジネスロジックには「じゃんけんの勝敗判定」のような「コアなルール系」と、「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出す、一連の流れ」のような「処理の流れ系」の 2 つがあります。
前者がDomainで、後者がUsecaseやServiceという印象
「後述しますが」の部分
エンタープライズビジネスルール
アプリケーションビジネスルール
例えば、日付時刻形式変換アプリを実装する場合、日付時刻形式の変換がシステムのコアとなるロジックであり、変換ロジックが Web アプリだろうと CLI アプリだろうと同じだと考えられるため、変換処理はビジネスロジックに実装します。
このように、同じロジックであっても、アプリケーションによってそれがビジネスロジックか異なる場合もあります。
ビジネスロジック
アプリケーション
ドメイン
データアクセス
プレゼンテーション
Controller
View
トランザクションスクリプトとドメインモデル
トランザクションスクリプト
Serviceなり、なんとかLogicというクラスが、ドメインロジックとユースケースを担当します。この実装方式は、メリットとして学習コストが低いというか、プログラミングを勉強し始めて、別のやり方を教わらずに「コードを書け」と言われたら、この方式を書く人がほとんどだと思います。そういう意味で学習コストが低いです。
一方で、この実装方式をすると、Serviceクラスにいろいろなロジック、いろいろな分岐や処理が書かれるので、肥大化しやすいです。同じLogicがServiceクラス間に分散しやすく、変更に弱いという特徴もあります。
ドメインモデル
一方で、ドメインモデルパターンは、データの入れ物に処理も持たせる方式です。言ってしまえばオブジェクト指向プログラミング的ですね。オブジェクト指向プログラミングといっても指す意味が人によってけっこう違いますが、ここでは「データの入れ物に処理、メソッドを持たせるようなもの」をオブジェクト指向プログラミングと言っています。
そういうやり方で、Modelはドメインロジックを担当して、Serviceはユースケースを担当します。
こういう構成にすると、メリットとしてはServiceクラスが肥大化しにくく、同じロジックが分散しにくくて変更に強くなりやすいです。そしてトランザクションスクリプトの裏返しですが、デメリットとしては学習コストが高いこと。オブジェクト指向的なコードの書き方みたいなものが、ある程度わかっていないと書けないところですね。
フレームワークによっては、ビジネスロジック層とデータアクセス層を分離しないメリットが大きいという話
ActiveRecordやEloquentでRepositoryを内部的に実装して、ServiceはRepositoryを使います。プラス、このActiveRecordのデータの入れ物とは別にドメインモデル、データの入れ物かつドメインロジックを持つActiveRecordが関係ないドメインロジックのためのモデルを作って、こちらを使うような構成もできます。ただ、これは個人的にあまりおすすめしないです。
なぜかというと、アクティブレコードは、特にRails、LaravelのようなMVCとアクティブレコード系O/Rマッパーの場合であれば、アクティブレコードパターンというやり方をすることで実装量がすごく減って、早く開発できるのが魅力です。
代わりに、Modelの役割がわりと多いので、そこがネックになることはあり得ますが、そのデメリットを取ってでも、高速に少ないコードで実装できるという特性を取りたいからActiveRecordを使うというような発想でいるのが、私はいいんじゃないかなと思っています。
責務を分ける意義について
この構成はServiceの役割が多すぎます。そして、複数サービスで似たドメインロジックを実装したい時に、コードが重複しやすいです。似たというか、まったく同じドメインロジックを実装したい時に、重複すべきではないドメインロジックがサービス間で重複しやすい構成だったりします。
Controllerが巨大であるために、DRY原則を守りづらいコードになっている例
そこでドメインロジックをModelに持たせると、Serviceの見通しが良くなりやすいです。Serviceがユースケースもドメインロジックも持っていると、Serviceのメソッドが100行とかにもぜんぜんなるし、普通に30行、50行とかになって見通しが悪くなっていきます。
結局はドメインロジックの設計次第なところもありますが、ドメインロジックをドメインモデルにしっかり持たせて、そこをしっかり整理していけば、ある程度コードも見通しが良くなっていくかなと思います。
依存ライブラリの入れ替えがしやすくなる、というのはあくまで一側面であって、コードの見通しを良くして変更しやすくするのが本来の意義
とはいえ、将来的な載せ替えが十分想定できるソフトウェアの場合は、載せ替えがしやすい設計を目指すべき