Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spring Modulithで始めるモジュラモノリス開発

Spring Modulithで始めるモジュラモノリス開発

Spring Fest 2023での登壇資料

YutoOtsuka

March 17, 2023
Tweet

Other Decks in Programming

Transcript

  1. Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    Spring Modulithで始める
    モジュラモノリス開発
    Spring Fest 2023
    Acroquest Technology株式会社
    ⼤塚 優⽃
    1

    View Slide

  2. ⾃⼰紹介
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    2
    l⼤塚優⽃
    • Acroquest Technology株式会社
    エンジニアリングクリエイター
    • Java(Spring), Python, TypeScript(Angular)
    • 2022年12⽉に会社の技術ブログ(Taste of Tech
    Topics)でSpring Modulithの記事を書きました

    View Slide

  3. ⽬次
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    3
    1. Spring Modulithとは
    2. モジュラモノリスとは
    3. Spring Modulithの機能紹介
    4. まとめ

    View Slide

  4. 1. Spring Modulithとは
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    4
    モジュラモノリスなSpring Bootアプリの
    開発をサポートしてくれるライブラリ
    ※実験的プロジェクトとして開発されており
    Spring Boot 3, Java17がベース

    View Slide

  5. モジュラモノリスってなに︖
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    5

    View Slide

  6. 2. モジュラモノリスとは
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    6
    l ソフトウェアアーキテクチャの⼀種である
    l モノリスアーキテクチャの仲間であり、ひとつのアプリケーションが
    モジュールという単位で分割された複数の機能・役割を持つ
    モノリス モジュラモノリス マイクロサービス
    ひとつのアプリが
    全ての機能・役割を持つ
    ひとつのアプリが
    モジュールで明確に分割された
    複数の機能・役割を持つ
    複数のアプリ(サービス)が
    それぞれ1つの機能・役割を持つ
    デプロイ単位

    View Slide

  7. • モジュール化されているので構造が理解しやすい
    • モジュールごとの並列作業が⽐較的やりやすい
    • 将来的にマイクロサービスに移⾏しやすい
    モジュラモノリスのメリット・デメリット
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    7
    • 単⼀のアプリなのでデプロイが容易
    • ネットワーク越しの機能呼び出しが少ない
    • 全てのモジュールが常に利⽤可能
    • E2Eテストが容易
    • リファクタリングが容易
    メリット
    モノリスとの差分

    View Slide

  8. モジュラモノリスのメリット・デメリット
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    8
    • マイクロサービスほどの強い分離を強制できない
    • モジュール境界を管理する必要がある
    • 特定のモジュールをスケールさせることができない
    デメリット

    View Slide

  9. なぜモジュラモノリスが注⽬されているのか︖
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    9

    View Slide

  10. モノリスの課題点
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    10
    Order Inventory Catalog
    技術的観点による⽔平分割
    UI層(@Controller)
    データアクセス層
    (@Repository)
    ビジネスロジック層
    (@Service)
    src/main/java
    controller
    service
    repository
    密結合な実装になりやすい
    複数⼈での並列作業がしづらい

    View Slide

  11. モジュール化によって疎結合にする
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    11
    Order Inventory Catalog
    @Controller
    @Repository
    @Service
    @Controller
    @Repository
    @Service
    @Controller
    @Repository
    @Service
    ビジネス領域による垂直分割
    src/main/java
    order
    inventory
    catalog
    モジュール同⼠が疎結合になりやすい
    複数⼈での並列作業がしやすい

    View Slide

  12. モジュールのカプセル化によって疎結合にする
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    12
    Order Inventory Catalog
    Public API
    内部実装 内部実装 内部実装
    発注
    在庫
    更新
    l モジュールを跨ぐ呼び出しは
    パブリックなAPIにのみ依存する
    l パブリックAPIは⼩さく・変更の
    少ない安定したものにする
    モジュール同⼠を疎結合に
    • 公開しているものを後から
    隠すのは⼤変
    • 依存している箇所に変更が
    多いと修正が⼤変
    l モジュールでは、パブリックなAPIと内部実装を明確に分ける
    Public API Public API

    View Slide

  13. 3. Spring Modulithの機能紹介
    13
    ①アーキテクチャ違反の検証
    ②モジュールごとに独⽴してテスト可能
    ③イベント発⾏ログの永続化

    View Slide

  14. Spring Modulithの依存関係追加
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    14


    org.springframework.experimental
    spring-modulith-starter-jpa
    compile


    org.springframework.experimental
    spring-modulith-starter-test
    compile





    org.springframework.experimental
    spring-modulith-bom
    0.3.0
    import
    pom



    ・ライブラリのセットで構成されている
    ・使いたい機能を個別に追加
    ※機能⼀覧等の詳細はドキュメント参照
    このスライドで⽤いた依存関係

    View Slide

  15. 3. Spring Modulithの機能紹介
    15
    ①アーキテクチャ違反の検証
    ②モジュールごとに独⽴してテスト可能
    ③イベント発⾏ログの永続化

    View Slide

  16. ①アーキテクチャ違反の検証
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    16
    XXXパッケージ
    YYYパッケージ
    ZZZパッケージ
    ・循環参照はNG
    ・パッケージ間の依存関係は
    こうしたい(こうなっているべき)
    ・別モジュールの内部実装は
    参照しない
    開発者
    開発者の設計 コードの構造
    ここの乖離がないか
    検証する

    View Slide

  17. ①アーキテクチャ違反の検証
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    17
    Order Inventory
    公開API
    内部実装
    公開API
    内部実装
    src/main/java
    order
    inventory
    internal
    Application.java
    InternalComponent.java
    exposedOrderApi.java
    exposedInventoryApi.java
    l テストコードで、モジュールの内部実装への参照違反を検知できる
    other-internal
    OtherInternalComponent.java
    凡例
    モジュール
    公開API
    内部実装
    public
    private

    View Slide

  18. ①アーキテクチャ違反の検証
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    18
    l テストコード例
    • OrderモジュールがInventoryモジュールの内部実装に依存している場合
    org.springframework.modulith.model.Violations: - Module 'order' depends on non-exposed type
    com.example.samplemodulith.inventory.internal.InternalInventoryComponent within module 'inventory'!
    ログ
    import org.junit.jupiter.api.Test;
    import org.springframework.modulith.model.ApplicationModules;
    public class ModularityTests {
    @Test
    void verifyModularity() {
    var modules =
    ApplicationModules.of(SampleModulithApplication.class);
    modules.forEach(System.out::println);
    modules.verify();
    }
    }
    @SpringBootApplicationが
    ついているクラスを指定

    View Slide

  19. 3. Spring Modulithの機能紹介
    19
    ①アーキテクチャ違反の検証
    ②モジュールごとに独⽴してテスト可能
    ③イベント発⾏ログの永続化

    View Slide

  20. ②モジュールごとに独⽴してテスト可能
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    20
    ここだけでテスト可能
    Aモジュール Bモジュール Cモジュール
    チームA担当 チームB担当 チームC担当

    View Slide

  21. ②モジュールごとに独⽴してテスト可能
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    21
    l テストしたいモジュールに関連するBeanのみ⽣成してくれる
    スライスアノテーションのようなものが⽤意されている
    Order Inventory
    UI
    ビジネス
    ロジック
    データ
    アクセス
    @WebMvcTest
    @DataXXXTest
    @ApplicationModuleTest package com.example.samplemodulith.order;
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import
    org.springframework.modulith.test.ApplicationModuleTest;
    @ApplicationModuleTest()
    class OrderIntegrationTests {
    @MockBean
    private InventoryService inventoryService;
    @Test
    void 何かしらのテスト() {
    }
    }

    View Slide

  22. 3. Spring Modulithの機能紹介
    22
    ①アーキテクチャ違反の検証
    ②モジュールごとに独⽴してテスト可能
    ③イベント発⾏ログの永続化

    View Slide

  23. イベント駆動アーキテクチャの概要
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    23
    同期的
    モジュールA モジュールB モジュールA モジュールB
    メソッド呼び出し
    イベント
    イベント発⾏ イベント購読
    アプリA アプリB
    HTTP呼び出し
    アプリA アプリB
    メッセージブローカー
    ⾮同期的(イベント駆動)
    同⼀
    アプリ内の
    やり取り
    複数
    アプリ間の
    やり取り
    Spring Modulithでは
    基本的にこの⽅式

    View Slide

  24. @Service
    class OrderService {
    private final InventoryService inventoryService;
    public OrderService1(InventoryService inventoryService)
    {
    this.inventoryService = inventoryService;
    }
    @Transactional
    public void complete() {
    inventoryService.update();
    }
    }
    モジュール間のやり取りにイベントを利⽤する
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    24
    l 別モジュールの公開APIを直接呼び出すのではなく、
    イベントの公開と購読を利⽤する(Spring Application Events)
    他モジュールのBeanを知っておく必要がある
    テストでは依存Beanをモックする必要がある
    新機能を作成したときに、Orderモジュールを
    修正する可能性がある
    別モジュールの公開APIを直接呼び出す

    View Slide

  25. import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Service;
    import
    org.springframework.transaction.annotation.Transactional;
    @Service
    public class OrderService {
    private final ApplicationEventPublisher publisher;
    public OrderService(ApplicationEventPublisher publisher) {
    this.publisher = publisher;
    }
    @Transactional
    public void complete(OrderCompleted event) {
    publisher.publishEvent(event);
    }
    }
    モジュール間のやり取りにイベントを利⽤する
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    25
    l 別モジュールの公開APIを直接呼び出すのではなく、
    イベントの公開と購読を利⽤する(Spring Application Events)
    イベントを公開する
    他モジュールのことを知る必要がない

    View Slide

  26. モジュール間のやり取りにイベントを利⽤する
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    26
    l イベントを購読する側は、Listenerの引数で購読するイベント型を受け取る
    l @EventListener(元のTxと同期的)
    l @ApplicationModuleListener(元のTxと⾮同期的)
    発注
    在庫
    更新
    発注
    在庫
    更新
    ⾮同期で処理できる
    在庫更新でエラー発⽣時はリトライ等が必要
    トランザクション範囲
    イベントを起点に後続の処理を実施
    同じトランザクションで⼀貫性を維持できる
    不必要にトランザクション範囲を広げる可能性がある
    @Service
    public class InventoryService {
    ...
    @EventListener
    void onSameTx(OrderCompleted event) {
    // ここで在庫更新処理
    }
    @ApplicationModuleListener
    void onOtherTx(OrderCompleted event) {
    // ここで在庫更新処理
    }
    ...
    }
    凡例
    どのListenerでエラーが起きたか
    という情報が必要

    View Slide

  27. ③イベント発⾏ログの永続化
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    27
    モジュールA イベント
    ①イベント発⾏ ③イベント購読
    モジュールB
    ②イベント発⾏ログの永続化
    処理失敗時に
    リトライ対象のログを参照

    View Slide

  28. ③イベント発⾏ログの永続化(Event Publication Registry)
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    28
    l イベント発⾏にフックして、イベントを購読している各Listenerごとに
    イベント発⾏ログを永続化
    l @ApplicationModuleListenerが正常に処理された場合は
    そのイベントを完了状態にする
    発注
    在庫
    更新
    No error
    イベント公開
    @ApplicationModuleListener
    更新
    未完了のイベントは、
    デフォルトでアプリ再起動時に再送される
    ※H2の場合(他には HSQLDB, MySQL, PostgreSQL)
    COMPLETION_DATEは
    nullの状態で永続化
    Error
    nullのまま

    View Slide

  29. 4. まとめ
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    29
    l モジュラモノリスでは、内部をモジュール化することによって
    モノリスの恩恵を受けつつ疎結合な設計を保てる
    l Spring Modulithでは、テストを書くことで、
    モジュールの意図しない参照を検知し、
    開発者の設計と実際のコードに乖離がないことを機械的に判定できる
    l モジュール間のやり取りにイベント駆動を⽤いる際、
    イベント発⾏ログの永続化機能によって
    リトライすべきイベントを判別できる

    View Slide

  30. 30
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    ご清聴ありがとうございました
    よいSpringライフを︕

    View Slide