ドメイン駆動設計を支えるアーキテクチャテスト / RAKUS Meetup Osaka 5

73560128b23de542e47a318145bc781a?s=47 Yu Kawanami
February 05, 2020

ドメイン駆動設計を支えるアーキテクチャテスト / RAKUS Meetup Osaka 5

RAKUS Meetup Osaka #5「SaaSを支える開発原則」の登壇資料

https://rakus.connpass.com/event/161744/

※本資料は Object-Oriented Conference 2020 の登壇資料のベータ版です。
完成版はこちら
https://speakerdeck.com/kawanamiyuu/object-oriented-conference-2020

73560128b23de542e47a318145bc781a?s=128

Yu Kawanami

February 05, 2020
Tweet

Transcript

  1. ドメイン駆動設計を支える アーキテクチャテスト RAKUS Meetup Osaka #5 SaaS を支える開発原則 @kawanamiyuu

  2. 2 https://ooc.dev

  3. 3 https://speakerdeck.com/kawanamiyuu/jjug-ccc-2019-spring

  4. 自己紹介 • かわなみゆう • @kawanamiyuu • 株式会社ラクス / Lead Engineer

    • HR Tech x SaaS の開発 • Java (Spring Boot, Doma) / Vue.js / Puppeteer • 自動テスト(が書きやすい設計を考えながらコード) を書くのがすき 4
  5. Context Map 5 https://www.infoq.com/articles/ddd-contextmapping/

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

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

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

  9. Clean Architecture 9

  10. Clean Architecture 10

  11. Domain Model Employee Procedure Report xxx yyy 11

  12. 依存関係 12

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

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

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

  16. アーキテクチャとオブジェクト指向設計原則 • (乱暴に言うと)Layer Architecture も Clean Architecture も 、DDD のような設計論も、依存関係を適切に設計したいだ

    け • その土台としてのオブジェクト指向設計原則 ◦ 単一責任の原則(SRP) ◦ 依存関係逆転の原則(DIP) 16
  17. 「アーキテクチャ」の問題点 17

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

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

    19
  20. アーキテクチャの品質維持は難しい 人が決めたことであるがゆえに、壊れやすい。 時間が経つと「大きな泥団子(Big Ball of Mud)」に。 • ありえる要因 ◦ 設計知識の属人化・暗黙知化

    ◦ 開発スキルのばらつき ◦ 納期優先、相次ぐメンバー増員 20
  21. どうすればよいか? 21

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

  23. 23 https://www.archunit.org/

  24. 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
  25. ArchUnit を一言でいうと • Java(や Kotlin, Scala)で書かれたアプリケーションのパッ ケージやクラスの依存関係を JUnit のテストコードとして表現 し、テストできるテストフレームワーク

    • 依存関係の他にも、そのアプリケーション固有の実装ルール もテストすることができる 25
  26. 他のプログラミング言語でのアーキテクチャテスト • TNG/ArchUnitNET(C#) • iternity/archlint.cs(C#) • BenMorris/NetArchTest(.Net) • sensiolabs-de/deptrac(PHP) •

    carlosas/phpat(PHP) • nazonohito51/dependency-analyzer(PHP) 26
  27. アーキテクチャテストの例 27

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

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

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

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

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

    アーキテクチャを見直すサイン 34
  35. ドメイン駆動設計を支えるアーキテクチャテスト • ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー プ • 実装によって設計も磨かれていく 35

  36. ドメイン駆動設計を支えるアーキテクチャテスト • ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー プ • 実装によって設計も磨かれていく • アーキテクチャも同じ • アーキテクチャも一度決めて終わりではない

    • アーキテクチャもシステムの成長とともに進化する 36
  37. アーキテクチャの目的 37

  38. 38

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

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

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

  42. ソフトウェアが「ソフト」であるための選択肢を残す。 それがアーキテクチャ。 そのアーキテクチャが意図する依存関係を維持し、改善への気付 きを得るためのアーキテクチャテスト。 42

  43. Appendix. 43

  44. 参考資料 • Books ◦ エリック・エヴァンスのドメイン駆動設計(Eric Evans) ◦ 実践ドメイン駆動設計(Vaughn Vernon) ◦

    Clean Architecture ―達人に学ぶソフトウェアの構造と設計(Robert C.Martin) ◦ 進化的アーキテクチャ ―絶え間ない変化を支える(Neal Ford, Rebecca Parsons, Patrick Kua) • Talks ◦ ArchUnit で Java / Kotlin アプリケーションのアーキテクチャを CI する ▪ https://speakerdeck.com/kawanamiyuu/jjug-ccc-2019-spring 44