Closed19

ControllerとServiceの責務と呼び出し

mikannmikann

RestAPIを実装中、controllerとserviceの使い分けと呼び出し方のベストプラクティスってあるのかなとふと思った

mikannmikann

現状の認識だと

  • controller
    • フロント(外部)とビジネスロジックを繋げる場所
    • serviceのメソッド呼び出しは1回で行うのが理想(何で?)
    • 複数serviceのメソッドを呼び出すのはよくない(何で?)
  • service
    • ビジネスロジックを記述
    • serviceからserviceを呼び出すのは通常よくない(何で?)

という感じ。そもそも正解なのかというのと人づてなので理由がわからない。

mikannmikann

こんなのあるのね
毎回思うんだけど、世の中のSNS系SaaSって各ユーザーが画像とが動画とかバンバン挙げてよくサーバーもつよな

mikannmikann

Controller側は1つのServiceを呼び、そこから他のServiceを呼ぶのか、

についての質問があった。
回答は

  • 要件による
  • トランザクション範囲からの視点

https://teratail.com/questions/199834

mikannmikann

terasolunaによれば

  • Serviceは、以下2つの役割を担う。
    • Controllerに対して業務ロジックを提供する。
      業務ロジックは、アプリケーションで使用する業務データの参照、更新、整合性チェックおよびビジネスルールに関わる各種処理で構成される。
      業務データの参照および更新処理をRepository(またはO/R Mapper)に委譲し、Serviceではビジネスルールに関わる処理の実装に専念することを推奨する。
    • トランザクション境界を宣言する。
      データの一貫性を保障する必要がある処理(主にデータの更新処理)を行う業務ロジックの場合、トランザクション境界を宣言する。
      データの参照処理の場合でも業務要件によっては、トランザクション管理が必要になる場合もあるので、その場合は、トランザクション境界を宣言する。
      トランザクション境界は、原則Serviceに設ける。アプリケーション層(Web層)にトランザクション境界が設けられている場合、業務ロジックの抽出が正しく行われていない可能性があるので、見直しを行うこと。

http://terasolunaorg.github.io/guideline/current/ja/ImplementationAtEachLayer/DomainLayer.html#service

mikannmikann

え、controllerにトランザクション貼るのだめなん?w

mikannmikann

あ~回答っぽいのある

  • service間の呼び出しは非推奨(影響範囲の拡大、再利用すべきロジックとそうでないロジックの区別がつきにくくなる)
  • service間で処理を共通化した場合はsharedServiceクラスを作成する

mikannmikann

これSharedService使ってないPJはどうすんねん

mikannmikann

この手の記事見てるとみんなTransaction凄い意識してるな
全然考えたことなかったわorz

mikannmikann

どうもserviceクラスからserviceクラス呼び出すのは基本NGっぽいな。
※最悪許容できるくらい
serviceクラス間で処理を共通化したいなんてことはよくある話。
それなのに共通処理を書くためのクラスがないっていうのがそもそもおかしいのか?

アンチパターン:serviceクラスからserviceクラスを呼び出す
解決策:共通化のためのクラスを作成しましょう
ってところか

mikannmikann

クラス内で共通化した処理はprivateになることが多いし、他から呼び出せない

mikannmikann

トランザクションも分離レベルとか含めてなかなか闇が深そう
一回勉強せんとな

mikannmikann

よくよく考えると、もしservice間で処理が共通化できるなら、controllerから複数のserviceを呼び出す必要とかないか

mikannmikann

処理が共通化できていない
→serviceからserviceを呼び出すORcontrollerから複数のserviceを呼び出す

mikannmikann

最後に調査踏まえての認識

  • controller
    • フロント(外部)とビジネスロジックを繋げる場所
    • serviceメソッドの呼び出しは1回だけ行うのが理想
      • controllerはよりシンプルに
      • serviceの共通処理が切り出されていれば、serviceの呼び出しは1回(1クラス1メソッド)で済むはず
    • 複数クラスのserviceメソッドを呼び出すのはよくない
      • serviceの共通処理が切り出されていれば、serviceの呼び出しは1回(1クラス1メソッド)で済むはず
  • service
    • ビジネスロジックを記述
    • serviceからserviceを呼び出すのは通常よくない
      • 影響範囲の拡大
      • 再利用すべきロジックとそうでないロジックの区別がつきにくくなる
mikannmikann

一夜明けて、昨日参照した記事を改めて読むと、

  • service→service:ダメ
  • controllerから複数のserviceメソッドを呼ぶ:やってもいいけど要件とTransactionに気をつけろ

かなあ

mikannmikann

以下引用

ControllerとServiceで実装するロジックの責任分界点について

本ガイドラインでは、ControllerとServiceで実装するロジックは、以下のルールに則って実装することを推奨する。

  1. クライアントからリクエストされたデータに対する単項目チェック、相関項目チェックはController側(Bean ValidationまたはSpring Validator)で行う。
  2. Serviceに渡すデータへの変換処理(Bean変換、型変換、形式変換など)は、ServiceではなくController側で行う。
  3. ビジネスルールに関わる処理はServiceで行う。業務データへのアクセスは、RepositoryまたはO/R Mapperに委譲する。
  4. ServiceからControllerに返却するデータ(クライアントへレスポンスするデータ)に対する値の変換処理(型変換、形式変換など)は、Serviceではなく、Controller側(Viewクラスなど)で行う。

http://terasolunaorg.github.io/guideline/current/ja/ImplementationAtEachLayer/DomainLayer.html#service

このスクラップは2023/01/15にクローズされました