ドメインオブジェクトの見つけ方・作り方・育て方

7,469 views

Published on

ドメイン駆動設計 のための オブジェクト指向設計 の基本と実装技法。

Published in: Software
0 Comments
35 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,469
On SlideShare
0
From Embeds
0
Number of Embeds
905
Actions
Shares
0
Downloads
48
Comments
0
Likes
35
Embeds 0
No embeds

No notes for slide

ドメインオブジェクトの見つけ方・作り方・育て方

  1. 1. ドメインオブジェクトの 見つけ方・作り方・育て方 有限会社 システム設計 増田 亨 ドメイン駆動設計のための 2016-5-25
  2. 2. ドメインオブジェクト どうやって見つけるか どうやって作るか どうやって育てるか 実際に、なにを考え、どうやっているのか
  3. 3. オブジェクト指向設計の 考え方とやり方 オブジェクト指向エクササイズ 9つのルール モジュール性 5つの基準 抽象データ型 契約による設計 コードのいやな臭い その改善策1章 ドメインを学ぶ 2章 言葉を使う 3章 モデルと実装を結びつける 4章 ドメインを隔離する 5章 モデルを表現する部品 10章 しなやかな設計 4冊とも、想定読者はオブジェクト指向でコードを書く人 それぞれが関連している 今日は実践例として紹介してみたい
  4. 4. ドメインオブジェクト 設計の基本 ・モジュール性 凝集と結合 ・オブジェクト指向によるモジュール性 見つけ方 ・ドメインを学ぶ ・とりあえずのひな型 ・ドメインオブジェクトの発見パターン 作り方 ・主役は値オブジェクト ・ドメインを隔離する ・オブジェクト指向エクササイズ 9つのルール 育て方 ・リファクタリング いやな臭いと改善策 ・振る舞いを豊かにする7つの視点 ・しなやかな設計 6つのパターン
  5. 5. 4冊に共通する価値観 変化を続ける 変更容易性 複雑さと戦う そのための技法が、オブジェクト指向でありエクストリームプログラミング 4冊は、強調する点、抽象度、表現が異なるが、同じ考え方が底流にある
  6. 6. オブジェクト指向の開発スタイル Iterative 小さく繰り返す Incremental +1 : 一度に少しずつ変化させる Interactive 意思の疎通を図りながら Synergy 3つの “I” の相乗効果 (足し算ではなく掛け算) 変更容易性を重視した設計技法の必然の開発スタイル 「変更」を予防する/管理する技法とは対照的な発想
  7. 7. 設計の基本 モジュール性 凝集と結合 オブジェクト指向によるモジュール性 ちょっとつまらない話になりますが…
  8. 8. 設計原則 モジュール性 凝集度 結合度 独立性の高い部品を組み合わせることで、複雑なソフトウェアを扱いやすくする技法 機能分割のモジュール性とオブジェクト指向のモジュール性は発想が別 「機能分割」のモジュール性と「オブジェクト指向」のモジュール性を いっしょくたに議論するからわかりにくい ? ? ?
  9. 9. モジュール性の基準 凝集と結合を、もう少し整理したモジュール性の評価基準
  10. 10. モジュール性の評価基準 基準 説明 分解しやすい Good NG 全体を部品にわけたとき、部品ごとに独立して開発できる 部品の開発に、他の部品の理解や参照が必要 組合せやすい Good NG 部品を、分解時の構造とは異なる組み合わせ方ができる 部品は、分解時の構造以外では使えない わかりやすい Good NG そのモジュールだけで、そのモジュールの用途を理解できる そのモジュールを理解するためには、そのモジュールを呼び出す 側、そのモジュールが呼び出す先を理解しないといけない 連続性 Good NG 仕様の変更の度合いとモジュールの変更の度合いが対応する 仕様の変更の度合いとモジュールの変更の度合いがばらつく 保護性 Good NG モジュールの障害が全体に波及しない モジュールの障害がシステム全体に伝播し増殖する 簡単に言えば 変更が楽で安全なのが良いモジュール性 変更がたいへんで危険なのが悪いモジュール性
  11. 11. モジュール性:2つのアプローチ 機能クラス+データクラス 抽象データ型 Java は、クラスベースのオブジェクト指向言語 すべてのロジックとデータ構造は、クラスとして宣言する必要がある クラスの使い方で、大きく2つの方向に分かれる 機能分割 オブジェクト指向
  12. 12. 機能分割:機能クラスとデータクラス • C言語や COBOLの設計スタイルを、Java に流用 • JavaBeans getter/setter – データの入れ物クラスの設計パターン – get する側のクラスに機能を記述する • JPA @Entity – Java Beans をテーブルとのマッピングに利用 (データモジュール) – 機能は、ロジッククラスに記述する (機能モジュール) • トランザクションスクリプト • ファットコントローラ/ファットサービス
  13. 13. オブジェクト指向:抽象データ型 • メイヤー流の「型」重視のオブジェクト指向 • 使う側から見た抽象データ型 – 必要な判断・加工・計算を内部で実行して、その 「結果」を返してくれる – 内部をどのように実装しているかは非公開 • 抽象データ型の内部 – 具体的なデータ表現(非公開) – そのデータを使った、判断・加工・計算のロジック の記述
  14. 14. 抽象データ型の例 内部のデータ表現 公開メソッド(やってほしいこと) String char[] value String substring() String[] split() String replace() … BigDecimal BigInteger intVal ( ⇒ int[] ) int scale BigDecimal add() BigDecimal[] divideAndRemainder() BigDecimal setScale() … LocalDate int year short month short day LocalDate plusDays() LocalDate minusMonths() boolean isBefore() … ArrayList Object[] elementData int size boolean add() boolean contains() …
  15. 15. モジュール性の比較 基準 機能分割 機能クラス+データクラス オブジェクト指向 抽象データ型 分解しやすい ○ ○ 組合せやすい × 分解時の構造に依存 ○ 分解時の構造に依存しない わかりやすい × 呼び出し元や呼び出し先を調べる 必要がある ○ 独立性が高い 連続性 × ひとつの変更が、複数個所に波及 する(コードの分散) ○ 関心事と実装の単位が整合している 保護性 × 呼び出し関係に沿って伝播する ○ 閉じ込めやすい 簡単に言えば 変更が楽で安全なのがオブジェクト指向 変更がたいへんで危険なのが機能分割
  16. 16. オブジェクト指向のモジュール性 • 難しい理屈から理解するのはたいへん – 学び方として、費用対効果が悪い • 実際にやってみる – オブジェクト指向らしいコードを書いてみて、変更が楽で 安全になることを体験するのが一番 ⇒ オブジェクト指向エクササイズ 9つのルール ⇒ リファクタリング いやな臭いとその改善 ⇒ ドメイン駆動設計 10章しなやかな設計の6パターン • いちど味を覚えると元の世界にはもどれない – わかりやすい – 連続性 – 組合せやすい 知っておいて損はない こっちが好きな人はこちらからどうぞw
  17. 17. モジュール性に優れたオブジェクト オブジェクト指向エクササイズ リファクタリング ドメイン駆動設計 10章しなやかな設計
  18. 18. オブジェクト指向エクササイズ 1. 1つのメソッドにインデントは1段階まで 2. else 句は使わない 3. すべての基本データ型をラップする 4. 1行につきドットはひとつまで 5. 名前を省略しない 6. 50行を超えるクラスを作らない 7. 1つにクラスはインスタンス変数は2つまで 8. ファーストクラスコレクションを使う 9. getter / setter を使わない このガイドラインにそってコードを書けばモジュール性を向上できる
  19. 19. リファクタリング いやな臭い 1. 重複したコード 2. 長いメソッド 3. 大きなクラス 4. 多すぎる引数 5. 基本データ型への執着 6. データクラス 7. switch 文 8. コメント … モジュール性が悪くなっている明らかな兆候 リファクタリングによる改善 ・メソッドの抽出 ・クラスの抽出 ・メソッドの移動 ・メソッドオブジェクト 一つのメソッドにインデントは1段階まで 50行を超えるクラスを書かない ひとつのクラスのインスタンス変数は2つまで すべての基本データ型をラップする getter/setter を書かない ファーストクラスコレクションを使う else句を使わない
  20. 20. ドメイン駆動設計 しなやかな設計 1. 意図の明確なインタフェース 2. 副作用のない関数 3. 表明 4. 概念の輪郭 5. 独立したクラス 6. 閉じた操作 10章の6つのパターン わかりやすい 組み立てやすい 分けやすさ 保護性 わかりやすい 連続性(モデルと実装の構造の一致) モジュール性を改善するための基本テクニック 5章の 値オブジェクトの設計パターンでもある
  21. 21. 設計の基本:まとめ • 設計の基本は「モジュール性」 • オブジェクト指向のモジュール性は 「抽象データ型」で実現する – データクラス+機能クラスは、手続き型のモ ジュール性 • 理屈よりも実践で覚えるのが楽で確実 – オブジェクト指向エクササイズ 9つのルール – リファクタリング いやな臭いとその改善 – ドメイン駆動設計 10章しなやかな設計
  22. 22. ドメインオブジェクトの見つけ方 ドメインを学ぶ とりあえずのひな型 覚えておくと役に立つ道具箱 メモ代わりにコードを書く
  23. 23. ドメインを学ぶ 情報源 語彙を増やす 言葉を関係づける
  24. 24. ドメイン駆動設計 ドメイン モデル ドメインの 「重要な関心事」を 鋭く説明する 選び抜かれた 重要な関心事を コードで表現する 会話を繰り返して 「要点」を明確にする 「重要な語彙」を チームで合意する 1章 2章 3章 24 第1章 ドメインの知識をかみ砕く 第3章 モデルと実装を結びつける 第2章 言葉を使った意図の伝達
  25. 25. 実際にどうやっているか 既存サイトの大幅改修の案件 召集されたチームが初日にやったこと
  26. 26. トップページ ヘルプ 利用規約
  27. 27. 全体図+用語の洗い出し
  28. 28. 言葉を関連づけた 初期のクラスのラフスケッチ
  29. 29. コードに書いてみる とりあえずのひな型 覚えておくと役に立つ設計パターン
  30. 30. とりあえずのひな型:8点セット 「Plan」という関心事に対応して8つのクラスを書く とりあえずのスタートライン 名前や内容はあとから改善
  31. 31. 覚えておくと役に立つ ドメインオブジェクトの 発見パターン
  32. 32. これらについて「名前」を探す
  33. 33. 関心事:3つの対象/6つの関係 ヒトは意思のある行動主体 特別の関心事 ・行動の履歴 ・連絡手段 ・特徴(Profile) ・好み(Preferece) 組合せは6種類だが、 ・方向 ・多重度 ・順序 ・再帰 など奥は深い ヒトとヒトの関係も 特別な関心事 ・コンタクト履歴 関心の強い関係には「名前」がついていることも多い 逆に関係の「名前」を発見できるとブレークスルーが起きる 多重度のある場合はファーストクラスコレクションクラスの名前になる
  34. 34. 関心事の種類と見つけ方 Aspect 知りたいこと それが何であるか which, what, when, where 画面や帳票から具体的に見つけやすい Why 6つの関係 約束と履行 方針と規則 判断や行動の理由づけ 業務知識の中核 見つけにくい ここを深く理解し、コードでうまく表現するこ とがドメイン駆動設計の勝負どころ How 記録と参照 約束と履行の監視 業務の基本 要求は表面的 より突っ込んだ設計が必要 勘定パターンを参考に 通知 受信と送信 業務の流れ 具体的な要求として見つかりやすい whyの 実行手段 性状 枠組み 制約
  35. 35. 性状(aspect) : 知りたいこと which 識別 Identity 名前、番号 Category 名前 Type 名前 what 値 数量、金額、率 説明、注釈 状態 when 時 日付 期間 where 位置 Address Location Area 物理、論理、仮想 知りたいことに「名前」をつけ 基本データ型(文字列型、数値型、日付型)で表現する それが、値オブジェクト 絶対/相対
  36. 36. why の設計パターン 外部との約束 「注文」は売買契約の一種 キンセャルポリシー etc. 内部の取り決め(生産や開発) 誰と誰の約束か? 契約 スケジュール 方針と規則
  37. 37. 性状 状態 約束と履行 ヒト 初期のモデルにも いろいろ登場している
  38. 38. ドメインオブジェクトの見つけ方:まとめ • 語彙を増やす – キャッチフレーズ、ヘルプ、利用規約、… • 関連づける – 言葉と言葉の正しい組み合わせ方を学ぶ – 図よりも声に出してしゃべってみる • 初日からコードを書く(クラス名を考える) – とりあえずのひな型 8クラス – 業務の関心事の発見パターン – メモ代わりに • src/main/java/domain/model を作って • ⌘N リターン 名前 リターン powered by Intellij IDEA
  39. 39. ドメインオブジェクトの作り方 主役は値オブジェクト ドメインを隔離する オブジェクト指向エクササイズ 9つのルールで作る
  40. 40. ドメイン知識を記述する ドメイン知識の実体は 基本データ型に対する ・判断 ・加工 ・計算 このコードをどこに書くか?
  41. 41. オブジェクト指向エクササイズ 1. 1つのメソッドにインデントは1段階まで 2. else 句は使わない 3. すべての基本データ型をラップする 4. 1行につきドットはひとつまで 5. 名前を省略しない 6. 50行を超えるクラスを作らない 7. 1つにクラスはインスタンス変数は2つまで 8. ファーストクラスコレクションを使う 9. getter / setter を使わない このガイドラインにそってコードを書けばモジュール性を向上できる
  42. 42. getter を使わない • getter がないということは、データを持つオブ ジェクトに仕事を依頼するしかない – get して自分で判断・加工・計算するのはNG • 基本データ型はすべてラップする • クラスは、最大2つのインスタンス変数しか持 ていない つまり • 基本データ型を1つか2つもった、50行以内 のクラスに、業務ロジックを書く
  43. 43. 主役は値オブジェクト • 文字列・数値・日付を保持する • それらのデータを使った、判断・加工・計算を担 当する • 値オブジェクトの業務知識と振る舞いが豊かに なれば、業務ロジックの大半は値オブジェクトに 書かれるようになる • 名前(クラス名)がロジックの置き場所を導く – 省略しない – 同一のコード(式)の重複記述が激減する – わかりやすさ/変更の容易さの源泉
  44. 44. ドメイン知識の置き場所 ドメイン知識の実体は データに対する ・判断 ・加工 ・計算 このコードをどう書くか?
  45. 45. ドメイン駆動設計 しなやかな設計 1. 意図の明確なインタフェース 2. 副作用のない関数 3. 表明 4. 概念の輪郭 5. 独立したクラス 6. 閉じた操作 値オブジェクトの設計パターン 判断・加工・計算を依頼する メソッド名 言語の標準ライブラリのみ依存 業務の用語と値オブジェクトの名前を一致させる 完全コンストラクタ 不変オブジェクト 契約による設計 メソッドが返す型、受け取る型を 自分と同じ型にする BigDecimal, LocalDate, String は、ある程度、この条件を満たしている ただし、扱えるデータ範囲が広すぎ クラス名やメソッド名が漠然としていて意図が不明確
  46. 46. ドメインオブジェクトの作り方 • String, BigDecimal, LocalDate を一つか二つ持った 「値オブジェクト」を作る – クラス名で役割を明確に – 公開メソッドを少数に限定して意図を明確に – メソッド名で意図を明確に – 内部で保持するデータの範囲を限定して意図を明確に – 事前条件、事後条件、不変条件を明確に • null を渡さない、戻さない • ゼロ割り算をしない • 表明 and/or 例外のスロー
  47. 47. 値オブジェクトの例 String List<String> BigDecimal Integer … LocalDate Long 起算日 InitialDate 期限 DueDate 有効期間 ValidTerm 金額 Money 数量 Quantity 単位 Unit 品名 ProductName 備考 Remarks 摘要 Abstract 言語で用意された「型」 (汎用) 独自に定義した「型」 (目的特化) 47
  48. 48. 値オブジェクトの設計 • 完全コンストラクタ – すべてのインスタンス変数は、生成時に設定 • 不変 – setter を書かない(状態を変えない) – 値を変更する時は、別のオブジェクトを生成して返す – 不変による「安定」 • ロジックの置き場所 – インスタンス変数を使った、判断・加工・計算 – 何もしないで素のデータを返す getter はNG 48
  49. 49. 値オブジェクトが主役 • 業務の関心事の基本語彙の抽出手段 目的を限定した抽象データ型 – String, BigDecimal, LocalDateの値の範囲、文字 種、形式、計算範囲を業務に合わせて制限する – 用途を限定するとプログラムが安定する – コードの重複がなくなり、変更が楽になる • 関心事を豊かに表現する手段 – メソッドの戻す値の「型」 – メソッドの引数の「型」 49
  50. 50. コード例
  51. 51. public class UserIdentity { @NotBlank(message = "メールアドレスを入力してください") @Email(message = "メールアドレスが正しくありません。") String mail; public UserIdentity(@NotNull String mail) { this.mail = mail; } public String mail() { return mail; // ローカル部(@の前) だけ返すとか、さんづけとか… } @Override public String toString() { return mail; } } Mail に型づけされた文字情報 データ表現として、InternetAddress を使うのも選択肢
  52. 52. public class DateOfBirth { @NotNull(message = “誕生日を入力してください。”) LocalDate date ; // データ表現として 文字列ではなく、LocalDate型を使う String source; // 入力値の保持 boolean valid = true; // 入力値の有効性 public DateOfBirth(@NotNull String source) { this.source = source; try { LocalDate.parse(source); } catch ( DateTimeException exception) { valid = false; } } public Age age() { return new Age(this.date); // 年齢計算や表記は Age にまかせる } @AssertTrue(message = "日付が正しくありません。") public boolean isValid() { if(source.equals("")) return true; return valid; } @Override public String toString() { return source; } }
  53. 53. あとは、育て方へ … 知識の広がり 知識の深まり コードで表現
  54. 54. 第4章 ドメインを隔離する 形式的な隔離 ドメインロジックをほんとうに隔離する オブジェクトの世界とフラットな世界 その前に
  55. 55. 形式的な隔離
  56. 56. 形式的な隔離
  57. 57. 形式的な隔離:お約束 クラス フィールド メソッド コントローラ PlanController @Conroller @RestController @ControllerAdvice @Autowired Service @RequestMapping @Validated アプリケーション PlanService @Service @Autowired Repository データソース PlanDatasource @Repository @Autowired Mapper データマッパー PlanMapper @Mapper @Param ドメイン Plan PlanRepository … @Valid @NotBlank @Size … @AssertTrue ドメイン以外は、お約束の名前とアノテーションでシンプルに記述 コードがごちゃごちゃしてきたら、ドメインロジックがドメイン層から流出している兆候
  58. 58. ドメインロジックをほんとうに隔離する • ドメインのロジックが書かれやすい個所 – ビューテンプレート – コントローラ – サービス – データソース – SQL文( where 句とか ) – 動的SQL文の組み立てロジック – テーブル • 値オブジェクトに置くべきちょっとしたロジックがころがって いないか、いつもきょろきょろする – コードがごちゃごちゃしてきたら、そこにロジックが見つかる – 値オブジェクトにロジックを移動する – 新しい値オブジェクトを作る
  59. 59. ドメインを隔離する オブジェクトの世界 / フラットな世界 基本データ型のリスト構造 ロジックのモジュール性を 取り除いた世界 具体的なデータ表現のみ グラフ構造(モジュール性) ロジックの整理の単位 関係の表現手段 組み立て方の柔軟性 抽象データ型(内部のデータ表現は隠ぺい) テーブル 画面項目 JSON
  60. 60. ドメインロジックをほんとうに隔離する • 外部のビュー構造から独立させる – 外部のビュー : フラットな基本データ型の羅列 • テーブル • 画面( form のデータバインディング) • JSON – ドメインオブジェクト : グラフ構造 • 構造変換 – グラフ ⇔ フラット – フレームワークを活用する ただし、フレームワークの都合は排除する ドメインの表現にこだわる 妥協しない
  61. 61. フレームワークの都合を排除する • O-R マッピング MyBatis SQL Mapper – ダイレクトフィールドアクセス ( getter/setter 不要) – 構造変換は、path 記法 ( plan.location.primary ) – null はマッピングされない • フォームバインディング Spring MVC DataBinder – ダイレクトフィールドアクセスに設定 (getter/setter を使わない) – 構造変換は、path 記法 – nullはバインドの対象外にする • O-JSON マッピング Jackson ObjectMapper – ダイレクトフィールドアクセスに設定 – 構造変換は、View クラスにやらせる • ドメインオブジェクトはどのような構造に変換されるか知らない
  62. 62. public class CustomObjectMapper { public ObjectMapper ofDirectFieldAccess() { ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.FIELD,JsonAutoDetect.Visibility.NON_PRIVATE); mapper.setVisibility(PropertyAccessor.GETTER,JsonAutoDetect.Visibility.NONE); mapper.setVisibility(PropertyAccessor.SETTER,JsonAutoDetect.Visibility.NONE); return mapper; } } @ControllerAdvice public class BinderAdvice { @InitBinder public void initBinder(WebDataBinder binder) { binder.initDirectFieldAccess(); binder.registerCustomEditor(Object.class, new StringTrimmerEditor(true)); // ブランク文字列は、null とする // バインドの対象外となる } } ダイレクトフィールドアクセスの設定
  63. 63. ドメインオブジェクトの作り方:まとめ • 主役は値オブジェクト – データの保持(文字列、数値、日付) – データを使った、判断/加工/計算の置き場所 • オブジェクト指向エクササイズ 9つのルール – getter/setter を使わない – 名前は省略しない – ひとつのクラスにインスタンス変数は2つまで • ドメインを隔離する – 形式的な隔離 – ドメイン層以外へのロジックの記述に敏感になる – オブジェクトの世界/フラットな世界 • フレームワークを活用する • フレームワークや外部の都合を排除する
  64. 64. ドメインオブジェクトの育て方 育て方のシナリオ リファクタリング 知識の置き場所のターゲット 7つの視点 しやなかな設計6つのパターン
  65. 65. 育て方のシナリオ 1. 最初は器だけのクラスを作る – とりあえずのひな型8点セット – メモ代わりに作られたクラス名だけのクラス – コンストラクタと toString() だけの値オブジェクト ・・・ 2. 動かすために判断・加工・計算ロジックを書いていく – 理想:よく置き場所を考えて書く – 現実:てっとりばやく動かせる場所に書く 3. コードが増え、ごちゃごちゃしてくるので整理する – ドメインオブジェクトの持つデータを使って、判断・加工・計算してい るロジックを見つける(一行の式かもしれない) – そのロジック(計算・加工・判断)に名前をつける – 適切な場所にロジックを移動する(リファクタリング)
  66. 66. ロジックを整理すべき兆候 リファクタリングのいやな臭い コードの重複 長いメソッド 大きなクラス 引数の多さ
  67. 67. 改善の技法 メソッドの抽出 クラスの抽出 メソッドの移動 一時変数を値オブジェクトに 長いメソッドをオブジェクトに
  68. 68. メソッドの抽出 • 基本中の基本 • ひとかたまりのロジック(判断・加工・計算)を 見つける – 改行 – コメント – 3行以上、改行がなかったら怪しい • かたまりに名前をつける(メソッドを抽出する) – 一行の式でも、抽出の対象(名前をつける対象) – このひと手間が、ロジックの移動を可能にする
  69. 69. クラスの抽出とメソッドの移動 • データに注目して別クラスを見つける – インスタンス変数が増えたら別クラスに • インスタンス変数は2つまで – いつもペアになっている変数や引数のグループ を見つけたらクラスに • prefix や、 suffix が同じ変数名は、グループ化の有力 候補 • そのクラスのデータを使う判断・加工・計算の ロジックを、そのクラスに移動する – メソッド名を考える – やりたいことや知りたいこと
  70. 70. 一時変数を値オブジェクトに • メソッド内の一時変数を持つ値オブジェクトを 作る • その値オブジェクトにロジックを移動する • もとのロジックを書き換える value = new ValueObject(一時変数) value.doSomething() • たった一行の式でも、こういう値オブジェクト にカプセル化すると、あちこちで利用可能に なる – コードの重複を減らす
  71. 71. 長いメソッドをオブジェクトに • ごちゃごちゃしたメソッドのリファクタリングの 定石 • メソッド名を名詞に変えたクラスを作る • そのクラスに、メソッドごとコピーする • 元のクラスのインスタンス変数、メソッドの引 数、一時変数をすべて、新しいクラスのインス タンス変数として宣言する • すべての変数がインスタンス変数なので、い かようにも、メソッドの分割ができる
  72. 72. ロジックの置き場所のターゲット 値オブジェクト 一覧オブジェクト 区分オブジェクト
  73. 73. ドメインのロジックをどこに書くか その有力な候補が 値オブジェクト、一覧オブジェクト、区分オブジェクトの3つ
  74. 74. 値オブジェクト 「値」の判断・加工・計算ロジックの置き場所 74
  75. 75. 値オブジェクト String List<String> BigDecimal Integer … LocalDate Long 起算日 InitialDate 期限 DueDate 有効期間 ValidTerm 金額 Money 数量 Quantity 単位 Unit 品名 ProductName 備考 Remarks 摘要 Abstract 言語で用意された「型」 (汎用) 独自に定義した「型」 (目的特化) 75
  76. 76. 一覧オブジェクト (ファーストクラスコレクション) 76
  77. 77. 一覧オブジェクト (ファーストクラスコレクション) • ListやSetをラップしたドメインオブジェクト • Offers • MailBox • SkillSet • 「一覧」や「履歴」という関心事の表現 – 「一覧」は利用者の関心事が集中する場所 – 「一覧」の議論は、重要な関心事の発見の良い機会 • コレクションの操作は、コードがごちゃごちゃしや すく、変更の副作用が多い – クラスとして独立させ、そのクラスに閉じ込める 77 9章 概念を掘り出す 10章 概念の輪郭
  78. 78. 区分オブジェクト (場合ごとのビジネスルールの表現) 78
  79. 79. 区分オブジェクト • 振る舞いを持った Enum • 区分ごとのロジックを別クラスに記述 • Java言語使用に組み込まれた Strategy/Stateパターン 説明とコード例は、googleで 「場合わけの書き方あれこれ」で検索。 または「オブジェクト指向をきちんと使 いたいあなたへ」 場合ごとのビジネスルールの表現 79
  80. 80. 区分オブジェクトの効果 • 関心事の明示的なコード表現 • 複雑な if文記述の解消 – 区分ごとの分岐記述( if文 or switch文 )は、一箇所 になる – 場合によっては、まったく書かなくてよくなる • どこに何が書いてあるかわかりやすくなる – 区分ごとの業務ルールや知識のロジックの置き場所 をクラス単位で分離 • 区分の追加や削除をした時の、変更の副作用が 少ない 80 9章 概念を掘り出す 10章 概念の輪郭
  81. 81. オブジェクトを育てる7つの視点
  82. 82. 振る舞いを豊かにするメソッド候補 視点 例 文字列で表現する show(), asText(), inThousand(), shortName() , fullName(), … 文字列から生成する parse(), of(), from(), … 同一性の判定 isSame(), equalsIgnoreCase(), … 比較・順序づけ compareTo(), before(), after(), … 計算 plus(), minus(), next(), previous(), with(), … 列挙 values(), contains(), valueOf(), … 上限・下限 max(), min(), within(), …. 元ネタは Haskell の組み込みの型クラス
  83. 83. 第10章 しなやかな設計 値オブジェクト、一覧オブジェクト、区分オブジェクトの 改善のチェックリスト
  84. 84. しなやかな設計:6つのパターン 1. 意図の明確なインタフェース 2. 副作用のない関数 3. 表明 4. 概念の輪郭 5. 独立したクラス 6. 閉じた操作 モジュール性を改善するためのチェックリストとして使う
  85. 85. 予測可能に改善する 1. 意図を明確に – クラス名やメソッド名をみただけで、どんな判断・加工・計算を やってもらえるか、わかりやすいか? 2. メソッドの副作用をなくす – query と command は同じメソッドにしない – クライアント側からとのお約束の例 • query で確認してから command 実行 • command を実行してから query で確認 3. 表明を具体的に – アノテーション – 例外のスロー宣言 – JavaDoc – assert 文 ( Java では使い物にならない) – テストコード ( 別モジュールになるのが難点)
  86. 86. モジュールの独立性を高める 4.概念の輪郭 – 業務の関心事とモジュールの単位を合わせる – どこに何が書いてあるかわかりやすく – 業務のニーズの変更とモジュールの変更の連続性を向上する 5.独立したクラス – 言語仕様と標準ライブラリだけに依存させると独立性が高くな る – 変更の影響が局所化しやすい – 再利用が容易 6.閉じた操作 – メソッドの返す型、引数の型を、自身の型だけにする – 他のモジュールへの依存性が減る
  87. 87. ドメインオブジェクトの育て方:まとめ • ごちゃごちゃしてきたら整理する • 整理の基本はメソッドの抽出と移動 • 移動先の有力候補は、値オブジェクト、一覧 オブジェクト、区分オブジェクト • 7つの視点で振る舞いを豊かにする • 6つのパターンでモジュール性を改善する
  88. 88. 本日のまとめ 88
  89. 89. ドメインオブジェクト どうやって見つけるか どうやって作るか どうやって育てるか 実際に、なにを考え、どうやっているのか
  90. 90. オブジェクト指向設計の 考え方とやり方 オブジェクト指向エクササイズ 9つのルール モジュール性 5つの基準 抽象データ型 契約による設計 コードのいやな臭い その改善策1章 ドメインを学ぶ 2章 言葉を使う 3章 モデルと実装を結びつける 4章 ドメインを隔離する 5章 モデルを表現する部品 10章 しなやかな設計 4冊とも、想定読者はオブジェクト指向でコードを書く人 それぞれが関連している 今日は実践例として紹介してみたい
  91. 91. ドメインオブジェクト 設計の基本 ・モジュール性 凝集と結合 ・オブジェクト指向によるモジュール性 見つけ方 ・ドメインを学ぶ ・とりあえずのひな型 ・ドメインオブジェクトの発見パターン 作り方 ・主役は値オブジェクト ・ドメインを隔離する ・オブジェクト指向エクササイズ 9つのルール 育て方 ・リファクタリング いやな臭いと改善策 ・振る舞いを豊かにする7つの視点 ・しなやかな設計 6つのパターン
  92. 92. ドメイン駆動設計への道 92
  93. 93. できない理由? • 今のプロジェクトでは無理 • 今のチームでは無理 • 今の会社では無理 • 今の自分の力では無理 … 93
  94. 94. • どんな状況でも改善できる • どんなときでも「あなた」から改善を始められる • どんなときでも「今日」から改善を始められる ケント・ベックのメッセージ 94
  95. 95. ドメイン駆動設計への道 95 どんな状況でも「ドメインの知識」を学ぶことはできる どんな時でも「ドメインの言葉」で話すことはできる どんな時でもドメインの言葉を「コード」に反映できる

×