$30 off During Our Annual Pro Sale. View Details »

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

Yu Kawanami
February 16, 2020

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

Yu Kawanami

February 16, 2020
Tweet

More Decks by Yu Kawanami

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  8. Clean Architecture
    8

    View Slide

  9. Clean Architecture
    9

    View Slide

  10. Domain Model
    Employee
    Procedure
    Report
    xxx
    yyy
    10

    View Slide

  11. 依存関係
    11

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    ● その礎としてのオブジェクト指向設計原則
    ○ 単一責任の原則(SRP)
    ○ 依存関係逆転の原則(DIP)
    15

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  21. どうすればよいか?
    21

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  32. 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);
    }

    View Slide

  33. 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);
    }

    View Slide

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

    View Slide

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

    View Slide

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

    36

    View Slide

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

    View Slide

  38. ドメイン駆動設計が支えるアーキテクチャ
    ● ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー

    ● 実装で得た知識が設計にも反映される
    38

    View Slide

  39. ドメイン駆動設計が支えるアーキテクチャ
    ● ドメイン駆動設計の真髄は、設計⇔実装のフィードバックルー

    ● 実装で得た知識が設計にも反映される
    ● アーキテクチャも同じ
    ● アーキテクチャも一度決めて終わりではない
    ● アーキテクチャもシステムの成長とともに磨かれる
    39

    View Slide

  40. アーキテクチャの目的
    40

    View Slide

  41. 41

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  46. Appendix.
    46

    View Slide

  47. 参考資料
    ● 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

    View Slide