【jjug ccc 2016 fall 公開版】ドメイン駆動設計とscala...

100
ドメイン駆動設計とScala 〜既存プロジェクトへの適用〜 Fumiyasu Sumiya

Upload: fumiyasu-sumiya

Post on 06-Jan-2017

412 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメイン駆動設計とScala〜既存プロジェクトへの適用〜

Fumiyasu Sumiya

Page 2: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

対象・目的既存プロジェクトにDDDを適用させてカオスからの脱却

と、Scalaの紹介

Page 3: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

アジェンダ

1. 自己紹介

2. HRMOS紹介

3. 本編

4. 締め

3

Page 4: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

アジェンダ

1. 自己紹介

2. HRMOS紹介

3. 本編

4. 締め

4

Page 5: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

自己紹介

5

角谷 文康(すみや ふみやす) @FScoward

■ 略歴

2011年4月 ~ 2015年7月

TIS株式会社にてクレジットカードシステムの保守開発・新規開発などに従事

- 2014年2月 デブサミ2014登壇

2015年8月

株式会社ビズリーチ入社

2015年8月 ~ 2015年12月

スタンバイ のサーバーサイドエンジニア

2016年1月 ~ 現在

HRMOS採用管理 のサーバーサイドエンジニア

2016年12月3日

JJUG CCC

■ 好きなもの

スフィア、乃木坂46、欅坂46

Page 6: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

アジェンダ

1. 自己紹介

2. HRMOS紹介

3. 本編

4. 締め

6

Page 7: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

7

https://www.hrmos.co/

HRMOS紹介

Page 8: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

アジェンダ

1. 自己紹介

2. HRMOS紹介

3. 本編

4. 締め

8

Page 9: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

2016年1月~HRMOS採用管理に参画

この時点でかなり、モノとして形になっていた

スピード重視の開発

HRMOSへの参画

9

Page 10: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメイン駆動設計は取り入れていなかった

機能追加しようとするとかなり作りが 複雑になっている部分があって、精神的に 辛い

部分があった

今後どんどんと機能追加して使いやすくしていかなければならない

HRMOS採用管理システム

10

Page 11: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

今後もどんどん機能追加を行っていく必要があるので、なんとかして 複雑性に立ち向

かわなければならない

HRMOS採用管理システム(課題)

11

Page 12: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

今後のためにも最低限整備しておかないとまずい

Page 13: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

実装の複雑性をどうしようか

Page 14: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

複雑性に立ち向かう

Page 15: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

HRMOS採用管理システム(課題)

Page 16: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
Page 17: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
Page 18: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

DDD!!!

18

Page 19: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

複雑性はどこから?

19

多くのアプリケーションにおいて、最も重要な複雑さは、技術的なものではない。 複雑

なのはドメインそのもの、すなわち、ユーザの活動やビジネス なのである。ドメインの

持つこの複雑さが設計で扱われないのであれば、基盤となる技術が適切に考えられ

ていたとしても意味がない。設計を成功させるためには、ソフトウェアにおけるこの中

心的な側面を、体系的に扱わなければならない。

エリック・エヴァンスのドメイン駆動設計 まえがき 複雑さという課題

Page 20: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

20

設計の時点でスパゲッティコードは運命づけられている

Page 21: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Why DDD?

21

ドメイン意識

なんちゃらServiceにビジネスロジックをまとめ、ごちゃごちゃして複雑になり、

肥大化していってしまうのを防ぐことが出来る

常にドメインモデルを意識した設計を行うので、行き過ぎた単純化・汎用化を

防ぐことが出来る

複雑性に立ち向かう

責務を明確にドメインモデルに正しく処理をもたせるため、誰が何をするのかが明確になる

(処理が各所に散らばらない)

Page 22: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Why DDD?

機能実現のためのコード(ソフトウェアの関心事)とビジネスロジック(ドメインの

関心事)は綺麗に分離されていないと、機能追加やバグ修正の時に非常につ

らい思いをする。

22

設計思想の統一思想がないと実装者、レビュワーによってコードの実装に偏りが生じる

※ 毎回全員がレビューしてるなら別

ビジネスロジックへの集中

ScalaとDDDは相性がいいらしい

某社はDDDをやりやすくするためにScalaを使ったらしい

Page 23: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Why DDD?(精神面)

■ 「ソフトウェアの核心にある複雑性に立ち向かう」 ← かっこいい

■ SIerに居た頃は業務がどうなってようが、知ったこっちゃない。言われたと

おりに動くものが作れればOKという感じだったが、それが嫌になって事業

会社に転職したので、きちんと業務を理解して、あるべき姿のきれいなシス

テム作りをしたかった

■ 我々”一般的な”技術者が解決しなければならないのは技術的問題の前

に、ビジネスの問題であるということを認識しなければならない。

23

Page 24: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Scalaでドメイン駆動設計?

24

■ Scalaは静的型付け言語なのでドメイン駆動設計と相性がいい(と個人的に

は思っている)

■ ちなみにEric Evans本人はRubyが相性が良いかもねと言っている。

● https://www.infoq.com/jp/articles/eric-evans-ddd-matters-today

● 理由としてはrubyがドメイン固有言語(DomainSpecificLanguage)を簡単に作成できる点にあ

る。

● ドメイン駆動での開発はDSLでメタプログラミングでシステムを作ることなのかもしれない。

● DSLについて語るつもりはない(というか語れるほど詳しくない)ので、各自調べてみてくださ

い。

● http://www.slideshare.net/yizawa/rubydsl-25541986

Page 25: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

■ 巨大なモデルが存在(一つのclassでデータ持ちすぎ)

● 大きすぎる集約

■ どのモデルが一体何のためのモデルなのかが明確になっていない

● フロントエンドから受ける/返すためのモデル

● ドメインモデル

● 日付を表すようなYearMonthDateというクラスなどもあったがドメインモデルではない

■ ドメインモデル貧血症に陥っている

● モデルはメソッドをほぼ持っていない

● XXService, XXUtil にビジネスロジックが散らばっている

● ソフトウェアの関心事とビジネスの関心事の分離が出来ていないため処理が複雑に

HRMOS採用管理での問題点

25

Page 26: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルとの戦い

26

■ 例えばApplicationと名のつくクラスがいっぱい

Page 27: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルとの戦い

27

■ ApplicationInfoという巨大モデル

■ 応募者を表すモデル

■ なぜか求人情報を持っている

■ なぜか面接情報を持っている

■ しかもこの面接情報のなかには面接評価もある

■ これが内部で使いまわされている

■ しかもこいつはメソッドを持っていない

■ このクラスでフロントエンドへ返している

Page 28: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

HRMOSの問題

28

1. モデルの定義がぐちゃぐちゃ

2. 大きすぎる集約

3. ドメインモデル貧血症

Page 29: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルの再定義

29

まずはユビキタス言語が適切に定義されているかを今一度確認しておく

Page 30: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

1. ユビキタス言語

Domain Driven Design

Page 31: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ユビキタス言語とは

31

業務領域についてよく知った人との会話においても お互いに齟齬なく情報を伝え合う

ために用いることが出来る言葉を定義したもの。

システム開発においては、情報伝達の齟齬が発生しておかしなシステムをつくり上げ

ることがままあるが、こういった齟齬をなくすためのプロダクトに関わる全員とスムーズ

に会話を行うための言語のことを作り上げることをやっておく必要がある。

Page 32: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ユビキタス言語の作成

32

まずはドメインエキスパートとじっくりと会話をしてお互いのことばが滑らかに立ち止ま

ることなく進むようにお互いの ことばによる理解の齟齬をなくすことを目的として作成

する。

世間一般で通じる言葉を用いる必要はなく、 境界づけられたコンテキスト 内で通じる言

葉が出来ればいい

※ ドメインエキスパート とは、業務領域についての深い知識を持っている人物のこと

であって必ずしも役職者ではない。

Page 33: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ユビキタス言語の作成

33

ドメインエキスパートは専門的な用語を用いて語りがちだが、それが本当に求めてい

るものを表しているとは限らない

そういった齟齬をなるべく減らすために自分たちで 言葉を再定義する必要がある

チーム全員がその言葉を聞いて勘違いすることなく、同じ物事を思い浮かべることが

出来るまで言葉を洗練するのが重要

Page 34: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

2. 境界づけられたコンテキスト

Domain Driven Design

Page 35: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

境界づけられたコンテキスト

35

コンテキストとは、Wikipediaを見ると以下のように定義されています。>言語学におけるコンテクストとは、メッセージ(例えば1つの文)の意味、メッセージとメッセージの関係、言語が発せられた場所や時代の社会環境、

言語伝達に関連するあらゆる知覚を意味し、コミュニケーションの場で使用される言葉や表現を定義付ける背景や状況そのものを指す。 例えば日本

語で会話をする2者が「ママ」について話をしている時に、その2者の立場、関係性、前後の会話によって「ママ」の意味は異なる。2人が兄弟なのであ

れば自分達の母親についての話であろうし、クラブホステス同士の会話であれば店の女主人のことを指すであろう 。このように相対的に定義が異な

る言葉の場合は、コミュニケーションをとる2者の間でその関係性、背景や状況に対する認識が共有・同意されていなければ会話が成立しない。この

ような、コミュニケーションを成立させる共有情報をコンテクスト という。

>マーケティングの方法論として、顧客の背景を理解・把握したうえで、それに沿った商品プロモーションを行うことを「コンテクスト・マーケティング」と

呼ぶ。

>情報工学におけるコンテキストは、デバイスが使われている状況を意味する。例えばある時点でデバイスを使用しているユーザーなど。コンテキス

トアウェアネスおよびコンテキストスイッチを参照されたい。

>人工知能におけるコンテキストは、意思伝達、言語学、形而上学などに属する部分と深い関係がある。自動的な推論を使ってそれらの観点が如何

にしてコンピュータシステム上でモデル化できるかは、人工知能の研究テーマの1つである。

>シチュエーション・コメディにおけるコンテクストとは、そのショーが公開されている時代背景やその時点の社会の出来事などを意味する。例えば、"I

love Lucy"には1950年代のアメリカのコンテクストが反映されている。

>心理学におけるコンテクストとは、フォアグラウンドの事象に伴うバックグラウンドの刺激を意味する。例えば、ネズミがネコを恐れながらエサを探し

ているとき、ネコがフォアグラウンドの事象であり、探し回っている場所(および時間)がバックグラウンドの刺激である。海馬にはある種のコンテクスト

処理に特化した神経構造があると考えられている。

Page 36: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

境界づけられたコンテキスト

36

対象とする範囲が異なればドメインモデルは意味をなさなくなるということがわかる。

なので、初めに自分たちの定めようとするドメインモデルがどのコンテキストに属する

ものなのかをきちんと定義する必要がある。

Page 37: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインを見つけ出し、境界づける

37

自分たちの行う事業の ドメインは一体何なのか

採用管理、勤怠管理、評価管理...etc

それぞれ明確な境界があり、採用管理コンテキスト、勤怠管理コンテキストと言った、

各コンテキストを境界づけることが出来る。

Page 38: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

コンテキストマップ

38

コンテキストマップと呼ばれる図を描くことで、それぞれのドメインが担うべき役割を明

確に分けることができて、ドメインモデルがどこに属するかを端的に表すことが出来る

※「境界づける」というのはドメインモデルに明確に区別をつけてドメインモデルを 共有

しないということ

Page 39: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

コンテキストマップ

39

モデルが適用されるコンテキストを明示的に定義すること。明示的な境界は、チーム

編成、そのアプリケーションに特有の部分が持つ用途、コードベースやデータベース

スキーマなどの物理的な表現などの観点から設定 すること。その境界内では、モデル

を厳密に一貫性のあるものに保つこと。ただし、境界の外部の問題によって注意を逸

らされたり、混乱させられたりするのを避けること。

エリック・エヴァンスのドメイン駆動設計 第14章 モデルの整合性を維持する p.344

Page 40: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

境界づけられたコンテキスト 超意訳ことばの定義、意味が変わらない範囲を定めること

Page 41: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

きつね?たぬき?

41

■ 関東のたぬきそば

■ 大阪の立ち食いそば屋のたぬきそば

Page 42: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

きつね?たぬき?

42

Wikipediaより

https://ja.wikipedia.org/wiki/%E3%81%9F%E3%81%AC%E3%81%8D_(%E9%BA%BA%E9%A1

%9E)

関東 関西

きつね 油揚げをのせたそば又はうどん(きつねうどん、きつねそば)

油揚げの甘煮をのせたうどん(けつね、しのだ)

たぬき 揚げ玉をのせたそば又はうどん(たぬきうどん、たぬきそば)

京都:刻んだ油揚げ[21]と青ねぎをあんかけにしたうどん又はそば大阪:油揚げの甘煮またはキザミをのせたそば

Page 43: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

きつね?たぬき?(ポルナレフ状態)

43

あ…ありのまま 今 起こった事を話すぜ!

「おれは 大阪の立ち食い蕎麦屋でたぬきそばを頼んだら

なぜか上に油揚げがのっていた」

な… 何を言っているのか わからねーと思うが 

おれも 何をされたのか わからなかった…

頭がどうにかなりそうだった… 催眠術だとか超スピードだと

そんなチャチなもんじゃあ 断じてねえ

もっと恐ろしいものの片鱗を 味わったぜ…

Page 44: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

HRMOSの問題

44

1. モデルの定義がぐちゃぐちゃ

2. 大きすぎる集約

3. ドメインモデル貧血症

なぜモデルの定義がぐちゃぐちゃになってしまうのか

Page 45: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルの定義がぐちゃぐちゃ

45

■ Applicationと名のつくクラスがいっぱい

Page 46: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルの定義がぐちゃぐちゃ

46

■ ApplicationInfoという巨大モデル

■ 応募者を表すモデル

■ なぜか求人情報を持っている

■ なぜか面接情報を持っている

■ しかもこの面接情報のなかには面接評価もある

■ これが内部で使いまわされている

■ しかもこいつはメソッドを持っていない

■ このクラスでフロントエンドへ返している

Page 47: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

モデルを明確に分けていない

47

リクエストを受け付けたときのモデルなのか、ドメインモデルなのか、レスポンス用の

モデルなのかがわけられておらず、無法地帯になってしまっている。

そこで、パッケージによる手助けをして解決を目指す。

Page 48: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

パッケージ分けによるサポート

48

■ controller - コントローラー層 Inputの変換を行う

● model - データを受けとるためのモデル

■ presenter - プレゼンター層 Outputへの変換を行う

● model - データを返すためのモデル

■ application - アプリケーション層

● service - 調整役。処理の振り分けを行う。 トランザクション制御 もここ。ドメインロジックは存在しては

ならない。

■ domain - ドメイン層

● model - ドメインモデル。packageで集約をまとめる。ドメインロジックを記

● service - エンティティや値オブジェクトで行うには 不自然なビジネスロジックを記述

■ infrastructure - インフラ層

● repository - 永続化についての責務を負う

■ gateway - ゲートウェイ層。 外部サービスとのやり取りを行う。外部のメールサービスとか

■ util - ユーティリティ

Page 49: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

引用 - http://qiita.com/kondei/items/41c28674c1bfd4156186

Page 50: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

3. ドメインモデルを見つけ出す

Domain Driven Design

Page 51: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルを見つけ出す

51

ユビキタス言語が作れたらあとは見つけ出した ことばたちをドメインモデルとして落と

し込むだけ

Page 52: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルに落とし込む

52

1. エンティティ(Entity)

2. バリューオブジェクト(ValueObject)

3. 集約(Aggregate)

これら3つの概念を押さえておく必要がある

Page 53: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルに落とし込む

53

1. エンティティ(Entity)

2. バリューオブジェクト(ValueObject)

3. 集約(Aggregate)

Entityとは

Page 54: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Entity

54

■ Entityは(同一性を)識別することが必要となるモデルのこと● 簡単に言うと他と区別するためのIDを持たせて管理するということ

■ 同一性を担保出来れば識別子はなんでも良い

Page 55: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

55

Entity

田中太郎くん(10歳)と6年後の田中太郎くん(16歳)は同一人物

年齢などの属性が異なるだけ

田中太郎くん(10)田中太郎くん(16)

Page 56: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

56

同一性を担保する識別子は何か

名前?年齢?性別?

名前+年齢?名前+年齢+性別?

田中太郎くん(10) 田中太郎くん(16) 里中太郎くん(27)

Page 57: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

57

同一性を担保する識別子は何か

識別子は国民総背番号「行政手続における特定の個人を識別するための番号の利

用等に関する法律」で定められたマイナンバー

Page 58: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルに落とし込む

58

1. エンティティ(Entity)

2. バリューオブジェクト(ValueObject)

3. 集約(Aggregate)

バリューオブジェクトとは

Page 59: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ValueObject

59

■ イミュータブルに保つ(状態を管理しない)値

■ 状態を持たないオブジェクトとすることで、複雑性の排除に役立つ

Page 60: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Scala講座

■ Scalaでは値は基本的にval(イミュータブル)で宣言するのでValueObjectで

あることを担保しやすくなっている● ※ var(ミュータブル)で宣言も可能

■ case classもイミュータブル

60

Page 61: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Scala講座 〜 case class について 〜

61

Scalaでは case class というものがつくれて宣言が簡単になる

Page 62: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ValueObject 例え話

62

■ 誕生日をどう表すか

■ 単純にDate型で表すのかBirthDate型を作るか

■ Dateでやると年齢を別の場所で算出しなければならない● HRMOS採用管理ではUtilでやっていた

■ BirthDateを用意してcalcAgeのようなメソッドを用意してやったほうが良い

Page 63: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

BirthDateというValueObject

Page 64: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Entity / ValueObject 例え話

64

■ 同姓同名の人がいたとしてもそれは別人なので、”人”としてはきちんと識

別する必要がある● case class Human (id: ID, name: Name, gender: Gender)

■ 一方で”名前”というオブジェクトに注目するとただの文字の羅列でしかな

いので、識別する必要はなく識別子を持たずにただの置き換え可能な値

(ValueObject)として扱えば良い

● case class Name(firstName: String, lastName: String)

Page 65: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

65

Entity / ValueObject 例え話国民を番号で管理するに当たって名前などを仔細に管理する必要はない

性別も名前も年齢もただの記号でしかないとすれば、 ValueObjectで良い

田中太郎くん(10)田中太郎くん(16)

Page 66: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

主体によってEntityとValueObjectは変化する

66

たとえばお札(千円札)

一般人にとっては千円のお札は千円でしかない(千円であると認識していれば良い)

ので、ValueObject

日本銀行からすればお札一枚一枚についてキチンと区別して管理する必要があるた

め、お札はEntity(識別子は「記番号」)

Page 67: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

一般人にとっての千円

Page 68: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

日本銀行にとっての千円 http://www.npb.go.jp/ja/intro/kihon/genzai.html

Page 69: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

日本銀行にとっての千円

Page 70: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルに落とし込む

70

1. エンティティ(Entity)

2. バリューオブジェクト(ValueObject)

3. 集約(Aggregate)

集約とは?

Page 71: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約(Aggregate)

71

■ エンティティのライフサイクルを同一にするものを集める集約は最小限に

■ keyword:

● トランザクション整合性

● 結果整合性

Page 72: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

エンティティのライフサイクル

72

エンティティと値オブジェクトを 集約の中にまとめ、各集約の周囲に境界を定義するこ

と。各集約に対してルートとなるエンティティを1つ選び、境界の内部に存在するオブ

ジェクトへのアクセスは、その ルートを経由して制御 すること。外部のオブジェクトが参

照を保持できるのは、ルートのみとすること。内部のメンバに対する一時的な参照を

渡して良いのは、単一の操作で使用する時だけだ。ルートがアクセスを制御するの

で、内部が知らないうちに変更されることはなくなる。この取り決めにより、どんな状態

変化においても、集約内にあるオブジェクトと集約全体に対して、不変条件をすべて

強制することが現実的になる。

(エリック・エヴァンスのドメイン駆動設計 p.127 第6章 ドメインオブジェクトのライフサ

イクル)

Page 73: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約

73

トランザクション整合性を保つ必要のあるエンティティたちを1つに 集約する。

集約の境界の外部は結果整合性を用いる。

E.g. 自動車(Entity)はタイヤ(Entity)、車輌(Entity)で構成される。

タイヤと車輌は自動車を構成するものであり、生成~破棄が同一のタイミングで行わ

れるものとすると、自動車(Entity)は 集約のルートエンティティとなる。

Page 74: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約のルール

74

集約内部のオブジェクトに対してアクセスしてよいのは集約の ルートのみ。

内部を変更したい場合には 必ず集約のルートを通して変更を行う こと。

Page 75: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約のルール(例)

75

車の速度を上げるのに、タイヤに対して速度を上げるように命令を出すのではなく、車

に対して速度を上げるように命令して、車がタイヤ(エンジン)の回転数を上げるように

する

Page 76: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約は非常に難しい

76

■ オブジェクトのライフサイクルに対する今までの考え方を捨てて集約につい

て向き合わなければならない

■ トランザクション整合性?結果整合性?

■ 全部含んで巨大な集約できちゃうよ・・・

Page 77: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約はなぜ難しいのか

77

■ ビジネス的なライフサイクル?

■ システム的なライフサイクル?

■ 頭のなかで概念が交錯する

Page 78: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

たとえば

78

自動車は車両、タイヤで構成されているが、エンジンも構成物のひとつ

ビジネス(ドメイン)の関心事として エンジンは生成から破棄までをキチンと管理したい

とすると、エンジンは自動車の集約の内部にあるべきだろうか?

自動車の生成〜破棄とエンジンの生成〜破棄は果たして同じ ライフサイクルだろう

か?

Page 79: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

たとえば

79

たとえば、面接と面接評価を考えてみる。

「面接」設定時点では「面接評価」自体は空なので ライフサイクルが違うように思える

が、「面接評価」はそもそも「面接」がないと存在し得ないので「面接」と「面接評価」は

同一の集約であり、「面接」は集約のルートになるかもしれない

Page 80: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

たとえばこうなる

Page 81: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約の勝手な解釈

81

■ 一つの集約のルート(エンティティ)でどこまで責任を持つかということ

■ モデルの一貫性を保つためのものが集約である

■ (参考)http://masuda220.jugem.jp?day=20091126

Page 82: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデル図を描いてみるユビキタス言語を定義し、ドメインモデルとしてEntity、ValueObject、集約につ

いて理解したらドメインモデル図を描いてチーム全員での認識が正しくなされ

ているかを確認する

Page 83: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

PlantUmlでドメインモデル図を書く

Page 84: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

HRMOSの問題

84

1. モデルの定義がぐちゃぐちゃ

2. 大きすぎる集約

3. ドメインモデル貧血症

Page 85: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

集約が大きすぎる

■ 応募者の情報であれば求人情報はいらない

し、面接の情報もいらない

■ レジュメの情報も集約としては別として小さ

な集約を目指す。

85

Page 86: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

パフォーマンス問題

86

■ SQLTimeoutが頻発するようになっていた(DDD取り入れる前から)

■ 1つのSQLで大量にデータ取りすぎている

■ この問題はDDDでは解決できず、逆にすべてにドメインモデルを強制する

とパフォーマンスは劣化する可能性がある

Page 87: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

CQRS(コマンドクエリ責務分離)という考え方

87

■ DBからデータ引っ張ってちょっとしたデータ表示したいという要求に対して

もドメインモデルを用いるべきか?

■ コマンドとクエリに分け、クエリの場合にはドメインモデルをスキップしても

良いのではないか?

■ 全部が全部ドメインモデルを用いていてはパフォーマンスに問題ありそう

Page 88: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Command

88

フロントエンドから問い合わせがあってビジネスロジックを用いるのであればコマンドと

してドメインモデルを活かして 実装をする。

Page 89: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

Query

89

フロントエンドから問い合わせがあってデータを返すだけで良いのであれば クエリなの

でドメインモデルはスキップして、欲しいデータだけを素早く取るように実装する

Page 90: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

ドメインモデルとリポジトリの関係

Page 91: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
Page 92: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
Page 93: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

個人的にはドメインモデルに永続化は持たせたくない

Page 94: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

HRMOSの問題

94

1. モデルの定義がぐちゃぐちゃ

2. 大きすぎる集約

3. ドメインモデル貧血症

Page 95: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

DDDでよく語られるドメインモデル貧血症

95

■ ドメインモデルっぽく出来たものの実際はただのデータを入れる箱でしか無

くドメインモデルがどういった責務を果たすべきなのかが明確になっていな

い(外部に出てしまっている)状態

■ サービス層にばかり処理を書いて、ドメインモデルがほとんどgetterと

setterばかりになってしまっている状態のこと

Page 96: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

DDDでよく語られるドメインモデル貧血症

96

■ HRMOSではScalaを使っているのでgetter, setterは無いがメソッドを持たな

いcase class が大量に存在

■ また、XXServiceやXXUtilといったクラスがあらゆるロジックを持っていたが

それを再定義したドメインモデルのクラスに少しずつ移譲

■ 少しずつリファクタリングを進めて貧血状態から抜け出せるように

Page 97: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

DDDを超意訳するとDDDはドメインモデルを用いて、ソフトウェアの関心事とドメインの関心事をキ

チンと分けて設計しましょうというお話

Page 98: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

98

DDDを理解して実践できているような口ぶりで説明をしてきましたが

まだまだ道半ば

Page 99: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

99

DDDを理解して実践できているような口ぶりで説明をしてきましたが

まだまだ道半ば

Page 100: 【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜

We are hiring!

■ Bizreach: https://bizreach.biz/landing/base_01

■ HRMOS: https://www.hrmos.co/saiyo/

■ Stanby: https://jp.stanby.com/

■ Careertrek: https://careertrek.biz/?trcd=corp

■ Bizreach CAMPUS: https://br-campus.jp/ etc...