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.

ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring

16,089 views

Published on

ドメインロジックに焦点をあてる。
それが、ドメイン駆動設計の基本。
ドメイン駆動設計の考え方とやり方の説明と、実践基盤としての Spring Framework/Spring Boot を使った事例の紹介。

Published in: Software
  • Be the first to comment

ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring

  1. 1. ドメイン駆動設計 powered by Spring
  2. 2. ドメインロジックに集中せよ 2017年3月28日 ギルドワークス 増田 focus on domain logic
  3. 3. ドメイン駆動設計 Domain-Driven Design
  4. 4. ソフトウェアの核心にある 複雑さに立ち向う Tackling Complexity in the Heart of Software
  5. 5. 複雑さという課題 The Challenge of Complexity
  6. 6. 設計を複雑にする要因 技術的な複雑さ ドメインの複雑さ ネットワーク、データベースなど 基盤となる技術の複雑さ ドメイン(対象領域)の ユーザの活動やビジネスの複雑さ
  7. 7. 設計を複雑にする要因 技術的な複雑さ ドメインの複雑さ ネットワーク、データベースなど 基盤となる技術の複雑さ ドメイン(対象領域)の ユーザの活動やビジネスの複雑さ 重要な課題は、ドメインの複雑さ ユーザの活動やビジネスそのものがもつ複雑さ
  8. 8. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  9. 9. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  10. 10. ドメインロジックに集中する ビジネスルール ドメインロジック 分析の対象 実装の対象 遵守すべき約束事 外部:契約、商習慣、法令、… 内部:社内規定、予算、しきたり、… ビジネスルールのサブセット プログラミング言語で記述
  11. 11. ドメインロジックに集中する ビジネスルール ドメインロジック 分析の対象 実装の対象 遵守すべき約束事 外部と:契約、商習慣、法令、… 社内で:予算、計画、規定、しきたり、… ビジネスルールのサブセット プログラミング言語で記述 アプリケーションが使われる領域(現実世界)の約束事を理解する システム化の対象となるビジネスルールを特定する それをプログラミング言語で表現する その活動に集中する
  12. 12. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  13. 13. 情報収集 分析・整理 ヒヤリング Q&A ユーザストーリ 画面の紙芝居 システム企画書 既存の帳票/ファイル 既存の画面 既存のデータベース 仕様 実装設計 画面一覧 機能一覧 項目定義 処理詳細 モデルを使わない開発プロセス
  14. 14. 情報収集 分析・整理 ヒヤリング Q&A ユーザストーリ 画面の紙芝居 システム企画書 既存の帳票/ファイル 既存の画面 既存のデータベース 仕様 実装設計 画面一覧 機能一覧 項目定義 処理詳細 モデルを使わない開発プロセス ドメインモデルを一切もたず バックログ(機能一覧、画面一覧)をとにかく消化する開発
  15. 15. 情報収集 分析・整理 ヒヤリング Q&A ユーザストーリ 画面の紙芝居 システム企画書 既存の帳票/ファイル 既存の画面 既存のデータベース 仕様 実装設計 画面一覧 機能一覧 項目定義 処理詳細 ビジネスルール モデル 現実を単純化した模型の導入 全体の見通しが良くなる ムリ・ムダ・ムラが減る モデリング作業が増える
  16. 16. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  17. 17. フェーズに分ける開発 情報収集 分析・整理 基本設計 詳細設計 運用 実装 based on out-of-date assumptions
  18. 18. フェーズに分ける開発 情報収集 分析・整理 基本設計 詳細設計 運用 実装 based on out-of-date assumptions 担当者が変わる → 伝言ゲーム 1方向の活動 → 誤りがあっても是正されない (後ろにいくほどつじつま合わせが多発)
  19. 19. インクリメンタルな開発 情報収集 分析・整理 基本設計 詳細設計 運用 実装 step-by-step, in small pieces, based on real-life experience day-1 day-2 day-3 … 同じメンバーが担当 すべてが発展途上 変化への機敏な対応 創発性(ブレークスルー)
  20. 20. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  21. 21. ステキなお知らせ
  22. 22. 核心にある 複雑さに立ち向かう 強力な援軍 Spring Framework Spring Boot
  23. 23. Spring Framework ドメインとドメインロジックに集中できる ドメインモデリングに時間を割ける
  24. 24. Spring Framework ドメインモデル以外のことを 全部用意するフレームワーク Spring handles the infrastructure so you can focus on your application. Spring focuses on the “plumbing" of enterprise applications so that teams can focus on application-level business logic. Spring Framework Reference Document Spring Framework Project Introduction Spring 入門 配管
  25. 25. Spring Boot 本来のアプリケーション開発をすぐ始められる day-1 からプロダクションレベルで運用できる インクリメンタルな開発を実践できる
  26. 26. 残念なお知らせ
  27. 27. Spring Framework Spring Boot こんな開発にも使えます…
  28. 28. ドメインとドメインロジックに 技術課題に集中する モデルに基づき設計する バックログをせっせと消化する インクリメンタルな設計 フェーズに分けて伝言ゲーム 基盤とアプリで別チーム
  29. 29. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  30. 30. ドメイン駆動設計 powered by Spring
  31. 31. アンチパターン ドメインロジック以外に焦点をあてる ドメインモデルなしに機能一覧バックログを消化
  32. 32. プレゼンテーション層 データソース層 アプリケーション層 画面の入出力 データベースの入出力 データベースの 更新・参照の手続き データの加工ロジック データの検証ロジック データの判断/加工/計算 書き込みの前処理ロジック 読み出しの後処理ロジック データ処理に焦点をあてる @Controller @Service @Repository
  33. 33. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  34. 34. プレゼンテーション層 データソース層 アプリケーション層 ドメインを隔離する @Controller @Service @Repository ドメインモデル ここを インクリメンタルに 成長させながら 全体の開発を駆動する ドメインロジックを ここに集約する
  35. 35. ドメインモデル An object model of the domain that incorporates both behavior and data
  36. 36. ドメインモデル ドメインロジックを オブジェクトで表現する model elements expressed as objects
  37. 37. ドメインモデルだと 何が良いのか?
  38. 38. 変更が楽で安全
  39. 39. ドメインモデル:変更容易性 ドメインロジックが重複しない ロジックを書いてある箇所の特定が簡単 変更の影響を狭い範囲に限定できる データを持つクラスが唯一のロジックを持つ パッケージ名→クラス名 変更したクラスに閉じる せいぜい、そのクラスを使うクラスまで
  40. 40. トランザクションスクリプト ドメインロジックが重複しない 同じロジックが重複する ロジックを書いてある箇所の特定が簡単 データ処理の流れを追いかけて探し回る 変更の影響を狭い範囲に限定できる 変更箇所の後続処理をすべて追いかける
  41. 41. ドメインオブジェクト 設計パターン
  42. 42. ドメインロジック ビジネスルール ドメインロジック 分析の対象 実装の対象 遵守すべき約束事 外部:契約、商習慣、法令、… 内部:社内規定、予算、しきたり、… ビジネスルールのサブセット プログラミング言語で記述
  43. 43. ドメインロジックの最小単位 数値 日付 文字列 数量、金額、… 予定日、締日、… 演算の対象 演算(判断/加工/計算)のパターン 識別コード/識別名 分類コード/分類名 等値の判定 大小判定/順序付け 四則演算 換算 範囲内/範囲外の判定 型変換(文字列表現から) 型変換(文字列表現へ) 有効要素の判定 ==, equals(), … <,>, compareTo(), … MIN,MAX, …. contains(), has(), … of(), parse(), … toString(), asText(), … +-*/, plus(), minus(), … inThousand(), inPieces(),
  44. 44. 値オブジェクト コレクションオブジェクト 区分オブジェクト ドメインロジックの置き場所 基本パターン
  45. 45. 値オブジェクト BigDecimal Integer … LocalDate Long 起算日 InitialDate 期限 DueDate 有効期間 ValidTerm 金額 Money 数量 Quantity 単位 Unit 言語で用意された汎用の「型」 独自に定義したドメイン固有の「型」 判断/加工/計算ロジックの置き場所 45
  46. 46. コレクションオブジェクト (ファーストクラスコレクション) • ListやSetをラップしたドメインオブジェクト • 「一覧」「履歴」という関心事 • 一覧の検索条件、表示項目、表示順の議論は、重要な関 心事の発見につながる • コレクション操作はコードがごちゃごちゃする • 変更の副作用が多い • クラスとして独立させ、そのクラスに コレクション操作のロジックを閉じ込める • count(), contains() • select(), reject() • convertTo()
  47. 47. 区分オブジェクト • 振る舞いを持った Enum • 区分ごとのロジックを別クラスに記述 • Java言語仕様に組み込まれた Strategy/Stateパターン • if 文/switch文を書かない工夫 説明とコード例は、googleで 「場合わけの書き方あれこれ」で検索、 または技術評論社ムック本 「オブジェクト指向をきちんと使いたいあなたへ」 場合ごとのドメインロジックを表現する道具
  48. 48. モジュール化 構造化 自己文書化 ドメインオブジェクト:設計原則
  49. 49. モジュール化 構造化 自己文書化 ドメインオブジェクト
  50. 50. モジュール化 複雑さに立ち向かうための工夫 プログラムを 開発/保守がやりやすい単位に分割する 部品化 組み立て
  51. 51. ドメインロジックのモジュール化 ドメインモデル (オブジェクトモデル) トランザクションスクリプト (手続きモデル) アプローチ 関連するデータとロジックを 一体にする データクラスと機能クラスに 分ける モジュール 分割の単位 関心事 (数量、金額、納期、締日、…) 値オブジェクトなど ドメインロジックの 部品化のパターンが明確 機能 (受注登録、注文変更、…) サブルーチン化が不明確 大きなデータクラスと 長いメソッドになりがち ロジックの 再利用 ドメインオブジェクトとして部品化 ドメインオブジェクトの 組み合わせで機能を実現 部品化が進まない ロジックの再利用がしにくい コードの重複
  52. 52. モジュール化 構造化 自己文書化 ドメインオブジェクト
  53. 53. ドメインロジックの構造化 複雑さに立ち向かうために 記述レベルを階層化する コンピュータよりの記述から 人間よりの記述へ 段階的に近づける
  54. 54. 構造化:記述レベルの階層化 業務で使う用語 期日 数量 金額 消費税 キャンセル規定 順番待ち 商品リスト 在庫一覧 ドメイン固有API ExpireDate Quantity Amount TaxAmount OverBookingPolicy WaitingList Catalogue Inventory Java コアAPI BigDecimal LocalDate List,Set,Map Predicate Stream/Collectors Java 言語仕様 int , char int[], char[] String , Enum if , for 機械 人 階 層 化 ドメイン固有APIのレイヤを追加する
  55. 55. モジュール化 構造化 自己文書化 ドメインオブジェクト
  56. 56. ドメインロジックの自己文書化 複雑さに立ち向かうために コードにドメインロジックを語らせる (自己文書化) パッケージ名/クラス名/メソッド名 メソッドの返す型 引数の型
  57. 57. ドメインロジックの自己文書化 ドメインオブジェクトを参照する他の三層のコード ドメインロジックとの関係性を語るようになる (ドメインモデルの自己文書化が他の三層に波及する) ソースコード以外の文書化 業務マニュアル <重要> 利用者ガイド <重要> 開発・保守ドキュメント <不要>
  58. 58. モジュール化 構造化 自己文書化 ドメインオブジェクト:設計原則
  59. 59. ドメインオブジェクトの設計レビュー ドメインロジック記述の怪しい臭い else句 switch文 boolean 宣言 判断ロジックの不適切な置き場所 判断ロジックの不要な複雑化 定数宣言だけの enum 区分ごとのロジックの置き場書が不適切 Stream ドメインロジックの暗黙化(判断/加工の隠蔽) ドメインロジックの重複 5行以上のメソッド ドメインロジックの暗黙化 ドメインロジックの重複 3つ以上のフィールド クラスの凝集度の低下(関心事の発散) ラムダ記法(無名関数) ドメインロジックの暗黙化 メソッドチェイン ドメインロジックの暗黙化 モジュール化/構造化/自己文書化の原則違反の臭い
  60. 60. ドメインを隔離する Isolating the Domain
  61. 61. プレゼンテーション層 データソース層 アプリケーション層 ドメインを隔離する @Controller @Service @Repository ドメインモデル ここを インクリメンタルに 成長させながら 全体の開発を駆動する ドメインロジックを ここに集約する
  62. 62. ドメインを隔離する データの入出力 画面 データベース ドメインモデル ドメインロジックの オブジェクト表現 画面やデータベースの都合を、ドメインモデルに持ち込まないこと
  63. 63. ドメインを隔離する 画面やデータベースの都合を ドメインモデルに持ち込まない
  64. 64. プレゼンテーション層と ドメインオブジェクト Spring MVC Thymeleaf Spring Security
  65. 65. プレゼンテーション層 @Controller ドメインモデル ドメインモデルに依存させる
  66. 66. プレゼンテーション層 ドメインオブジェクトを直接使う プレゼンテーション層の記述を ドメインモデルに依存させる プレゼンテーション層に 判断/加工/計算のロジックを書かない
  67. 67. プレゼンテーション層 HTTP リクエスト → ドメインオブジェクト DirectFieldAccess ドメインオブジェクト → HTTPレスポンス HTML テンプレート ( Thymeleaf )
  68. 68. @Controller class PersonController { @GetMapping("/") String form(Person person) { return "form"; } @PostMapping("/") String register(@Validated Person person, BindingResult result) { if (result.hasErrors()) return "form"; return "redirect:/results"; } @GetMapping("/results") String results() { return "/results"; } } ドメインオブジェクトを直接使う
  69. 69. Direct Field Access ドメインオブジェクトはロジックを書く <getter/setter/isXxx()を書かない> @ControllerAdvice public class BinderAdvice { @InitBinder public void initBinder(WebDataBinder binder) { binder.initDirectFieldAccess(); PropertyEditor trimmer = new StringTrimmerEditor(false); binder.registerCustomEditor(Object.class, trimmer); } } #kanjava MVC で検索
  70. 70. アプリケーション層と ドメインオブジェクト @Service @Validated ドメインの関心事としてのデータフロー
  71. 71. プレゼンテーション層 データソース層 アプリケーション層 @Controller @Service @Repository ドメインモデル 業務の関心事としての入出力
  72. 72. サービスクラス @Service @Validated public class PersonService { @Autowired PersonRepository repository; public void register(@NotNull Person person) { repository.register(person); } @NotEmpty public List<Person> listOf(@NotNull Criteria criteria) { return repository.listOf(criteria); } } @Validated 契約による設計 assertより表現力が豊か ドメインの関心事としてのデータ入出力
  73. 73. ドメインの関心事としての入出力 interface PersonRepository { void register(Person person); List<Person> listOf(Criteria criteria); } ドメインの関心事:モデルの一部としてインタフェース宣言 記録/参照(Repository インタフェース) 通知 (Transfer インタフェース) データベースの都合をドメインオブジェクトに持ち込まない インタフェースで実装を分離する 依存性の逆転 データソース層がドメインモデルに依存する
  74. 74. データソース層と ドメインオブジェクト @Repository MyBatis SQL mapping Transfer interface RestTemplate JmsTemplate MailSender
  75. 75. データソース層 @Repository ドメインモデル オブジェクトとテーブル 異なる世界のマッピング
  76. 76. データソース層 オブジェクトとテーブル 異なる世界を明示的にマッピング ドメインオブジェクトはロジックの置き場所 テーブルの構造を持ち込まない テーブルは事実を正しく記録するために 徹底的に正規化する (Not Null制約、一意制約、参照制約)
  77. 77. データソースの実装 @Repository public class PersonDatasource implements PersonRepository { @Autowired PersonMapper mapper; @Override public Person findBy(PersonNumber number) { return mapper.findBy(number); } } @Mapper public interface UserMapper { Person findBy(@Param(“number”) PersonNumber number); }
  78. 78. データソースの実装 <resultMap id= person" type="example.domain.model.user.Person"> <id property= id" column= user_id"/> <result property="name" column="name"/> <result property="dateOfBirth" column="date_of_birth"/> </resultMap> <select id="findBy" resultMap= person"> SELECT user_id, name, date_of_birth FROM users.users WHERE user_id = #{number} </select> SQLテンプレートからドメインオブジェクトを参照する Personクラスに明示的にマッピングする
  79. 79. プレゼンテーション層 データソース層 アプリケーション層 ドメインを隔離する @Controller @Service @Repository ドメインモデル ここを インクリメンタルに 成長させながら 全体の開発を駆動する ドメインロジックを ここに集約する
  80. 80. ドメイン駆動設計 Domain-Driven Design
  81. 81. ソフトウェアの核心にある 複雑さに立ち向う Tackling Complexity in the Heart of Software
  82. 82. ドメインロジックに集中する モデルに基づき設計する インクリメンタルに開発する 核心にある複雑さに立ち向う
  83. 83. ドメイン駆動設計 powered by Spring

×