Slide 1

Slide 1 text

ドメイン駆動設計を支える アーキテクチャテスト Object-Oriented Conference 2020 @kawanamiyuu

Slide 2

Slide 2 text

2 https://speakerdeck.com/kawanamiyuu/jjug-ccc-2019-spring アーキテクチャテストへの モチベーション、具体例を 紹介した入門編

Slide 3

Slide 3 text

自己紹介 ● かわなみゆう ● @kawanamiyuu ● 株式会社ラクス / Lead Engineer ● HR x SaaS の開発 ● Java (Spring Boot, Doma) / Vue.js / Puppeteer ● 自動テスト(が書きやすい設計を考えながらコード) を書くのがすき 3

Slide 4

Slide 4 text

Context Map 4 https://www.infoq.com/articles/ddd-contextmapping/

Slide 5

Slide 5 text

Context Map 5 https://www.infoq.com/articles/ddd-contextmapping/

Slide 6

Slide 6 text

Layer Architecture (〇〇〇〇を逆転したレイヤードアーキテクチャ) 6 (一般的なレイヤードアーキテクチャ)

Slide 7

Slide 7 text

Layer Architecture (〇〇〇〇を逆転したレイヤードアーキテクチャ) 7 (一般的なレイヤードアーキテクチャ)

Slide 8

Slide 8 text

Clean Architecture 8

Slide 9

Slide 9 text

Clean Architecture 9

Slide 10

Slide 10 text

Domain Model Employee Procedure Report xxx yyy 10

Slide 11

Slide 11 text

依存関係 11

Slide 12

Slide 12 text

アーキテクチャとは 「依存関係」のガイドライン 12

Slide 13

Slide 13 text

アーキテクチャの正体 ● アーキテクチャとはソフトウェアの構造についての取り決めで あり、 ● 解像度を上げていくと、ソフトウェアを構成する責務や関心事 の「依存関係」についての取り決め 13

Slide 14

Slide 14 text

アーキテクチャの視座 ● 責務や関心事の粒度 ○ 大きな粒度:コンテキスト、レイヤー ○ 小さな粒度:パッケージ、クラス ● それぞれの粒度で依存関係を注意深く設計する 14

Slide 15

Slide 15 text

アーキテクチャとオブジェクト指向設計原則 ● (乱暴に言うと)Layer Architecture も Clean Architecture も 、DDD のような設計論も、依存関係を適切に設計したいだ け ● その礎としてのオブジェクト指向設計原則 ○ 単一責任の原則(SRP) ○ 依存関係逆転の原則(DIP) 15

Slide 16

Slide 16 text

「アーキテクチャ」の問題点 16

Slide 17

Slide 17 text

「ガイドライン」というものの性質 ● ガイドラインとは「指針」「ルール」「マナー」 ● 人が決めて、守る(守らせる) ● 最初にルールをつくるのは、簡単 ● ルール通りつくり始めるのも、簡単 17

Slide 18

Slide 18 text

「ガイドライン」というものの性質 ● ガイドラインとは「指針」「ルール」「マナー」 ● 人が決めて、守る(守らせる) ● 最初にルールをつくるのは、簡単 ● ルール通りつくり始めるのも、簡単  なにが難しいのか? 18

Slide 19

Slide 19 text

アーキテクチャの維持が難しい 19

Slide 20

Slide 20 text

アーキテクチャの維持は難しい 人が決めたことであるがゆえに、壊れやすい。 時間が経つと「大きな泥団子(Big Ball of Mud)」に。 ● よくある要因 ○ 設計知識の属人化・暗黙知化 ○ 開発スキルのばらつき ○ 納期優先、相次ぐメンバー増員 20

Slide 21

Slide 21 text

どうすればよいか? 21

Slide 22

Slide 22 text

22 アーキテクチャをテストしたい

Slide 23

Slide 23 text

23 https://www.archunit.org/

Slide 24

Slide 24 text

ArchUnit ● GitHub ○ https://github.com/TNG/ArchUnit ○ https://github.com/TNG/ArchUnit-Examples ● Twitter ○ https://twitter.com/archtests ● Technology Radar ○ https://www.thoughtworks.com/radar/tools/archunit ○ 進化的アーキテクチャ x 適応度関数 24

Slide 25

Slide 25 text

ArchUnit を一言でいうと ● Java(や Kotlin, Scala)で書かれたアプリケーションのパッ ケージやクラスの依存関係を JUnit のテストコードとして表現 し、テストできるテストフレームワーク ● 依存関係の他にも、そのアプリケーション固有の実装ルール もテストすることができる 25

Slide 26

Slide 26 text

他のプログラミング言語でのアーキテクチャテスト ● TNG/ArchUnitNET(C#) ● iternity/archlint.cs(C#) ● BenMorris/NetArchTest(.Net) ● sensiolabs-de/deptrac(PHP) ● carlosas/phpat(PHP) ● nazonohito51/dependency-analyzer(PHP) 26

Slide 27

Slide 27 text

アーキテクチャテストの例 27

Slide 28

Slide 28 text

28 @Test void DIP_依存性逆転の原則_を適用したレイヤードアーキテクチャ () { layeredArchitecture() .layer("ui").definedBy("com.example.presentation..") .layer("app").definedBy("com.example.application..") .layer("domain").definedBy("com.example.domain..") .layer("infra").definedBy("com.example.infrastructure..") .whereLayer("ui").mayOnlyBeAccessedByLayers("infra") .whereLayer("app").mayOnlyBeAccessedByLayers("infra", "ui") .whereLayer("domain").mayOnlyBeAccessedByLayers("infra", "app") .whereLayer("infra").mayNotBeAccessedByAnyLayer() .check(CLASSES); }

Slide 29

Slide 29 text

29 @Test void DIP_依存性逆転の原則_を適用したレイヤードアーキテクチャ () { layeredArchitecture() .layer("ui").definedBy("com.example.presentation..") .layer("app").definedBy("com.example.application..") .layer("domain").definedBy("com.example.domain..") .layer("infra").definedBy("com.example.infrastructure..") .whereLayer("ui").mayOnlyBeAccessedByLayers("infra") .whereLayer("app").mayOnlyBeAccessedByLayers("infra", "ui") .whereLayer("domain").mayOnlyBeAccessedByLayers("infra", "app") .whereLayer("infra").mayNotBeAccessedByAnyLayer() .check(CLASSES); }

Slide 30

Slide 30 text

30 @Test void ReportドメインはProcedureドメインからのみ依存される () { classes().that().resideInAPackage("com.example.domain.report..") .should() .onlyBeAccessed().byAnyPackage("com.example.domain.procedure..") .check(CLASSES); }

Slide 31

Slide 31 text

31 @Test void ReportドメインはProcedureドメインからのみ依存される () { classes().that().resideInAPackage("com.example.domain.report..") .should() .onlyBeAccessed().byAnyPackage("com.example.domain.procedure..") .check(CLASSES); }

Slide 32

Slide 32 text

32 @Test void ドメイン層はWeb実行環境に依存しない () { noClasses().that().resideInAPackage("com.example.domain..") .should() .dependOnClassesThat().resideInAPackage("javax.servlet..") .check(CLASSES); } @Test void ドメイン層はWebアプリケーションフレームワークに依存しない () { noClasses().that().resideInAPackage("com.example.domain..") .should() .dependOnClassesThat().resideInAPackage("org.springframework..") .check(CLASSES); }

Slide 33

Slide 33 text

33 @Test void ドメイン層はWeb実行環境に依存しない () { noClasses().that().resideInAPackage("com.example.domain..") .should() .dependOnClassesThat().resideInAPackage("javax.servlet..") .check(CLASSES); } @Test void ドメイン層はWebアプリケーションフレームワークに依存しない () { noClasses().that().resideInAPackage("com.example.domain..") .should() .dependOnClassesThat().resideInAPackage("org.springframework..") .check(CLASSES); }

Slide 34

Slide 34 text

ドメイン駆動設計にとっての アーキテクチャテスト 34

Slide 35

Slide 35 text

ドメインが隔離されていることを担保する ● ドメインと、他の詳細や関心との依存関係 ○ ドメインと技術的詳細 ○ ドメインと UI ● ドメイン同士の依存関係 これらが期待通りであることを自動テストによって担保し続けること ができる。 35

Slide 36

Slide 36 text

アーキテクチャテストの失敗は悪か? ● アーキテクチャテストはあるべき依存関係を表現したもの ● アーキテクチャテストは失敗しないはずのテスト ● アーキテクチャテストが失敗するとき ○ 実装誤り ○   ○ 36

Slide 37

Slide 37 text

アーキテクチャテストの失敗は悪か? ● アーキテクチャテストはあるべき依存関係を表現したもの ● アーキテクチャテストは失敗しないはずのテスト ● アーキテクチャテストが失敗するとき ○ 実装誤り ○ アーキテクチャに対する発見のサイン ○ アーキテクチャについて議論する始点 37

Slide 38

Slide 38 text

ドメイン駆動設計が支えるアーキテクチャ ● ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー プ ● 実装で得た知識が設計にも反映される 38

Slide 39

Slide 39 text

ドメイン駆動設計が支えるアーキテクチャ ● ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー プ ● 実装で得た知識が設計にも反映される ● アーキテクチャも同じ ● アーキテクチャも一度決めて終わりではない ● アーキテクチャもシステムの成長とともに磨かれる 39

Slide 40

Slide 40 text

アーキテクチャの目的 40

Slide 41

Slide 41 text

41

Slide 42

Slide 42 text

この図は ● モノリシックなアプリケーション内部の、ドメイン同士の依存関 係? ● マイクロサービスアーキテクチャで実現されたアプリケーション の、サービス同士の依存関係? 42

Slide 43

Slide 43 text

この図は ● モノリシックなアプリケーション内部の、ドメイン同士の依存関 係? ● マイクロサービスアーキテクチャで実現されたアプリケーション の、サービス同士の依存関係? どちらもありえる。 43

Slide 44

Slide 44 text

ドメイン駆動設計という文脈で私たちが「ドメイン」と呼んでいるも のが、ありていに言えば、高凝集で疎結合な実装技術によって実 現されていれば、システムとしてもビジネスとしても多くの選択肢 が残される。 モノリスからマイクロサービスへ、アーキテクチャを進化させる可 能性も。 44

Slide 45

Slide 45 text

ソフトウェアが「ソフト」であるための選択肢を残す。 それがアーキテクチャ。 そのアーキテクチャが意図する依存関係を維持し、ソフトウェアの 発展の可能性を支えるアーキテクチャテスト。 45

Slide 46

Slide 46 text

Appendix. 46

Slide 47

Slide 47 text

参考資料 ● Books ○ エリック・エヴァンスのドメイン駆動設計( Eric Evans) ○ Clean Architecture ―達人に学ぶソフトウェアの構造と設計( Robert C.Martin) ○ 進化的アーキテクチャ ―絶え間ない変化を支える( Neal Ford, Rebecca Parsons, Patrick Kua) ● Talk ○ JJUG CCC 2019 Spring ■ ArchUnit で Java / Kotlin アプリケーションのアーキテクチャを CI する ■ https://speakerdeck.com/kawanamiyuu/jjug-ccc-2019-spring ● Blog ○ ドメイン駆動設計#1 Advent Calendar 2019 ■ 6日目:ドメイン駆動設計を支えるアーキテクチャテスト ■ https://tech-blog.rakus.co.jp/entry/20191206/java 47