Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

設計と実装で 抑えておきたい サービスクラスと例外

1,977 views

Published on

社内勉強会資料

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

設計と実装で 抑えておきたい サービスクラスと例外

  1. 1. 設計と実装で 抑えておきたい サービスクラスと例外 UUUM株式会社 佐藤琢哉(nazo)
  2. 2. UUUMについて • YouTuberであれこれする会社 • HIKAKIN・はじめしゃちょー・フィッシャー ズ… • 自社チャンネルも多数
  3. 3. 会場提供 DCI Toyko #1
  4. 4. エンジニア採用してま す • エンジニアいるんですよ • クリエイター向けサービス、一般向けサービス 、ゲーム、データ解析などなど… • 詳細はuuum.co.jpで
  5. 5. 本スライドの内容について • プログラムを書く上で抑えておきたい点 • サービスクラスって何?必要なの? • DDDの話ではなく、なぜ「サービスクラス」 というものが存在するのか、という話 • 例外の書き方って?
  6. 6. 今時の設計って? • DDDとかDCIとかオニオンアーキテクチャとか クリーンアーキテクチャとかMVVMとかSOLID 原則とかなんとか… • 覚えきれない! • 自分は覚えれたとしてもチーム全員が覚える まで待つ?無理じゃない?
  7. 7. • 設計力だけでなく設計思想にも個人差がある • 設計に正解はない • とはいえチーム開発ではある程度同程度の品質 にしたいし、コードレビューでケンカするよう な状況になってはいけない • ここだけ抑えておくというところを決める
  8. 8. ここだけ抑える • サービスクラスの作り方 • 例外設計 • テストは書く!
  9. 9. お詫び • 以下の内容は、各種書籍やインターネット上の 文献を元に、独自解釈を加えたものです • 断言しているような箇所がいくつかありますが 、あくまで「私なりの定義」であり、一般的に こうだ!というものではありません • 他所で似たような話をしても通じない・解釈が 違う可能性があります
  10. 10. サービスクラス
  11. 11. サービスクラスとは? • ビジネスロジック(ドメインロジック)を書く 場所の集合体 • クラスじゃなくてもいい(言語による)
  12. 12. MVCの何が足りない? • MVCはシステム的な観点で役割を分解したもの • 処理(M)・出力(V)・フロー(C) • 本来の意味ではモデルとサービスは同等
  13. 13. モデルではだめなのか ? • 現代ではなぜかモデルがテーブルと1:1だったり 、そもそもテーブルの1レコードを表すようにな ってしまった • それにしても役割が多すぎる
  14. 14. モデルを更に分解する • Entity • ドメインモデル層のオブジェクト • 誤解前提で言えば1レコード • Repository • Entityの倉庫 • 誤解前提で言えばSQL • Service • ビジネスロジック • 他にもある
  15. 15. Railsで考える • Entity : Modelオブジェクト • Repository : Modelのクラスメソッド(特に scope) • Service : どこ?
  16. 16. (Railsの)モデルクラスにサ ービスを書いたら駄目なのか ? • テーブルはあくまで集合を表すもの • ロジックは業務であり、業務は集合ではない • テーブル名と業務名が同じとしても、そこは明 確に分けたほうがいい • まあでも面倒だったら書いてもいいんじゃな い(適当)
  17. 17. そもそもビジネスロジックっ て何? • ドメインロジック(違いあるの?) • 実際に(そのシステムで)行われる業務をコー ドに落とし込んだもの • 「責任範囲」という単位で分割される
  18. 18. 責任範囲 • その業務はどこまでの内容に対して責任を持っ ているか • その業務が責任を持っていない範囲はどこか • なるべく1業務の責任範囲は最小にする
  19. 19. 業務 • なるべく現実の業務を「そのまま」コードに落と す • 「人事部」には「人材を探す業務」や「人員を 異動させる業務」とかがあって…みたいな • 「人事部」がサービスクラスで、様々な細かい 業務がメソッド • 日本語で考えて設計する
  20. 20. なんかそのビジネスロジック とかがわかんないんだけど… • こればかりは案件次第なのでトレーニングが必 要 • 基本は「システム的でないもの」 • システム的なものって? • リクエストから来たものをどうするとか • 認証がどうとか • ビューに渡すための整形とか
  21. 21. 今までのコントローラーの中 身をサービスに移せばいいの ? • 全然違う • よくある間違い • サービスクラス内に `execute` みたいなメソッ ドが1しかないやつ • コントローラーに書く必要があるものはコント ローラーに書いて良い • 前述の「システム的なもの」 • そこの共通化はサービスの責務ではない
  22. 22. コントローラーには処理の流 れを書く • リクエストからフォームを作って • フォームで入力値を検証して • 入力値が問題なければビジネスロジックで処理 して • 処理結果をビューに渡す
  23. 23. サービスクラスにはビジネス ロジックのみを書く • インフラ固有のコードはビジネスロジックでは ない • 入出力のためのコードはビジネスロジックでは ない
  24. 24. メール送信とか外部API呼び出 しとか • それらは別クラスに分類 • ビジネスロジック内でそれらを直接書いてはい けない • 依存するものであればDIで依存関係を明確にす る • 依存しなくてもいいのであればコントローラー などでそれぞれ別に扱う
  25. 25. データと業務は違う • 「注文」テーブルと「注文」業務 • たまたま同じ名前なだけ • データは自ら処理しない • 「注文明細」テーブルがあっても「注文明細」 業務はない
  26. 26. コントローラーを全部サービ スにすればいいの? • 違うよ全然違うよ • サービスはビジネスロジックだけを書く場所だ よ • サービスが全てではないよ
  27. 27. Dependency Injection • サービスAはサービスBに依存する • サービスAはインフラCに依存する • 事前に定義することで依存関係を明確にする • 外部ライブラリなどの依存関係の差し替え • 依存部分をモック化することによってテストを明 確にする
  28. 28. DIとテスト • DIはテストのためにあると言っても過言ではな い • そのテストはどのビジネスロジックを対象とし たものか • 他のビジネスロジックのテストを混ぜてはいけ ない
  29. 29. テストが書きやすい設計 • テスト対象が複雑であればあるほどテストしに くい • 常に「このコードはテストが書きやすいか」を 意識する
  30. 30. 役割を混ぜない • サービスクラスにしてもDIにしてもテストにし ても、「役割を明確にする」ということが全て • 違う役割のものは違う箇所に • 役割=ドメイン 役割を基準に考える=ドメイ ン駆動設計…? • 本資料はDDDの解説ではありません
  31. 31. 役割を最小にする • 1つのメソッドは1つの役割のみにする • あれもしてこれもして…みたいなのは作らない • 作るなら「それだけに専念する」 • それを呼び出すことによって起こることを明確 にする
  32. 32. まとめ • 「モデル」と呼ばれているものは役割(責務) が多すぎるので分解する • サービスクラスはそのための手法の一つ • 1メソッドでの役割は1つに絞る • 少ない役割に対してテストを書く
  33. 33. 例外とエラー処理
  34. 34. 例外 • いわゆる try catch
  35. 35. ダメ try { … } catch (Exception $e) { … }
  36. 36. 例外とは? • 「例外」 • 本来ありえない状態
  37. 37. 本来ありえない状態 • いかなるユーザーの操作でも起こらない状態 • ユーザーの操作によって起こる状態は正常系 • 「正常に」エラーを返す
  38. 38. 本来ありえない状態 • DBなどへの接続エラー • 本来その状態では起こり得ないデータの状態 • 通常の方法では入力できないものを入力したと か
  39. 39. 例外とバリデーション • 入力に対する検証=バリデーション • それだけではないが • バリデーション違反は、適切な違反理由をユーザーに返却 する • 処理が続行不可能になる=例外 • 例外の場合は、ユーザーに詳細内容を伝える必要はない • あっても問い合わせコードみたいなのとか
  40. 40. 例外とcatch • 続行不可能なんだから基本的にはcatchしてはい けない • そのまま静かに終了するのが良い
  41. 41. catchしてもいい場合 • 特定のライブラリの範囲内では続行不能だが 、それを取り扱うアプリケーション的には続 行可能な場合 • 特定ドメインでは続行不可能だが、ドメイ ンの外では続行可能
  42. 42. catchするからには責任を持つ • 例外を握りつぶす=本来ありえない状態を無視 する • 危険な状態を見過ごす可能性が高い • 本当に握りつぶして良いか、エラーログはどう 扱えばいいのか
  43. 43. 全catchがダメな理由 • 何の例外がそこで出るのか全て把握しているか ? • それを全部握りつぶして良いのか把握している のか?
  44. 44. DBロールバックと例外 • ロールバックしたいから全部の例外を取りたい • それ本当に必要? • セッションが終了してしまえば勝手にロールバ ックされる • 終了で自動切断の仕組みを作っておく
  45. 45. ログと例外 • ログを取りたいから全てcatchしたい • それも本当に必要? • 例外をcatchしない場合に外側で勝手にログを吐 くようにすればいい
  46. 46. 例外と責務 • 共通的な例外処理は各個別処理でやることでは ない • 共通のことは共通の部分に任せる • 個別処理は個別処理に集中する
  47. 47. まとめ • 例外を取る必要があるのか考える • 例外を取った場合は取った例外の種類全てに責 任を持って対応する

×