83
ドメイン駆動設計 powered by Spring

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

  • Upload
    -

  • View
    5.301

  • Download
    13

Embed Size (px)

Citation preview

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

ドメイン駆動設計powered by Spring

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

ドメインロジックに集中せよ

2017年3月28日ギルドワークス 増田

focus on domain logic

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

ドメイン駆動設計Domain-Driven Design

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

ソフトウェアの核心にある複雑さに立ち向う

Tackling Complexity in the Heart of Software

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

複雑さという課題The Challenge of Complexity

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

設計を複雑にする要因

技術的な複雑さ

ドメインの複雑さ

ネットワーク、データベースなど基盤となる技術の複雑さ

ドメイン(対象領域)のユーザの活動やビジネスの複雑さ

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

設計を複雑にする要因

技術的な複雑さ

ドメインの複雑さ

ネットワーク、データベースなど基盤となる技術の複雑さ

ドメイン(対象領域)のユーザの活動やビジネスの複雑さ

重要な課題は、ドメインの複雑さユーザの活動やビジネスそのものがもつ複雑さ

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

ドメインロジックに集中する

ビジネスルール

ドメインロジック

分析の対象

実装の対象

遵守すべき約束事外部:契約、商習慣、法令、…内部:社内規定、予算、しきたり、…

ビジネスルールのサブセットプログラミング言語で記述

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

ドメインロジックに集中する

ビジネスルール

ドメインロジック

分析の対象

実装の対象

遵守すべき約束事外部と:契約、商習慣、法令、…社内で:予算、計画、規定、しきたり、…

ビジネスルールのサブセットプログラミング言語で記述

アプリケーションが使われる領域(現実世界)の約束事を理解するシステム化の対象となるビジネスルールを特定する

それをプログラミング言語で表現する

その活動に集中する

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

情報収集 分析・整理

ヒヤリングQ&A

ユーザストーリ画面の紙芝居システム企画書

既存の帳票/ファイル既存の画面

既存のデータベース

仕様 実装設計

画面一覧機能一覧

項目定義処理詳細

モデルを使わない開発プロセス

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

情報収集 分析・整理

ヒヤリングQ&A

ユーザストーリ画面の紙芝居システム企画書

既存の帳票/ファイル既存の画面

既存のデータベース

仕様 実装設計

画面一覧機能一覧

項目定義処理詳細

モデルを使わない開発プロセス

ドメインモデルを一切もたずバックログ(機能一覧、画面一覧)をとにかく消化する開発

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

情報収集 分析・整理

ヒヤリングQ&A

ユーザストーリ画面の紙芝居システム企画書

既存の帳票/ファイル既存の画面

既存のデータベース

仕様 実装設計

画面一覧機能一覧

項目定義処理詳細

ビジネスルール

モデル

現実を単純化した模型の導入

全体の見通しが良くなるムリ・ムダ・ムラが減る

モデリング作業が増える

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

フェーズに分ける開発

情報収集

分析・整理

基本設計

詳細設計

運用

実装

based on out-of-date assumptions

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

フェーズに分ける開発

情報収集

分析・整理

基本設計

詳細設計

運用

実装

based on out-of-date assumptions

担当者が変わる → 伝言ゲーム

1方向の活動 → 誤りがあっても是正されない(後ろにいくほどつじつま合わせが多発)

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

インクリメンタルな開発

情報収集

分析・整理

基本設計

詳細設計

運用

実装

step-by-step, in small pieces, based on real-life experience

day-1 day-2 day-3 …

同じメンバーが担当すべてが発展途上変化への機敏な対応創発性(ブレークスルー)

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

ステキなお知らせ

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

核心にある複雑さに立ち向かう

強力な援軍

Spring FrameworkSpring Boot

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

Spring Frameworkドメインとドメインロジックに集中できる

ドメインモデリングに時間を割ける

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

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 入門

配管

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

Spring Boot本来のアプリケーション開発をすぐ始められる

day-1 からプロダクションレベルで運用できる

インクリメンタルな開発を実践できる

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

残念なお知らせ

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

Spring FrameworkSpring Boot

こんな開発にも使えます…

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

ドメインとドメインロジックに技術課題に集中する

モデルに基づき設計するバックログをせっせと消化する

インクリメンタルな設計フェーズに分けて伝言ゲーム基盤とアプリで別チーム

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

ドメイン駆動設計powered by Spring

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

アンチパターンドメインロジック以外に焦点をあてるドメインモデルなしに機能一覧バックログを消化

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

プレゼンテーション層

データソース層

アプリケーション層

画面の入出力

データベースの入出力

データベースの更新・参照の手続き

データの加工ロジックデータの検証ロジック

データの判断/加工/計算

書き込みの前処理ロジック読み出しの後処理ロジック

データ処理に焦点をあてる

@Controller

@Service

@Repository

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

プレゼンテーション層

データソース層

アプリケーション層

ドメインを隔離する

@Controller

@Service

@Repository

ドメインモデル

ここをインクリメンタルに成長させながら

全体の開発を駆動する

ドメインロジックをここに集約する

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

ドメインモデルAn object model of the domain that incorporates

both behavior and data

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

ドメインモデル

ドメインロジックをオブジェクトで表現する

model elements expressed as objects

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

ドメインモデルだと何が良いのか?

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

変更が楽で安全

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

ドメインモデル:変更容易性

ドメインロジックが重複しない

ロジックを書いてある箇所の特定が簡単

変更の影響を狭い範囲に限定できる

データを持つクラスが唯一のロジックを持つ

パッケージ名→クラス名

変更したクラスに閉じるせいぜい、そのクラスを使うクラスまで

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

トランザクションスクリプト

ドメインロジックが重複しない

同じロジックが重複する

ロジックを書いてある箇所の特定が簡単

データ処理の流れを追いかけて探し回る

変更の影響を狭い範囲に限定できる

変更箇所の後続処理をすべて追いかける

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

ドメインオブジェクト設計パターン

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

ドメインロジック

ビジネスルール

ドメインロジック

分析の対象

実装の対象

遵守すべき約束事外部:契約、商習慣、法令、…内部:社内規定、予算、しきたり、…

ビジネスルールのサブセットプログラミング言語で記述

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

ドメインロジックの最小単位

数値

日付

文字列

数量、金額、…

予定日、締日、…

演算の対象 演算(判断/加工/計算)のパターン

識別コード/識別名分類コード/分類名

等値の判定

大小判定/順序付け

四則演算

換算

範囲内/範囲外の判定

型変換(文字列表現から)

型変換(文字列表現へ)

有効要素の判定

==, equals(), …

<,>, compareTo(), …

MIN,MAX, ….

contains(), has(), …

of(), parse(), …

toString(), asText(), …

+-*/, plus(), minus(), …

inThousand(), inPieces(),

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

値オブジェクト

コレクションオブジェクト

区分オブジェクト

ドメインロジックの置き場所基本パターン

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

値オブジェクト

BigDecimalInteger…

LocalDateLong

起算日 InitialDate期限 DueDate有効期間 ValidTerm

金額 Money数量 Quantity単位 Unit

言語で用意された汎用の「型」独自に定義したドメイン固有の「型」判断/加工/計算ロジックの置き場所

45

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

コレクションオブジェクト(ファーストクラスコレクション)

• ListやSetをラップしたドメインオブジェクト

• 「一覧」「履歴」という関心事• 一覧の検索条件、表示項目、表示順の議論は、重要な関心事の発見につながる

• コレクション操作はコードがごちゃごちゃする• 変更の副作用が多い

• クラスとして独立させ、そのクラスにコレクション操作のロジックを閉じ込める• count(), contains()

• select(), reject()

• convertTo()

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

区分オブジェクト

• 振る舞いを持った Enum• 区分ごとのロジックを別クラスに記述• Java言語仕様に組み込まれた

Strategy/Stateパターン• if 文/switch文を書かない工夫

説明とコード例は、googleで「場合わけの書き方あれこれ」で検索、または技術評論社ムック本「オブジェクト指向をきちんと使いたいあなたへ」

場合ごとのドメインロジックを表現する道具

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

モジュール化

構造化

自己文書化

ドメインオブジェクト:設計原則

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

モジュール化

構造化

自己文書化

ドメインオブジェクト

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

モジュール化

複雑さに立ち向かうための工夫

プログラムを

開発/保守がやりやすい単位に分割する

部品化

組み立て

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

ドメインロジックのモジュール化ドメインモデル

(オブジェクトモデル)トランザクションスクリプト

(手続きモデル)

アプローチ関連するデータとロジックを

一体にするデータクラスと機能クラスに

分ける

モジュール分割の単位

関心事(数量、金額、納期、締日、…)

値オブジェクトなどドメインロジックの

部品化のパターンが明確

機能(受注登録、注文変更、…)

サブルーチン化が不明確大きなデータクラスと長いメソッドになりがち

ロジックの再利用

ドメインオブジェクトとして部品化ドメインオブジェクトの

組み合わせで機能を実現

部品化が進まないロジックの再利用がしにくい

コードの重複

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

モジュール化

構造化

自己文書化

ドメインオブジェクト

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

ドメインロジックの構造化

複雑さに立ち向かうために

記述レベルを階層化する

コンピュータよりの記述から

人間よりの記述へ

段階的に近づける

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

構造化:記述レベルの階層化

業務で使う用語

期日数量金額消費税

キャンセル規定順番待ち商品リスト在庫一覧

ドメイン固有API

ExpireDateQuantityAmountTaxAmount

OverBookingPolicyWaitingListCatalogueInventory

JavaコアAPIBigDecimalLocalDateList,Set,Map

PredicateStream/Collectors

Java言語仕様int , charint[], char[]String , Enum

if , for

機械

ドメイン固有APIのレイヤを追加する

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

モジュール化

構造化

自己文書化

ドメインオブジェクト

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

ドメインロジックの自己文書化

複雑さに立ち向かうために

コードにドメインロジックを語らせる

(自己文書化)

パッケージ名/クラス名/メソッド名

メソッドの返す型

引数の型

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

ドメインロジックの自己文書化

ドメインオブジェクトを参照する他の三層のコード

ドメインロジックとの関係性を語るようになる

(ドメインモデルの自己文書化が他の三層に波及する)

ソースコード以外の文書化

業務マニュアル<重要>

利用者ガイド <重要>

開発・保守ドキュメント <不要>

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

モジュール化

構造化

自己文書化

ドメインオブジェクト:設計原則

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

ドメインオブジェクトの設計レビュー

ドメインロジック記述の怪しい臭い

else句switch文boolean宣言

判断ロジックの不適切な置き場所判断ロジックの不要な複雑化

定数宣言だけの enum 区分ごとのロジックの置き場書が不適切

Streamドメインロジックの暗黙化(判断/加工の隠蔽)ドメインロジックの重複

5行以上のメソッドドメインロジックの暗黙化ドメインロジックの重複

3つ以上のフィールド クラスの凝集度の低下(関心事の発散)

ラムダ記法(無名関数) ドメインロジックの暗黙化

メソッドチェイン ドメインロジックの暗黙化

モジュール化/構造化/自己文書化の原則違反の臭い

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

ドメインを隔離するIsolating the Domain

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

プレゼンテーション層

データソース層

アプリケーション層

ドメインを隔離する

@Controller

@Service

@Repository

ドメインモデル

ここをインクリメンタルに成長させながら

全体の開発を駆動する

ドメインロジックをここに集約する

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

ドメインを隔離する

データの入出力

画面データベース

ドメインモデル

ドメインロジックのオブジェクト表現

画面やデータベースの都合を、ドメインモデルに持ち込まないこと

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

ドメインを隔離する

画面やデータベースの都合をドメインモデルに持ち込まない

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

プレゼンテーション層とドメインオブジェクト

Spring MVC

Thymeleaf

Spring Security

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

プレゼンテーション層

@Controller

ドメインモデル

ドメインモデルに依存させる

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

プレゼンテーション層

ドメインオブジェクトを直接使う

プレゼンテーション層の記述を

ドメインモデルに依存させる

プレゼンテーション層に

判断/加工/計算のロジックを書かない

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

プレゼンテーション層

HTTP リクエスト→ ドメインオブジェクト

DirectFieldAccess

ドメインオブジェクト→ HTTPレスポンス

HTML テンプレート ( Thymeleaf )

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

@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";

}

}

ドメインオブジェクトを直接使う

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

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 で検索

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

アプリケーション層とドメインオブジェクト

@Service

@Validated

ドメインの関心事としてのデータフロー

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

プレゼンテーション層

データソース層

アプリケーション層

@Controller

@Service

@Repository

ドメインモデル

業務の関心事としての入出力

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

サービスクラス

@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より表現力が豊か

ドメインの関心事としてのデータ入出力

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

ドメインの関心事としての入出力interface PersonRepository {

void register(Person person);

List<Person> listOf(Criteria criteria);

}

ドメインの関心事:モデルの一部としてインタフェース宣言記録/参照(Repository インタフェース)

通知 (Transfer インタフェース)

データベースの都合をドメインオブジェクトに持ち込まないインタフェースで実装を分離する

依存性の逆転データソース層がドメインモデルに依存する

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

データソース層とドメインオブジェクト

@Repository

MyBatis SQL mapping

Transfer interface

RestTemplate

JmsTemplate

MailSender

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

データソース層

@Repository

ドメインモデル

オブジェクトとテーブル異なる世界のマッピング

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

データソース層

オブジェクトとテーブル

異なる世界を明示的にマッピング

ドメインオブジェクトはロジックの置き場所

テーブルの構造を持ち込まない

テーブルは事実を正しく記録するために

徹底的に正規化する

(Not Null制約、一意制約、参照制約)

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

データソースの実装

@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);

}

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

データソースの実装

<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クラスに明示的にマッピングする

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

プレゼンテーション層

データソース層

アプリケーション層

ドメインを隔離する

@Controller

@Service

@Repository

ドメインモデル

ここをインクリメンタルに成長させながら

全体の開発を駆動する

ドメインロジックをここに集約する

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

ドメイン駆動設計Domain-Driven Design

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

ソフトウェアの核心にある複雑さに立ち向う

Tackling Complexity in the Heart of Software

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

ドメインロジックに集中する

モデルに基づき設計する

インクリメンタルに開発する

核心にある複雑さに立ち向う

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

ドメイン駆動設計powered by Spring