ドメインロジックの実装方法とドメイン駆動設計

48
ドドドドドドドドドドドドドド ドドドドドドドド Ouobpo ドド ドド http://ameblo.jp/ouobpo BPStudy ド7ド 2008 ド 3 ド 28 ド

Upload: tadayoshi-sato

Post on 27-May-2015

13.264 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: ドメインロジックの実装方法とドメイン駆動設計

ドメインロジックの実装方法とドメイン駆動設計

Ouobpo

佐藤 匡剛http://ameblo.jp/ouobpo

BPStudy 第 7 回 2008 年 3 月 28 日

Page 2: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 2

もくじ

第Ⅰ部 ドメインロジックの実装方法 第Ⅱ部 ドメイン駆動設計の紹介

Page 3: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 3

第Ⅰ部ドメインロジックの実装方法

Page 4: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 4

3 層アーキテクチャ

エンタープライズアプリの典型的アーキテクチャ

Web アプリ FW

サー

ビス

レイ

ヤー

DI / IoC コンテナ

データアクセス FW

DAO

プレゼンテーション層 ドメイン層 インテグレーション層

POJOアクション

アクション

アクション

POJO

POJO POJO

DAO

インテグレーションゲートウェイ

システム間統合 MW

FW ・・・ フレームワーク   MW ・・・ ミドルウェア

ルールエンジン

ワークフローエンジン

Page 5: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 5

ビジネスにとって最も重要な部分

Web アプリ FW

サー

ビス

レイ

ヤー

DI / IoC コンテナ

データアクセス FW

DAO

プレゼンテーション層 ドメイン層 インテグレーション層

POJOアクション

アクション

アクション

POJO

POJO POJO

DAO

インテグレーションゲートウェイ

システム間統合 MW

ルールエンジン

ワークフローエンジン

業務知識を実現している部分=ドメインロジック

Page 6: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 6

ドメインロジック実装の 3 つのパターンMartin Fowler 『エンタープライズアプリケーションアーキテクチャパターン』より) Transaction Script パターン

ドメインロジックをデータと振舞に分け、振舞をスクリプト的に記述する方法。手続き的。

Domain Model パターン ドメインロジックをデータと振舞を合わせたオブ

ジェクトによりモデル化する方法。オブジェクト指向的。

Table Module パターン 上記 2 つの中間的な方法。データと振舞を分ける

が、振舞をテーブル毎に構成する。(今回は省略)

Page 7: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 7

Transaction Script パターン

( Martin Fowler 『エンタープライズアプリケーションアーキテクチャパターン』より)

recognizedRevenue()calculateRevenueRecognitions()

RecognitionService

Page 8: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 8

Domain Model パターン

( Martin Fowler 『エンタープライズアプリケーションアーキテクチャパターン』より)

recognizedRevenue()calculateRecognitions()

Contract

calculateRecognitions()

Product

1

RecognitionStrategy

1Complete

RecognitionStrategy

Page 9: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 9

Transaction Script と Domain Model の比較 Transaction Script

○ 構造がシンプル。 OO に慣れてないプログラマにも分かりやすい

× ロジックが複雑になると重複がひどくなる Domain Model

○ 複雑なロジックも重複なくきれいにモデル化できる

× 非常にハードルが高い。データベースとのマッピングも大変

Page 10: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 10

日本では・・・

Transaction Script が主流 Domain Model を採用したプロジェクトは見たことがない ⇒  なぜ?

ちまたに Domain Model のサンプルコードがほとんどないからでは? PofEAA もちょっとしかサンプルコードを載せていない 雑誌でも Domain Model のサンプルコードはほとんどない フレームワーク、 DI コンテナに付いてくるサンプルコー

ドはだいたい Transaction Script 寄り

⇒  それではサンプルコードを見てみよう!

Page 11: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 11

給与計算システムの例

ユースケース図

例月バッチ

例月給与を支払う

基本給を計算する

<< include >>

手当を計算する

保険料を計算する

税を計算する

<< include >>

<< include >>

<< include >>

期末賞与を

支払う

年末調整を行う

Page 12: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 12

給与システムのドメインモデル

従業員番号氏名

従業員Employee

対象年月時間外勤務時間

勤怠実績Time Record*

1

手当Allowance

職種ランク

職責Position

1

1

1

対象年月支給項目控除項目

給与明細Pay Slip

時間外手当Overtime

Allowance

家賃

住宅手当Rent

Allowance

基本情報

1

/ 勤怠項目1

1

控除はモデルから省略

Page 13: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 13

給与システムのデータモデル

employee_id <<PK>>namejob_typerankrent_allowancerent

<< table >>

employee

employee_id <<PK>> <<FK>>target_year <<PK>>target_month <<PK>>overtime_hours

<< table >>

time_record

1

employee_id <<PK>> <<FK>>target_year <<PK>>target_month <<PK>>base_salaryovertime_allowancerent_allowancetotal_amount

<< table >>

pay_slip1

Page 14: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 14

給与システムのサンプルコード

Google Code プロジェクトの SVN リポジトリ上に公開されています。 http://ouobpo.googlecode.com/svn/trunk/ 

bpstudy-200803/

Page 15: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 15

Transaction Script版の設計クラス図

dao

entity

service

getAllEmployees()pay()

PayrollServiceImpl

selectAll()

<< interface >>EmployeeDao

Seasar

PayrollService

Main

insert()update()selectByEmployeeIdYearMonth()

<< interface >>PaySlipDao

selectByEmployeeIdYearMonth()

<< interface >>TimeRecordDao

PaySlip

TimeRecord

Employee

給与計算の仕組みは pay メソッドの中で閉じてしまい、モデルからは何も分からない

Page 16: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 16

Domain Model版の設計クラス図

domain

service

daogetAllEmployees()pay()

PayrollServiceImpl

selectAll()

<< interface >>EmployeeDao

Seasar

pay()

employeeIdname

Employee

PayrollService

Main

calculateBaseSalary()

jobTyperank

Position

1

insert()update()selectByEmployeeIdYearMonth()

<< interface >>PaySlipDao

selectByEmployeeIdYearMonth()

<< interface >>TimeRecordDao

calculate()

Allowance{ abstract }

calculate()

OvertimeAllowance

calculate()

applicablerent

RentAllowance PaySlip

TimeRecord

給与計算の仕組みがオブジェクトモデル上に反映されている

Page 17: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 17

Domain Model パターンの真のメリット① 複雑なロジックを可視化できる

.xls

ユースケース記述ビジネスルール定義書

【 Transaction Script】

【 Domain Model】

ソースコード

.xls

ユースケース記述ビジネスルール定義書 ソースコード

pay()

employeeIdname

Employee

calculateBaseSalary()

jobTyperank

Position

1

calculate()

Allowance{ abstract }

calculate()

OvertimeAllowance

calculate()

applicablerent

RentAllowance PaySlip

TimeRecord

文章で書かれた仕様がそのままソースコードに

設計クラス図

ソースコードの構造が分かる

Page 18: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 18

Domain Model パターンの真のメリット② ソースコードそのものはシンプルになる

クラス/インタフェースの数が減る Logic + Entity DomainObject⇒

メソッドの引数が減る pay(employee, year, month) pay(year, month)⇒

メソッド内の Getter メソッド呼び出しが減る entity.getXxx() this.xxx⇒

Getter / Setter メソッドが減る

Page 19: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 19

Domain Model を採用する際の障壁 3 つの障壁

1. Domain Model は修得が難しく、開発者の確保が難しい OO 的な考え方の普及、技術者の底上げが必要 そもそも高度な専門分野なのに、ソフトウェア工学の学位をもっ

た技術者がほとんどいないという、日本の IT 業界の構造的な問題?

2. DI との親和性が低い 確かに Seasar の SMART デプロイ、 S2Dao とは相性が悪い DI コンテナ、フレームワーク側が頑張ればなんとかなるのでは?

3. 日本のビジネスはデータと振舞を分けた方が自然にモデル化できる、という意見

たまたまそういう仕事が今 SI 業界で多いだけはないか? プロセス重視のドメイン(財務シミュレーション、生産ライン管理、給与計算など)でデータと振舞を分けるメリットはあるのか?

Page 20: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 20

Domain Model の作り方(作り方が分からないという方のために)

GRASP パターン( Craig Larman 『実践 UML 』) 情報エキスパート( Information Expert ) 生成者( Creator ) コントローラ( Controller ) 低結合性( Low Coupling ) 高凝集性( High Cohesion ) 多相性( Polymorphism ) でっち上げ( Pure Fabrication ) 間接化( Indirection ) バリエーション防護( Protected Variations )

この辺がとくに重要!

Page 21: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 21

とはいえ、そんなに複雑なビジネスロジックってあるの? 最近の Web アプリケーションは、ほとんどが CRUD処理のみ 「ドメインロジック層なんていらないじゃん」 画面や DB から直接作ってしまった方がいいのでは?

すべてをリッチにドメインモデリングする必要はない 私の経験だと、ロジックが複雑な部分はアプリ全体の 10%

くらい ビジネス的に重要な部分(=ロジックが複雑な部分)だけ、優秀なリソースを投入してきちんとモデリングすればいい

ロジックの薄い部分は手間を掛けず、ローコストに瞬殺する Transaction Script なり Active Record なりを使う 外注する パッケージ製品を買ってきて作らずに済ます

Page 22: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 22

とはいえ、そんなに複雑なビジネスロジックってあるの? (つづき) そもそもシステムが頭を使っていないからではない

か? Web CRUD なアプリは、結局オペレータが頭を使っている 戦略的なシステムは、もっと頭を使うはず

ドメインリッチなシステムは省人化を進める 今まで人間がやっていた業務をシステムが肩代わりする 会社の最適化に貢献するが、従業員削減にもつながってしま

う 従業員からすると好ましくないシステム 強い権限をもつ CIO がトップダウンにやらないと難しい

リストラが当たり前の欧米(?)でドメインモデルが流行って、日本でなかなか流行らない理由の 1 つ?

Page 23: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 23

余談

Page 24: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 24

DAOと O/Rマッパの違い

DAO ロジックに対して DB ゲー

トウェイの役割をするもの ロジックが DAO を呼び出す

O/R マッパ ドメインオブジェクトと DB

とをマッピングするもの ドメインオブジェクトは O/

R マッパと DB の存在を知らなくていい

DAOロジック

エンティティ

O/Rマッパ

ドメインオブジェクト

サービス

Page 25: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 25

Hibernate / JPAの間違った使い方 Hibernate / JPA は、本来 O/R マッパ なのに、 DAO の実装に使ってしまうことがよ

くある

DAOロジック

エンティティ

Hibernate

Page 26: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 26

第Ⅱ部ドメイン駆動設計の紹介

Page 27: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 27

『 Domain-Driven Design 』( Eric Evans著) 一冊まるまる「ドメインモデ

リング」について扱った書籍 「ソフトウェアの真の複雑さに挑戦する」

パターン本の 1 つ 40 パターン+ 1 アンチパターン

海外では大ブームに Ralph Johnson ( GoF の 1人):「 4 、 5 回は読み直した」

Rod Johnson ( Spring創始者):「 Java開発のこれからはリッチドメインモデルだ」

Page 28: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 28

ドメイン駆動設計とはなにか

ドメインモデルを中心にすえた設計思想 ドメインモデルはドメイン知識を深めながら反復的( iterative )に設計していく

ドメインモデルを開発者とユーザ・専門家の間の共通言語に

ドメインモデル⇔実装コード(や他の成果物)の対応関係を最後まで維持する

Page 29: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 29

DDD 本の構成

I. DDD の基本思想 DDD の基本的な考え方や前提

II. モデル駆動設計( MDD )の構成要素 MDD を実現する OO ベストプラクティス。既にあるド

メインモデルをいかにソフトウェア設計に落とし込むか

III. ドメインリファクタリング ドメインモデルにドメイン知識を反映させ、より深いモ

デルにしていくためのノウハウ

IV. 戦略的デザイン 1 アプリの範囲を超えて、大規模開発/ SOA に DDD を

適用していく方法

Page 30: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 30

MDD実践的

モデラーユビキタス言語

DDD の基本思想

基本要素

ライフサイクル

深いモデル + しなやかな設計

制約 プロセス 仕様 抽象化 分割

コンテキストマッピング

ドメインの優先付け

「大きな絵」の共有

MDD の構成要素

ドメインリファクタリング

戦略的デザイン

単一アプリケーションの開発 大規模開発/ SOA

エンティティ値 サービス

モジュール

集約ファクトリ リポジトリ中核ドメイン

汎用サブドメイン

コンテキストマップ

継続的統合

メタファ

責務の階層

Page 31: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 31

Ⅰ. DDD の基本思想

ドメインモデルを、プロジェクトを駆動する「共通言語」にすること

DDD の基本三原則 Ubiquitous Language (ユビキタス言語)パター

ン Model-Driven Design (モデル駆動設計)パター

ン Hands-On Modeler (実践的モデラー)パターン

Page 32: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 32

Ⅱ. MDD の構成要素

これまでの OO 方法論の集大成 責務駆動設計( Responsibility-Driven Design ) 契約による設計( Design by Contract ) GRASP パターン エンタープライズアプリケーションアーキテク

チャパターン

Page 33: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 33

MDD を構成するパターン

まずドメイン層を分離する Layered Architecture (層状アーキテクチャ)パ

ターン Smart UI (利口な UI )アンチパターン

ソフトウェアによってモデルを表現する Entities (エンティティ)パターン Value Objects (値オブジェクト)パターン Services (サービス)パターン Modules (モジュール)パターン

Page 34: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 34

MDD を構成するパターン(つづき) ドメインオブジェクトのライフサイクルを

設計する Aggregates (集約)パターン Factories (ファクトリ)パターン Repositories (リポジトリ)パターン

Page 35: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 35

Ⅲ. ドメインリファクタリング

現実のドメインモデリングは古典的 OO 方法論が教えるほど単純ではない ( × )「名詞をクラスにして、動詞をメソッドにする」 反復的にモデルを深めていく必要がある

リファクタリングの 3 つのレベル マイクロリファクタリング パターン指向リファクタリング ドメインリファクタリング

ドメインリファクタリングの 2 つの柱 深いモデル( deep model ) しなやかな設計( supple design )

Page 36: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 36

深いモデル

隠れた概念を発掘する 見つけづらい概念には、以下がある

制約 プロセス 仕様

Specifications (仕様)パターン

Page 37: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 37

しなやかな設計

理解を容易にする抽象化 Intention-Revealing Interfaces (意図の明白なイ

ンタフェース)パターン Side-Effect-Free Functions (副作用のない関数)

パターン Assertions (表明)パターン

変更しやすい適切な分割 Conceptual Contours (概念の輪郭)パターン Standalone Classes (独立したクラス群)パター

ン Closures of Operations (閉じた操作)パターン

Page 38: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 38

Ⅳ. 戦略的デザイン

単一アプリの枠組みを超えたシステム構築 大規模開発や EAI 、 SOA の世界 企業情報システムの全体構造( EA )に深く関係する 経営戦略的( strategic )な視点が求められる

全企業的な視野においても、ドメインを深く反映したシステムこそが大きなビジネス価値につながる

「戦略的デザイン」の構成 コンテキスト( context ) 蒸留( distillation ) 大規模な構造( large-scale structure )

Page 39: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 39

コンテキスト-他システムとの統合

システム統合における課題 異なるドメインモデル間の不整合をいかに解決

するか コンテキストの境界を定める

Bounded Context (コンテキスト境界)パターン Continuous Integration (継続的な統合)パター

ン Context Map (コンテキストマップ)パターン

Page 40: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 40

コンテキスト-他システムとの統合(つづき) コンテキスト間の 6 つの関係

Shared Kernel (共有カーネル)パターン Customer/Supplier Development Teams (顧客/供給者の開発チーム)パターン

Conformist (順応者)パターン Anticorruption Layer (腐敗防止層)パターン Separate Ways (別々の道)パターン Open Host Service (公開ホストサービス)パ

ターン

Page 41: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 41

コンテキスト-他システムとの統合(つづき) 補足的なパターン

Published Language (公表された言語)パターン

Page 42: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 42

蒸留-戦略的な優先付け

企業のコアコンピタンス(競争力)をいかに向上させるか 限りあるリソースをどこに投入するかが大きな課題

ドメインの優先順位付け Core Domain (中核ドメイン)パターン Generic Subdomains (汎用サブドメイン)パ

ターン

Page 43: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 43

蒸留-戦略的な優先付け(つづき) 中核ドメインの文書化方法

Domain Vision Statement (ドメインビジョン説明書)パターン

Highlighted Core (中核のハイライト)パターン 中核をさらに中核らしく磨き上げる

Cohesive Mechanisms (凝集されたメカニズム)パターン

Segregated Core (中核の隔離)パターン Abstract Core (中核の抽象化)パターン

Page 44: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 44

大規模な構造-「大きな絵」の共有

大規模システムの開発をいかに成功させるか チームがアーキテクチャレベルの「大きな絵」

を共有し、同じ目標意識をもって協調することが肝心

大規模な構造を扱う際の基本姿勢 Evolving Order (進化則)パターン

Page 45: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 45

大規模な構造-「大きな絵」の共有(つづき) 大規模な構造の 3 つのパターン

System Metaphor (システムのメタファ)パターン

Responsibility Layers (責務の階層構造)パターン

Knowledge Level (知識レベル)パターン 幸福な DDD の最終形態

Pluggable Component Framework (可換コンポーネントフレームワーク)パターン

Page 46: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 46

最後に

Page 47: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 47

なぜドメインモデルなのか?

それはドメインモデルが楽しいから! (がんばれば)複雑なシステムでもきれいに構築可能 オブジェクトという部品を使ってモノづくりする楽しさ

自分が作ったシステムの形を視覚的に実感できる トランザクションスクリプトより、なんか作ってて楽しい

結局、 Ruby でプログラミングするのがなぜか楽しいのと同じことでは?

Page 48: ドメインロジックの実装方法とドメイン駆動設計

2008/03/28 BPStudy 7第 回 48

ドメインモデル作りを楽しみましょう!