23K Views
October 25, 24
スライド概要
JJUG CCC 2024 Fallでのスポンサーセッション「Spring ModulithによるDDDとEvent-driven Architectureの実践」の公開資料です。
シンプレクスは1997年の創業以来、メガバンクや大手総合証券を筆頭に、日本を代表する金融機関のテクノロジーパートナーとしてビジネスを展開してきました。現在では、金融領域で培った豊富なノウハウを活用し、金融機関以外の領域でもソリューションを展開しています。2019年3月にはAI企業のDeep Percept株式会社、2021年4月には総合コンサルティングファームのXspear Consulting株式会社がグループに加わり、創業時より付加価値の創造に取り組んできたシンプレクスとワンチームとなって、公的機関や金融機関、各業界をリードする企業のデジタルトランスフォーメーション(DX)の推進を支援しています。
JJUG CCC 2024 Fall Spring Modulithによる DDDと Event-driven Architecture の実践 シンプレクス株式会社 菅原直弥 CONFIDENTIAL © 2024 Simplex, Inc.
スピーカー紹介 菅原 直弥 2012年 シンプレクス入社 - Principal 代表的なプロジェクト - NFTマーケットプレイスアーキテクチャ刷新 - Simplex Fourth PdM (web3統合プラットフォームソリューション) 1 © 2024 Simplex Inc.
What is Simplex Inc. 金融事業領域を中心にビジネスパートナーとしてお客様の収益力強化、生産性向上を支援しています。 近年は官公庁、製造業といった非金融領域に対してもシステム・ソリューションを提供しています。 シンプレクス・ホールディングス 社名 シンプレクス株式会社 事業内容 • コンサルティングサービス • システム開発 • 運用保守 • ASPサービス提供 等 代表取締役社長 金子 英樹 創業年月日 1997年9月16日 資本金 4,750 百万円(2024年3月31日現在) 連結従業員数 1,554名(2024年4月1日現在) 株主 シンプレクス・ホールディングス株式会社 テックファーム 本社所在地 東京都港区虎ノ門1-23-1 虎ノ門ヒルズ森タワー19階 1997年創業 (東証プライム:4373) シンプレクス クロスピア ビジネスプラットフォームの構築 “IDC FinTech Rankings”に13年連続で選出 DXビジネス戦略の立案 コンサルファーム 2021年創設 AWSパートナーネットワークにおける認定 2 © 2024 Simplex Inc.
What is Simplex Inc. シンプレクスは、金融から開始し、様々なweb3サービス構築を行っています 2018 業界別 対応 実績 暗号資産交換所 2019 2022 デジタル証券 (STO) 2024〜 新領域への活用 ゲーム・エンタメ ステーブルコイン 対応 技術 領域 コントラクト・ウォレット NFT FT(暗号資産・ST・ステーブルコイン) プライベートチェーン パブリックチェーン 3 © 2024 Simplex Inc.
What is Simplex Inc. サービス提供形態 クライアントのニーズにあわせた形で体制を組成、サービス提供を行っています。 プロダクト提供 プロフェッショナルサービス グループの強みを活かし、各種プロフェッショナルが、クライアントと一体となっ てサービス企画から構築、運用保守、継続拡張を一貫して支援 Xspear Consulting ・大手コンサルの経験者 ・各種業界の経験者 Simplex Inc. ・web3技術エキスパート ・大規模PJを完遂する実行力 ・金融水準の運用保守 個社カスタマイズ型 SaaS型 ベースパッケージを活用、個社カスタ マイズで、独自性に注力 SaaSを活用しクイックにPoCやサー ビス立ち上げを実施 Simplex Crypto Assets Simplex Fourth 暗号資産交換所システム ウォレットを軸としたweb3プラットフォーム Simplex Digital Securities Simplex Dealing Cloud デジタル証券取引システム 暗号資産ディーリング Simplex NFT Deep Percept マケプレ・GameFi・推し活等など ・データ分析 ・AIモデル構築 Simplex Stablecoin Stablecoinの発行・償還 Alceo ・UI/UXデザインに特化 4 © 2024 Simplex Inc.
Spring Modulithでアプリケーション開発をして きた経験をもとに、DDD × モジュラモノリスなアー キテクチャについて熱く語ります。 5 © 2024 Simplex Inc.
伝えたいこと • なぜモジュラモノリスを採用するのか • DDD × Spring Modulith開発において 気を付けるべきポイント 6 © 2024 Simplex Inc.
伝えたいこと • なぜモジュラモノリスを採用するのか • DDD × Spring Modulith開発において 気を付けるべきポイント 7 © 2024 Simplex Inc.
モノリス~モジュラモノリス~マイクロサービス モノリス モジュラモノリス 単一サービス 単一サービス ユーザ機能 入金機能 ユーザ 機能 入金 機能 通知 機能 通知機能 マイクロサービス ユーザ サービス 入金 サービス 通知 サービス ユーザ 機能 入金 機能 通知 機能 共通ロジック 単一のサービス内に様々な機 能を実装する 単一のサービスの中でモジュー ルを分割してモジュール間の依 存を明確にする 8 複数のサービスに機能・データ ストアを分割して、 複数のサービスを独立させる © 2024 Simplex Inc.
アーキテクチャごとの特徴 プログラミング インフラ モノリス モジュラモノリス マイクロサービス 再利用・共有化 しやすい モジュール間の 依存に制約を 付けられる ロジックの共通化 は比較的容易 サービス間の依存がAPIに限定される ロジックの共通化に対する制約が強い トランザクション管理が難しい 構成がシンプル 機能ごとのデプロイやスケーリングは できない 特定の箇所の障害がサービス全体に 波及する 技術選定の自由度が高い 独立したデプロイ/スケーリングが可能 特定の箇所の問題が全体に影響 しずらい サービス間のやり取りでネットワーク 通信が発生する 9 © 2024 Simplex Inc.
アーキテクチャごとの特徴 プログラミング モノリス モジュラモノリス マイクロサービス 再利用・共有化 しやすい モジュール間の 依存に制約を 付けられる ロジックの共通化 は比較的容易 サービス間の依存がAPIに限定される ロジックの共通化に対する制約が強い トランザクション管理が難しい モジュールの分割ができる 10 © 2024 Simplex Inc.
なぜモジュールの分割を 行いたいのか 11 © 2024 Simplex Inc.
なぜモジュールの分割を行いたいのか “モジュールは長い歴史を持つ確立された設計要素である。技術的な考慮も一 因ではあるが、認知のための負荷を下げることがモジュール化にあたって主 要な動機になっている。(中略) 全体によって圧倒されることなくモジュール内部の詳細を見ること ができるし、その一方で内部の詳細を無視したうえでモジュール間の 関係性を見ることもできるのだ。(中略) モジュール間では低結合、モジュール内では高凝集が必要なの は自明の理だ。” Eric Evans.『エリックエヴァンスのドメイン駆動設計』.翔泳社.2011年,108p 12 © 2024 Simplex Inc.
なぜモジュールの分割を行いたいのか マイクロサービス ユーザサービス 入金サービス 通知サービス API API API ユーザ機能 入金機能 通知機能 モジュラモノリス API API API ユーザ機能 入金機能 通知機能 モジュールをまたいだロジックの呼び出しは APIを経由しなければならない • 依存箇所がAPIに限定される →低結合 • 機能に関連したロジックが外部に 散らばりづらい →高凝集 共通ロジック 13 © 2024 Simplex Inc.
アーキテクチャごとの特徴 モノリス インフラ モジュラモノリス 構成がシンプル 機能ごとのデプロイやスケーリングは できない 特定の箇所の障害がサービス全体に 波及する マイクロサービス 技術選定の自由度が高い 独立したデプロイ/スケーリングが可能 特定の箇所の問題が全体に影響 しずらい サービス間のやり取りでネットワーク 通信が発生する 機能のまとまりごとに システムを独立管理できる 14 © 2024 Simplex Inc.
システムを独立管理 したいですか? 15 © 2024 Simplex Inc.
システムを独立管理したい事情があるかを考える • 開発メンバーの人数が大規模 • 大規模チームはそれだけで難易度が上がる 10人-20人以上なら分割を検討してそれぞれを独立した別サービスとして扱う (cf.2ピザチーム,コンウェイの法則) • コード行数が多すぎて、CI/CDに時間がかかりすぎる • コンパイル・テスト・ビルド・デプロイ・静的解析などに時間がかかりすぎると、 それだけでいろんなところに悪影響 • 開発端末のスペックやテストの書き方にも依存するので一概には言えないが、感覚的 にはコード行数50-100万行あたりから徐々にこの問題が大きくなる印象 • スペックアップで対処できるならそれが早い。サービスの寿命とコストのかけどころのバラン スで判断が必要 16 © 2024 Simplex Inc.
システムを独立管理したい事情があるかを考える • 開発言語など利用する技術を機能に応じて変えたい 例: • いつもはKotlinでサーバ開発しているけど、機械学習関係のロジックは Pythonで書きたい • 機能ごとに非機能要求のレベルが大きく異なる 例: • アカウント管理・送金処理周りのセキュリティ要件が厳しい • イベントに関連したキャンペーンサイトを新たに作るのでここだけ突発的な負 荷かかりそう 17 © 2024 Simplex Inc.
結局こうなりました • 高凝集/疎結合のためにモジュールの境界は厳密に設計する • 事情があれば別サービスに分ける • 開発体制の分割や、特別な技術要素・非機能要件がある場合 • 「トランザクションが分断される」「ネットワーク通信が発生する」という制約は考慮する • 他はモジュラモノリスの汎用サービスで開発 開発チーム 開発チーム UI UI ビジネス モジュール 高セキュリティ 要件なサービスなど 汎用サービス 特化サービス UI ビジネス モジュール ビジネス モジュール ビジネス モジュール ビジネス モジュール 一時的なサービス ビジネス モジュール 共通ロジック 18 © 2024 Simplex Inc.
伝えたいこと • なぜモジュラモノリスを採用するのか • DDD × Spring Modulith開発において 気を付けるべきポイント 19 © 2024 Simplex Inc.
Spring Modulithとは? “Spring Modulith は、Spring Boot を使用してドメイン駆動型の モジュール型アプリケーションを構築するための独自のツールキット です。 その結果、Spring Modulith を使用すると、開発者は更新が容易な アプリケーションを構築して、時間の経過とともに変化する ビジネス要件に対応できるようになります。” DDDを意識したライブラリ Spring Modulith(2024-10-20時点) https://spring.pleiades.io/spring-modulith/reference/ 20 © 2024 Simplex Inc.
Spring Modulithとは? 提供してくれる機能は主にこの二つ モジュールの分割 イベント連携 21 © 2024 Simplex Inc.
モジュールの分割 22 © 2024 Simplex Inc.
モジュールの分割 モジュール・公開部分・依存関係の定義をすると、Spring Modulith が構造をテストしてくれる。 Example/ └src/main/java/example ├─MainClass.java ├─user/ │ ├──UserApi.java │ ├──usecase/ │ ├──domain / │ └──infra / ├─payment/ │ └──・・・(同上) ├─notice/ │ └──・・・(同上) └─common/ デフォルトでは MainClassの直下 がモジュールになる モジュール 直下 デフォルトではモジュ ールの最上段が公開 APIになる 共有したいロジック置 き場も作れる (Log・Spring Security・Feature Flag) 23 user payment notice 公開 公開 公開 内部 ロジック 内部 ロジック 内部 ロジック domain usecase infra common 公開 © 2024 Simplex Inc.
モジュールの分割 テストでもモジュール性を重視する • ドメインテスト アーキテクチャテスト • ドメインロジックを対象としたテスト • レポジトリテスト user payment notice モジュール 直下 API テスト API テスト API テスト • APIテスト domain ドメイン テスト ドメイン テスト ドメイン テスト • • 検索クエリなどのロジックのテスト • モジュール単体を対象にしたAPIを実行するテスト • アーキテクチャテスト • モジュールのルール違反を検出するテスト usecase infra 他モジュールのAPI呼び出しはMock化する レポジトリ テスト レポジトリ テスト • • • レポジトリ テスト 公開していないコードにアクセスしてないか モジュールの依存関係の定義から逸脱してないか 依存関係の循環が発生していないか • レイヤー間の依存関係もテスト • common 24 ここではArchUnitを使ってる © 2024 Simplex Inc.
モジュール分割やって見た感想 いい点 気を付けるべき点 • 開発時に迷いがなくなる • モジュールの境界線を決める難しさ • ドメインの設計時点でモジュールのことまで意識 するので開発者ごとの考え方のブレが少なくなる • (その分設計が白熱する) • 境界づけられたコンテキストを探す工程が必要 • 設計難易度は上がる • モジュールの循環依存に悩まされて、リファクタし たりしました • 1つのユースケースだと思っていたのに、2つの APIに分けて整理したり • 影響範囲の把握が楽 • コアな箇所の修正でもAPIに影響を出さなけれ ば他モジュールへの影響は気にしない(強い意 志) • テストコードの存在があって初めて威力 を発揮する • 何かあったときのリスクが少ない • リファクタレベルの修正でモジュール化できる • 最悪モジュール統合しちゃえばモノリスと同じ扱 いに戻せる安心感 • もしSpring Modulithがバグっていてもサービス に影響がない安心感 • そもそもモジュール検証機能もテストなので、開 発の中で常に自動テスト結果を確認する文化 が必要 • モジュール外への影響が出てないかは最終的に はテストで担保されるもの 25 © 2024 Simplex Inc.
テストを書きましょう https://www.docswell.com/s/Simplex/ZRXNDN-simplex_maeda01/1 26 © 2024 Simplex Inc.
イベント連携 27 © 2024 Simplex Inc.
イベント連携 モジュラモノリス API API API ユーザ機能 入金機能 通知機能 共通ロジック ここのお話 28 © 2024 Simplex Inc.
Request・Responseの時 @Service payment class PaymentService( val service:NoticeService, ) { @Transactional fun postPayment(payment: Payment) { payment.complete(); service.sendMail(payment.user.mail); } } @Component class NoticeService{ fun sendMail(mail:string) {/** */} } notice 29 © 2024 Simplex Inc.
Request・Responseの時 @Service payment class PaymentService( val service:NoticeService, ) { @Transactional fun postPayment(payment: Payment) { payment.complete(); service.sendMail(payment.user.mail); } } @Component class NoticeService{ fun sendMail(mail:string) {/** */} } notice API 入金機能 API 通知機能 30 paymentが noticeに依存する © 2024 Simplex Inc.
同期イベント連携のとき @Service payment class PaymentService( val events: ApplicationEventPublisher, ) { @Transactional fun postPayment(payment: Payment) { events.publishEvent(payment.complete()); } } @Component class NoticeService{ fun sendMail(mail:string) {/** */} notice @EventListner fun on(event: PaymentCompleted) { sendEmail(event.user.mail); } } 31 © 2024 Simplex Inc.
同期イベント連携のとき @Service payment class PaymentService( val events: ApplicationEventPublisher, ) { @Transactional fun postPayment(payment: Payment) { events.publishEvent(payment.complete()); } } @Component class NoticeService{ fun sendMail(mail:string) {/** */} @EventListner fun on(event: PaymentCompleted) { sendEmail(event.user.mail); } notice API 入金機能 API 通知機能 noticeが paymentに依存する } 32 © 2024 Simplex Inc.
非同期イベント連携のとき @Service payment class PaymentService( val events: ApplicationEventPublisher, ) { @Transactional fun postPayment(payment: Payment) { events.publishEvent(payment.complete()); } } @Component class NoticeService{ fun sendMail(mail:string) {/** */} notice @ApplicationModuleListener fun on(event: PaymentCompleted) { sendEmail(event.user.mail); } } 33 © 2024 Simplex Inc.
非同期イベント連携のとき @Service payment class PaymentService( val events: ApplicationEventPublisher, ) { @Transactional API funAPI postPayment(payment: Payment) { 入金機能 通知機能 events.publishEvent(payment.complete()); } } noticeが paymentに 依存する paymentが @Component notice noticeの遅延や失敗の class NoticeService{ fun sendMail(mail:string) {/** */} 影響を受けない @ApplicationModuleListener fun on(event: PaymentCompleted) { sendEmail(event.user.mail); } } 34 © 2024 Simplex Inc.
Request・Response 同期イベント 非同期イベント はしっかり使い分けたい 35 © 2024 Simplex Inc.
Spring Modulithでイベント連携やって見た感想 いい点 気を付けるべき点 • 記述が簡単 • 非同期イベントは順序を制御できない • FIFOで順番に処理するなどの構造はとれない • 結合テストとの統合が用意されている • 非同期イベントがテーブルに依存する • イベント発生のたびにテーブルにレコードが発生 し続けるので、自身でライフサイクルの管理が必 要 • 今は管理用のインターフェースが存在しているの で管理しやすくなってる(v1.2系) • イベントの外部化とも組み合わせると、い い感じに他マイクロサービスとも連携が取 れそう • 非同期イベントはかなり改善されてきてい るので今後に期待 • スケールアウト構成の場合の挙動が怪し かった(V1.0系当時) 36 © 2024 Simplex Inc.
まとめ 37 © 2024 Simplex Inc.
アーキテクチャを検討する前に考えてほしいこと • モジュラモノリス・マイクロサービスは組み合わせてもいい • モジュールの分割に関するアプローチとしてモジュラモノリスは良い選択肢 • マイクロサービスが不要になるわけではない • ビジネスの特性を考慮しましょう • モジュールの境界線を設定するには分析が必要 • 結局これが重要で難しい。。。 DDDのアプローチが助けになる • 議論しながら業務の都合とシステムの都合をすり合わせて進めましょう • 未知の領域に挑むならモノリスで始めて、ドメイン知識の獲得を待つのもあり • モジュラモノリスならマイクロサービスよりは失敗したときの痛手が少ない 38 © 2024 Simplex Inc.
Spring Modulith開発において気を付けるポイント • モジュールの境界線を決めたら頑張って守る • 追加開発をしていくと、制約が邪魔に感じることはあるけどあきらめない その制約があることでシンプルさが生まれると思う。まずは頑張って考える • Reqeset/Response・同期イベント・非同期イベント使いこなそう! • 単一ドメイン、単一モジュール、モジュール間テストそれぞれの観点でテストピ ラミッドを意識したテストを実施する 39 © 2024 Simplex Inc.
Spring Modulith開発において気を付けるポイント • Spring Modulithの非同期イベントを使う場合は、非機能観 点のテストをしっかりやりましょう • イベント連携周りはシステムの根幹部分になるので、モジュールの分割のよう に気軽な判断は難しい • 今回は非同期イベントについてはFIFOキューで管理したい箇所があるので、 SQS+SpringAWSの慣れてる方式をつかいました • 去年時点(v1.0系)ではリトライやマルチプロセスでの挙動に不安を感じた。 • 今は(v1.2系)イベント管理が進化している部分もあるので使う選択肢があるかもし れません! 40 © 2024 Simplex Inc.
ご清聴ありがとうございました 41 © 2024 Simplex Inc.