Slide 1

Slide 1 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 好きになる、はじめての電子カルテ 楽ありゃ苦もある モノレポ化 Henryのモノレポ化で出会った課題と現状 2024年6月25日, Kengo TODA 1

Slide 2

Slide 2 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 自己紹介 フリーソフトウェア開発出身。OSSプログラマやBtoB研究開発 を経て、現在は医療機関向けにウェブサービスを提供する株式 会社ヘンリーでSREやセキュリティなどを担当。 元SpotBugsの中のひとで静的解析が好きだが、最近はRDBを Kotlinで実装したりGitHub Actionsを育てたりしている。 結局は技術的なめんどくささや遅さをぱっぱと解決して、顧客 の課題に注力したい人。 2

Slide 3

Slide 3 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 本日のねらい 「モノレポは令和のソフトウェア開発における銀の弾丸か?」 →んなわきゃない。 →では何に留意すべきか?を具体例で話せるようになろう! 3

Slide 4

Slide 4 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryのモノレポ化のあらすじ Henryは電子カルテ・レセコン・オーダリング システム一体型の医療機関様向けSaaS。 バックエンドを計算エンジンとそれ以外、とい う雑な分け方をしていた。チーム構造とシステ ム構造の不一致などの問題が発生、分散した密 結合状態に。 ドメインの分割について改めて話し合い、プロ ジェクトを統合してモノレポ化することに。 4 https://dev.henry.jp/entry/backend-monorepo-part-1

Slide 5

Slide 5 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 1. 複数サービスをまたがる変更をアトミックにできるようになった! 2. 設定や共通クラス、スクリプトなどを一箇所で管理できるようになった! 3. コンテキスト境界をコードベースに反映するなどの営みがしやすい! 5 モノレポ化で開発効率がめちゃくちゃ改善した!🙌 https://dev.henry.jp/entry/backend-monorepo-part-1

Slide 6

Slide 6 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta モノレポにはこういうことも期待していた - 機能追加や不具合修正に変更が1プロジェクトにまとまる - チームは一部のサブプロジェクトだけ責任を持つ - 変更した部分だけビルド・テストして細かく検証サイクルを回せる - 手元で簡単に起動して動作確認できる - 他チームとのインタフェース・契約についてコードで議論し合意できる 6

Slide 7

Slide 7 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの現在地 - 機能追加や不具合修正のために他プロジェクトも変更しないといけない - 手元ではなかなか起動できない - チームはすべてのサブプロジェクトを配慮しないといけない - 一部変更すると全部ビルド・テストしないといけない - 他チームとのインタフェース・契約はドキュメントで議論 7

Slide 8

Slide 8 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta - 機能追加や不具合修正のために他プロジェクトも変更しないといけない →モノレポにはなったがコードが未整理 - 手元ではなかなか起動できない →インフラの管理が別プロジェクトのまま - チームはすべてのサブプロジェクトを配慮しないといけない →サブプロジェクトを戦略的に分割できていない - 一部変更すると全部ビルド・テストしないといけない →サブプロジェクトを戦略的に分割できていない - 他チームとのインタフェース・契約はドキュメントで議論 →テストが書きにくい、書いて嬉しくなりにくい Henryモノレポの課題整理 8

Slide 9

Slide 9 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの課題を解決する 1. コード以外のモノレポ化を進める a. APIスキーマもモノレポの管理下に置く b. 関連サービスを一発で起動できるdocker-composeファイルの作成 2. モノレポとしての行儀を良くする a. プロジェクト構造リファクタリング b. テストの活用 9

Slide 10

Slide 10 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの課題を解決する 1. コード以外のモノレポ化を進める a. APIスキーマもモノレポの管理下に置く b. 関連サービスを一発で起動できるdocker-composeファイルの作成 2. モノレポとしての行儀を良くする a. プロジェクト構造リファクタリング b. テストの活用 10

Slide 11

Slide 11 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta なぜAPIスキーマを別リポジトリで管理していたか 11 スキーマをAPI公開プロジェクトで管理 すると、APIを使う側は複数のリポジト リからスキーマを取得してこないとい けない。 中央管理すれば、スキーマ情報の取得 は1回で済む。リポジトリ間で責務をき れいに分けることを志向していたた め、この利点が大きかった。 https://speakerdeck.com/agatan/server-side-architecture-at-henry-inc?slide=20

Slide 12

Slide 12 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta なぜスキーマを別リポジトリで管理していたか 12 モノレポにした段階で「スキーマ情報 を複数のリポジトリからかき集める」 ことがなくなった。 スキーマ定義の責務を中央管理からAPI 公開リポジトリに寄せることで、より 開発効率が高められると期待。

Slide 13

Slide 13 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta スキーマ駆動のふりかえり 13 観点 モノレポ以前 モノレポ以降 gRPCとGraphQLの不整合を防ぐ 便利 便利 並行開発の実現 チーム構造とシステム構造の不 一致により、思ったような メリットを享受できなかった リポジトリを分けていたがための コストは削減できた 中央集権管理 スキーマをかき集める必要がな く便利 別管理していることのデメリット が目立ってきた

Slide 14

Slide 14 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの課題を解決する 1. コード以外のモノレポ化を進める a. APIスキーマもモノレポの管理下に置く b. 関連サービスを一発で起動できるdocker-composeファイルの作成 2. モノレポとしての行儀を良くする a. プロジェクト構造リファクタリング b. テストの活用 14 本日はお時間の関係で割愛

Slide 15

Slide 15 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの課題を解決する 1. コード以外のモノレポ化を進める a. APIスキーマもモノレポの管理下に置く b. 関連サービスを一発で起動できるdocker-composeファイルの作成 2. モノレポとしての行儀を良くする a. プロジェクト構造リファクタリング b. テストの活用 15

Slide 16

Slide 16 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta プロジェクト構成リファクタリング 1. CODEOWNERを使う a. チームが見るべきプロジェクトを限定する b. 課題が発生したときに見るべきチームも明確になる(SentryによるCODEOWNER連携) 2. Gradle Build Cacheを活用する a. いらないビルドを減らすのにとても便利、特にテストを省略できるのがいい b. 上流プロジェクトが変更されるとそれに依存する下流プロジェクトも再ビルドになる =上流がたくさんあって下流が少ないほうが良い 3. こういうの↑ができるようにコードの持ち主を明らかにして依存を整理する a. 一番大変 16

Slide 17

Slide 17 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta プロジェクト構成の理想 理想的にはプロジェクト間依存が シンプルで、階層が浅い方が良い。 それぞれのプロジェクトは小さく、 ぱっとビルド・テストできるように したい。 ドメインモデルが余計なサードパー ティライブラリに依存しない形で書 けるとなお良い。 17 https://blog.kengo-toda.jp/entry/2021/01/30/173611

Slide 18

Slide 18 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta よくあるプロジェクト構成 実際はプレゼンテーション層から データアクセス層までを含む大きな プロジェクトとなっている。マスタ の存在がプロジェクト階層を深くし ている(Shared Libraries Pattern)。 ドメインモデルが全文検索などの 永続層関係のサードパーティに依存 できてしまう。ドメインモデルのテ ストが大げさになりがち。 18 そもそも適切な ドメイン境界が わからん

Slide 19

Slide 19 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 「適切なドメイン境界」を探して三千里 「電子カルテ・レセコン・オーダリングシステム一体型」のSaaSなのだから、そ の3つに切り分ければいいのでは? ● あくまでも歴史的な境界であって、ドメインの境界ではないと考えている ○ レセコン(1975年〜) ○ オーダリングシステム(1980年代〜) ○ 電子カルテ(1999年〜) ● 入院情報など、複数システムから参照されるデータも多い ○ 歴史をなぞることよりも、お客様の課題を解決することが大切 19

Slide 20

Slide 20 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta プロジェクトリファクタリングの初手 クラスの依存関係をDAG(有向非巡回グラフ)にできれば、プロジェクトをどう 分割するのかが見えてくるはず! .repository とか .entity とか、役割で パッケージを切っている場合は、まず ドメインでパッケージを切り直すと良いかも。 20

Slide 21

Slide 21 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta なぜプロジェクト分割が難しいのか 21 $ jdeps \ -include 'com\.example\.packagename\..*' \ -regex 'com\.example\.packagename\..*' \ -dotoutput 'path/to/dot' \ 'path/to/app-all.jar' $ cat 'path/to/dot/app-all.jar.dot' | \ sed 's/ (app-all.jar)//g' | \ dot -Tsvg > 'path/to/output.svg' みんなも自社のjarファイルを解析してみよう!

Slide 22

Slide 22 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryにおけるプロジェクトリファクタリングの現在地 ● モジュラモノリスに持っていく ○ 「ひとつのドメインとして一箇所に凝集されているべきだったもの」をまとめる ○ ビルドの並列性も向上する ● チームの粒度に沿ったプロジェクト構成にするために議論を続ける ○ チームを増やしたり減らしたりという試行錯誤もしている ○ 前例のないシステムを作っているので、フットワーク軽くやっていくのが重要 22

Slide 23

Slide 23 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta Henryモノレポの課題を解決する 1. コード以外のモノレポ化を進める a. APIスキーマもモノレポの管理下に置く b. 関連サービスを一発で起動できるdocker-composeファイルの作成 2. モノレポとしての行儀を良くする a. プロジェクト構造リファクタリング b. テストの活用 23

Slide 24

Slide 24 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta テストを活用する 1. テストを書きにくくしている技術的課題の解決 a. マスターデータに依存したコードが多いという前提条件 b. データベースが起動していないとテストが実行できない→Testcontainers c. データベース(Postgres)を起動するのに時間がかかる→Testcontainers d. テストが現在時刻に依存しがち→Clockインタフェースの実装をconstructor injection 2. 自動テストの実行を爆速化 a. マルチスレッド化 b. マルチプロセス化 i. Fan-out ii. Test Distribution c. Predictive Test Selection d. Gradleサブプロジェクトの分割 24

Slide 25

Slide 25 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta モノレポ化は銀の弾丸ではなく、長い旅の始まり - 良いドメイン境界を探して試行錯誤を続けていく組織としての姿勢が大切 - 変化をし続けるための基盤としてのモノレポの価値 - つらいこともあるが、解決すればいいだけ - モノレポはいいぞ! まとめ 25

Slide 26

Slide 26 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta We are hiring!! https://henry.jp/ https://dev.henry.jp/ 技術ブログやってます Thank you 26

Slide 27

Slide 27 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta 27 Q&A

Slide 28

Slide 28 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta SlackやNotionを活用した同期的・非同期的なコミュニケーションを厚くとり、 混乱を抑えることを意識しました。またsubmoduleから始めて並行期間を設け、 早く失敗する・すぐ直せるように意識していました。詳細は技術ブログで! 28 Monorepoにするときに混乱しなかった? https://dev.henry.jp/entry/backend-monorepo-part-2

Slide 29

Slide 29 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta GradleでビルドしているServer-side Kotlinプロジェクトの場合、ビルドのボト ルネックはだいたいテスト。2プロジェクトを並列してビルドすれば、CIビルド に必要な実体験時間はほぼ変わりません。 なお2リポジトリに共通して存在したクラスを統合し共通ライブラリとして括り だした関係で、トータルの(GitHub Actionsの課金根拠となる)ビルド時間は短 縮されています。 29 CIが遅くならない?

Slide 30

Slide 30 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta なります。 ただできるだけわかりやすくなるような書き方はあると思っていて、GitHub Actionsのreusable workflowを使うとか、できるだけGradle世界で完結させて GitHub Actionsのジョブはシンプルに保つとかの戦い方を選択しています。 30 CI複雑にならないですか?

Slide 31

Slide 31 text

Copyright © Henry, Inc. All rights reserved. #hack_at_delta モノレポ化もそうですが、多くの問題解決はひとりでは実行できません。弊社の このモノレポ化プロジェクトでもGradleに詳しい人、bash scriptでの自動化に 明るい人、detektプラグインを書いた人、サービスの構成に詳しい人など多くの エンジニアが協力しています。 ですから自分ではわからないことやできないことに遭遇したときに、自ら学ぶこ とも大切ですが、他のひとに助けを求めてチームで解決することもできるように なると良いと思います。こうした協力関係のうえに、チームとして・サービスと しての問題解決が成り立つものだと考えます。 31 エンジニアにとって大切なことは何か?