「ビジネスロジック」とは何か、どう実装するのか

アプリケーション開発で、「ビジネスロジックは分離しろ」だとか「Controller にビジネスロジックを書くな」といったことをよく言われると思います。

しかし、ビジネスロジックという言葉の意味を聞いたり調べたりしてみても、「システムのコアの部分」とか「システムの目的になる処理をするところ」みたいなことを言われたりして、よく分かりませんでした。

そんな中、クリーンアーキテクチャや DDD の戦術的設計について学ぶことで、**「ビジネスロジックとは何か」、「ビジネスロジックはどう実装するか」について、自分なりの考えが整理されてきたので、この記事ではそれをまとめます**。

※ 曖昧な言葉を自分としてどう使っているかという話になります。違う意味で使う方もいると思うので、ご注意ください

# ビジネスロジックとは何か

「システムのコアの部分」とか「システムの目的になる処理をするところ」といった説明も正しいとは思います。

しかし、誤解を恐れずに簡単に言うと、

**アプリケーションをプレゼンテーション・ビジネスロジック・データアクセスの 3 つに分けたとき、「プレゼンテーションでもデータアクセスでもない部分がビジネスロジック」**

と考えるととっかかりやすいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216010/b2b1c867-4209-90a8-74d8-e73eec341035.png)

では、何がプレゼンテーションに該当し、何がデータアクセスに該当し、結局何がビジネスロジックなのでしょうか ?

## データアクセス

まずは分かりやすそうなデータアクセスについてです。

データアクセス層の役割は、ファイルや DB に対してデータを読み書きすることです。

**ビジネスロジックをデータアクセスと切り離すというのは、保存先がファイルだろうと、RDB だろうと、ドキュメント DB だろうと、ビジネスロジックはそれを気にかけないように記述するということ**です。

**データアクセス層は、保存先の媒体によらず同じインタフェースをビジネスロジック層に対して提供して、保存先が変わってもデータアクセス層だけ直せばいいというのが理想的**です。

## プレゼンテーション

プレゼンテーション層とは、そのアプリケーションとユーザ (またはクライアントプログラムなど) とのやりとりを担当する層です。

具体的には、以下のようなものがプレゼンテーション層に属します。

* 古典的な MVC フレームワーク[^1]の場合 ... View や Controller
* API の場合 ... API を受け付ける Controller・リクエストやレスポンスの型
* CLI アプリケーションの場合 ... コマンドラインオプションの解析・ユーザからの入力受付・処理結果の出力

[^1]: Thymeleaf や ERB などのテンプレートエンジンを使い、サーバサイドで HTML をレンダリングする方式のフレームワークを指しています

例えば、**古典的な MVC フレームワークによる Web アプリと同様の処理を API や CLI アプリケーションとして提供するとき、プレゼンテーション層以外が使い回せるような構造になっていると理想的**です。
**その使い回すべき部分のうち、データアクセスではない部分がビジネスロジック**です。

## ビジネスロジック

では、どこまでがプレゼンテーションで、どこからがビジネスロジックなのでしょうか ?
例えば、「コンピュータとじゃんけんをして、その結果をどこかに保存する」というアプリケーションを考えてみます。

「じゃんけんの勝敗判定」は、それが API だろうと CLI アプリケーションだろうと同じです。
なので、**「じゃんけんの勝敗判定」はプレゼンテーションではありません**。

「コンピュータとじゃんけんをして、その結果をどこかに保存するという処理を呼び出すという流れ」も、それが API であろうと CLI アプリケーションであろうと関係ありません。
なので、**「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出す、一連の流れ」も、プレゼンテーションではありません**。

**「じゃんけんの勝敗判定」と「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出すという流れ」は、どちらもビジネスロジックに該当**します。

後述しますが、**ビジネスロジックには「じゃんけんの勝敗判定」のような「コアなルール系」と、「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出す、一連の流れ」のような「処理の流れ系」の 2 つがあります**。

## これはビジネスロジック ???

さて、ビジネスロジックとは何かについて自分なりの意見を書いたところで、これはビジネスロジックか ? という自分なりの判断基準を書いていきます。

### 日付時刻のフォーマット変換

DB に保存された日付時刻を UI に表示する際、フォーマットを変換することが多いでしょう。

私の場合、**日付時刻の形式変換は、ユーザインタフェースのためだけのロジックであるため、プレゼンテーション層に記述**します。

これはよくある例だと思いますし、賛同してくれる方も多いのではないでしょうか。

ただし、例外もあります。
例えば、**日付時刻形式変換アプリを実装する場合、日付時刻形式の変換がシステムのコアとなるロジックであり、変換ロジックが Web アプリだろうと CLI アプリだろうと同じだと考えられるため、変換処理はビジネスロジックに実装します**。

このように、**同じロジックであっても、アプリケーションによってそれがビジネスロジックか異なる場合もあります**。

### バリデーション

データのバリデーションについては、プレゼンテーションかビジネスロジックか意見が分かれやすいと思います。

* リクエストのフォーマットチェック
* フォーマットより少しだけ複雑な条件チェック
* DB のデータとの整合性チェック

の 3 つに分けて、私なりの考えを書いていきます。

#### リクエストのフォーマットチェック

リクエスト (CLI であればコマンドライン引数や標準入力) をプレゼンテーション層で受け取った際、まずバリデーションしろと教わった方も多いのではないでしょうか。

例えば

* リクエストの必須パラメータが足りているか
* 文字列のサイズが 1000 以下であるか

といったチェックをすると思います。

私はこのような**リクエストのデータの形式チェックは、プレゼンテーション層で実施**します。

理由は、以下の 3 つです。

* ユーザとのインタフェースでの約束事に対するチェックと考えていること
* 不正な形式のデータであることは即座に検知して、以後のプログラムに進ませないようにしたいこと
* DB とのやりとりが不要なため、簡単に記述できること

#### フォーマットより少しだけ複雑な条件チェック

もう少しだけ複雑なチェックとしては、

* Qiita のようなサイトで、「イイね」は自分にはできないようにする
* TODO 管理アプリで、過去日の TODO は登録できないようにする

といったものがあると思います。

これは非常に悩ましいところですが、私は**フォーマットより少しでも複雑なチェックは基本的にビジネスロジック層で実施**します。

理由は以下の 2 つです。

* プレゼンテーション層は見た目などの UI に直接関わることだけを知っているべきであること
* ユーザインタフェースが GUI か API か CLI かなどによらず共通したチェックであると想定されること

このチェックがプレゼンテーションかビジネスロジックかは、かなり意見が分かれるところだと思います。
上記の意見はあくまで「基本的に」であり、自分も状況によってはプレゼンテーション層に書くこともあります。
何がビジネスロジックかを突き詰めるよりも、チームとして合意を取ったり、一貫性を取ったりすることの方が大事だと思うので、これ以上深入りしないことにします。

#### DB のデータとの整合性チェック

最後に、DB のデータとの整合性チェックについてです。

例えば

* EC サイトで購入リクエストした商品が購入可能なものである

といったチェックがあると思います。

私はこういったチェックは必ずビジネスロジック層に記述します。

理由は以下の通りです。

* UI に起因したチェックではないため、プレゼンテーション層の役割ではないこと
* DB とのやりとりが発生すること

もっと言えば、このような**データの整合性チェックこそがビジネスロジックの代表**なので、それはビジネスロジック層に書くべきだと考えています。

# ビジネスロジックはどう実装するのか

ここまで、ビジネスロジックとは何かについての自分の考えを説明してきました。
ここからはビジネスロジックの実装について書いていきます。

## トランザクションスクリプトとドメインモデル

ビジネスロジックの方法には、大きく以下の 2 つがあります。

* トランザクションスクリプトパターン
* ドメインモデルパターン

### トランザクションスクリプトパターン

**トランザクションスクリプトパターンでは、「Service」クラスに処理を記述し、「DTO」をデータの入れ物としてやりとりします**。
**DTO はデータと getter、setter だけ持ち、処理は Service に記述します**。
いわゆる手続き型プログラミングの考え方でビジネスロジックを実装する方式です。

主なメリットとしては、ドメインモデルパターンよりも学習コストが低いことや、初期実装コストが低いことが挙げられます。
一方デメリットとしては、サービスをまたがった処理の共通化がしにくいことや、サービスが Fat になりがちなことが挙げられます。

### ドメインモデルパターン

**ドメインモデルパターンでは、トランザクションスクリプトパターンではただの入れ物だった「DTO」に処理も持たせ、処理とデータを一緒に配置するオブジェクト指向的な実装をします**。
**この場合、処理とデータを入れるものを「ドメインモデル」と呼んだりします**。

主なメリットは、ロジックをより共通化しやすいことや、サービスが Fat になりにくいことが挙げられます。
デメリットとしては、トランザクションスクリプトパターンよりも学習コストや初期実装コストが高いことが挙げられます。

ビジネスロジックの実装方法は大きくこの 2 つになります。
作るアプリケーションの特徴やチームメンバのスキルなどを加味して、どちらのパターンで実装するかを決めることになると思います。

## ビジネスロジックは 2 種類ある

ここまでビジネスロジックについて説明してきましたが、実はビジネスロジックは 2 種類あります。

クリーンアーキテクチャの図に書かれた言葉を使わせてもらうと、

* エンタープライズビジネスルール
* アプリケーションビジネスルール

の 2 つです。

![clean-architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216010/bfa609ff-3a43-6ae6-ebe4-32dfeda05d75.png)

この記事の前半で

> ビジネスロジックには「じゃんけんの勝敗判定」のような「コアなルール系」と、「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出す、一連の流れ」のような「処理の流れ系」の 2 つがあります。

と書きましたが、前者が「エンタープライズビジネスルール」で、後者が「アプリケーションビジネスルール」に該当します。

### エンタープライズビジネスルール

**エンタープライズビジネスルールというのは、システム都合ではない、コアなルールのことです**。

例えば、じゃんけんの勝ち負け判定ロジックはシステムであっても現実であっても同じなので、「エンタープライズビジネスルール」に該当します。
業務システムであれば、システムの代わりに帳票などを使って業務を回す際にも登場するルールが「エンタープライズビジネスルール」です。

他にも、DB のデータとの整合性チェックとして挙げた

> * EC サイトで購入リクエストした商品が購入可能なものである

といったチェックのロジックも「エンタープライズビジネスルール」です。

### アプリケーションビジネスルール

**アプリケーションビジネスルールは、システムを成立させるためのロジックや、システムであることによって発生したロジック**です。
**「ユースケースの処理の流れを実現すること」や「トランザクション管理」などが該当**します。

例えば、「コンピュータとじゃんけんをして、その結果をどこかに保存する処理を呼び出す、一連の流れ」がそうです。

> * EC サイトで購入リクエストした商品が購入可能なものである

の例でいうと、

1. DB などから関係するデータを取り出す処理を呼び出す
2. エンタープライズビジネスルールを呼び出して整合性をチェックする
3. 整合性チェックに合格した場合、データを保存する処理を呼び出す (商品購入の確定など)

といった流れを実現するのがアプリケーションビジネスルールです。

## 「サービス」も 2 種類ある

ビジネスロジックが 2 種類あると書きましたが、**ドメインモデルパターンにおいては、「サービス」も 2 種類あります**。
アプリケーションサービスとドメインサービスです。

ドメインモデルパターンでは、**エンタープライズビジネスルールをドメインモデルに記述**し、**アプリケーションビジネスルールを「アプリケーションサービス」クラスや「ユースケース」クラスに記述**します。

「ドメインモデル」には Entity、Value Object など、DDD の戦術的設計で登場する様々な要素が含まれます。
**「ドメインサービス」というのも「ドメインモデル」の要素の 1 つで、Entity や Value Object に記述することがどうしても適切でないエンタープライズビジネスルールを記述するところ**になります。
**ドメインモデルパターンにおいては、ドメインサービスは最後の手段であり、可能な限り使用は控えるべきもの**です。

一方、**「アプリケーションサービス」というのは、処理の流れなど (= アプリケーションビジネスルール) を実現するためのもの**です。
**DDD の戦術的設計では「アプリケーションサービス」と呼ばれ、クリーンアーキテクチャでは「ユースケース」と呼ばれています**。

# おわりに

以上、ビジネスロジックとは何か、どう実装するのかを自分なりにまとめました。

DDD の戦術的設計やクリーンアーキテクチャでは、同じ言葉が複数の意味で使われていたり、同じ意味の複数の言葉があったりするので、最初は混乱するかもしれません。
どこが対応していてどこがどう分類されるかが分かると、一気に理解が進むと思います。

# 【2020/12/12 追記】

アドベントカレンダーでこの記事と関連する内容をコードとともに解説しています。
興味を持ってくださった方は [じゃんけんアドベントカレンダー](https://qiita.com/advent-calendar/2020/janken) を参照ください。

# 【2021/05/23 追記】

この記事の内容と関連するサンプルコードを以下の記事で解説しました。

- [Raspberry Pi で動かすコードをクリーンアーキテクチャ的な考え方で整理する](https://www.kanzennirikaisita.com/posts/raspberrypi-clean-architecture)

# 参考

書籍

* [エリック・エヴァンスのドメイン駆動設計](https://www.amazon.co.jp/dp/4798121967)
* [実践ドメイン駆動設計](https://www.amazon.co.jp/dp/479813161X)
* [．ＮＥＴのエンタープライズアプリケーションアーキテクチャ　第２版](https://www.amazon.co.jp/dp/4822298485)
* [「実践ドメイン駆動設計」から学ぶDDDの実装入門](https://www.amazon.co.jp/dp/4798161500)
* [Clean Architecture](https://www.amazon.co.jp/dp/4048930656)

Web

* [ビジネスロジック - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF)
* [ビジネスロジック (business logic)とは｜「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word13666.html)
* [ビジネスロジックとは - IT用語辞典 e-Words](http://e-words.jp/w/%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF.html#:~:text=%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AF%E3%81%A8%E3%81%AF%E3%80%81%E6%A5%AD%E5%8B%99,%E3%81%AA%E3%81%A9%E3%81%A8%E3%81%97%E3%81%A6%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E9%83%A8%E5%88%86%E3%80%82)

# 関連記事

以下、自分が書いた関連記事です。

* [MVC、3 層アーキテクチャから設計を学び始めるための基礎知識](https://qiita.com/os1ma/items/7a229585ebdd8b7d86c2)
* [自分が現状気に入っているアプリケーションのパッケージ構成をさらす](https://qiita.com/os1ma/items/286eeec028e30e27587d)
* [「集約」でデータアクセスの 3 つの課題に立ち向かう ~ 大量の Repository・整合性のないオブジェクトのロード・N + 1 問題 ~](https://qiita.com/os1ma/items/28f5d03d3b92e6a1e1d8)