こんにちは、SmartHRでプロダクトエンジニアをしているkureです。
SmartHRでは2023年から一部パッケージでモジュラモノリス化の取り組みが始まり、2024年にコードベース全体での推進が決まりました。本記事では、私たちがなぜモジュラモノリス化に取り組んだのか、どのような成果と課題があったのかを、現場の実体験を通じてお伝えします。
モジュラモノリスという手法は近年注目を集めていますが、実際に導入・運用してみると理想と現実のギャップに直面することがあります。私たちの経験が、同様の課題を抱える開発チームの参考になれば幸いです。
- 直面していた課題とその背景
- なぜモジュラモノリスを選択したのか
- モジュラモノリス化への道のり
- モジュラモノリス導入前に抱えていた課題は解消されたのか
- 学んだこと
- 今後の取り組み
- まとめ
- We Are Hiring!
直面していた課題とその背景
SmartHRの労務管理システムは、2015年のサービス開始から10年以上にわたってRuby on Railsで開発を続けてきたモノリスアプリケーションです。10年以上の機能拡張を経てコードベースには暗黙的な依存関係が多数蓄積し、開発者の認知負荷が高い複雑さが生まれていました。
この複雑さの根本には、人事労務というドメインの性質があります。この領域は労働基準法や社会保険制度と密接に関わるため、法改正のたびにシステムの対応が必要です。給与計算、年末調整、マイナンバー管理など、人事労務領域に関わる機能はそれぞれが高度に専門的で相互に関連するビジネスルールを持っており、これらのルールは頻繁に変化します。
データの結びつきも、複雑さを増す要因のひとつです。従業員データ、組織データ、給与データ、勤怠データなどは密接に関連しており、例えば従業員の所属部署変更は、権限管理、お知らせ配信、発令管理、各種申請の承認フローなど、システム全体に波及します。 加えて、SmartHRは労務管理機能への継続的な機能追加を続けています。新しい法制度への対応、顧客からの要望に基づく機能拡張、他サービスとの連携など、システムは現在も進化し続けています。
そして、コードベースが巨大化するにつれて、各機能の責任範囲やオーナーシップが不明確になっていきました。新機能をどこに実装すべきか、既存機能を変更する際にどこまで影響が及ぶのか、問題が起きたときに誰が対応すべきかといった判断が難しくなり、開発者の意思決定コストやチーム間の調整コストが増大していました。
開発現場では、次のような場面にしばしば直面していました。
「この変更は他の箇所に影響しないか。影響調査を行ったが、調査範囲外に依存が潜んでいないか不安だ」
小さな変更であっても影響が広範囲に及ぶ可能性があり、実装前の影響調査は欠かせません。しかし、依存関係は明示的にドキュメント化されておらず、コードを詳細に読み込まなければ把握できない状態でした。調査を尽くしたつもりでも、調査範囲外から意図しない依存が見つかることもありました。「この変更が本当に安全なのか」という不安を抱えながら開発を進める状況が、開発効率と新機能開発のスピードに影響を与えていました。
この状況を改善するため、私たちは認知負荷の低減を目標に、アーキテクチャの見直しを検討し始めました。
なぜモジュラモノリスを選択したのか
検討の結果、私たちはモジュラモノリスというアプローチを選択しました。
モジュラモノリスとは、単一のアプリケーションとして運用しながら、コードベースを独立したモジュール(パッケージ)に分割し、モジュール間の依存関係を明示的に管理するアーキテクチャパターンです。マイクロサービスのようにアプリケーションを物理的に分割するのではなく、論理的な境界を設けることで、モノリスの運用の簡潔さを保ちながら、コードの整理と保守性の向上を図ります。
選択の理由は大きく2つあります。
1つ目は、依存関係や影響範囲の把握にかかる認知負荷の低減です。モジュラモノリスによってコードをパッケージ単位に分割することで、これまで暗黙的だった依存関係や影響範囲を機械的に特定できるようになります。これにより、開発者が機能開発そのものに集中できる状態を目指しました。
2つ目は、組織単位とコード単位を一致させることです。現状ではすべてのコードがグローバル空間に存在しているため、すべての開発者がすべてのコードを対象に作業しています。コードをパッケージ単位に分割することで、ドメインやチームとコードの担当範囲が一致し、変更の意思決定をチームに閉じて行えるようになります。また、影響範囲が限定されることで、大胆な変更も行いやすくなります。
一気にマイクロサービスへ移行するという選択肢も検討しましたが、既存の大規模なコードベースをすべて一度に分割することはリスクが高く、現実的ではありませんでした。モジュラモノリスであれば、単一アプリケーションとしての運用を維持しながら、段階的にパッケージ化を進められます。インフラ構成を大きく変えることなく、リスクを抑えつつ継続的に改善できる点も、私たちの状況に合った選択でした。
モジュラモノリス化への道のり
推進体制の変遷
2024年〜2025年上期: 推進決定から体制構築まで
2024年には、これまで一部のパッケージに限られていた取り組みを踏まえ、コードベース全体でモジュラモノリスを推進する方針が組織として決まりました。暗黙的な依存関係に起因する認知負荷の低減と、チームとコードの担当範囲を近づけることは、はじめに述べた課題意識と直結しており、技術的な手段としてのモジュラモノリスを、継続的な開発体制の前提として位置づける判断でした。
2025年上期は、その方針を実行に移すための準備期間でした。中心メンバーによる勉強会を通じてモジュラモノリスの考え方や他社事例を共有し、推進のゴールイメージや進め方について議論を重ねました。専任チームをすぐに立ち上げるのではなく、まず少数で知識と方向性を揃え、のちの組織展開に備える体制づくりがこの時期の主眼でした。
技術選定では、パッケージ境界をコード上で表現し、意図しない依存を検出する手段として Packwerk の採用を決めました。Packwerkは、Railsのコードをパッケージ単位に分割したうえで、静的解析によりパッケージ間の参照を検査するツールです。検出の対象として重要なのが、許可リストにないパッケージへの依存(Dependency違反)と、公開を意図したインターフェースを経由せずに他パッケージの内部へ参照している状態(Privacy違反)です。境界を「約束」として守るための機械的なフィードバックを得る、という位置づけで導入しました。
また、すべての領域に同じ厳しさのルールを一斉に適用するのは現実的ではないという認識のもと、パッケージごとに目指す独立度を段階的に定義する指標として「分離レベル」の整備も始まりました。後述する2025年下期以降の違反解消や運用設計は、この指標とPackwerkの組み合わせを前提に進められています。
2025年下期:技術検証と知見の蓄積
2025年下期、初めてモジュラモノリス推進チームが発足しました。このフェーズは、モジュラモノリスを組織全体に広げる前段階として、技術的な意思決定をするための材料集めの年と位置づけていました。
実際にコードベースをパッケージに分割しながら、各パッケージで発生するDependency違反やPrivacy違反をどう解消するか、モジュラモノリス化をどう進めるべきかという技術的な知見を蓄積していきました。並行して、その知見を組織全体で共有・活用できる仕組みを整えることにも力を入れていました。
2026年上期:イネイブリングフェーズへの転換
2026年上期からは、蓄積した知見を活かしてイネイブリング活動へと転換しました。普段は機能開発を担うチームからメンバーを集め、モジュラモノリスに関する知識を身につけてもらい、それを各チームに持ち帰ってもらうことでチーム全体に知識と意識を広げていくアプローチです。
対象は全チームではなく、機能開発の頻度や技術的負債の蓄積具合などを総合的に判断して選出した一部のチームから始めました。また、ガイドラインの作成とAIエージェントスキルの整備も進め、人間の判断に加えて機械的な支援やレビューの仕組みも合わせて整えています。
各フェーズで生じた課題とその対応
2025年下期の課題:違反解消手法の確立
推進チームが発足した2025年下期時点では、コード上のパッケージ自体はすでに存在しており、境界も一応引かれていました。ただし、Packwerkが検出するPrivacy違反やDependency違反は一切解消されておらず、どのように解消すればよいかが全く分からない状況からのスタートでした。
このフェーズでは、まず違反の解消パターンを定めることに注力しました。依存関係がそれほど複雑でない場所から着手し、徐々により絡み合った場所へと取り組みを広げることで、組織全体に展開できる形の解消パターンを整えることができました。
この過程では、パッケージ間の通信ルールも合わせて定義しています。Packwerkの Privacy Checker を有効にしたパッケージとの通信には、パッケージが外部に公開するインターフェース(以下、Public API)を利用するという方針で、それ以外のアクセスは違反とみなします。一方、Privacy Checker を有効にしていないパッケージについては、許可された依存関係にあるパッケージ間であれば直接参照しても問題ないという設計です。
こうした通信ルールをすべてのパッケージに一律で適用するのではなく、段階的に進められるようにするため、2025年には独自の指標として「分離レベル」を整備しました。前述したように、これはパッケージがどの程度他から独立しているかを示す指標で、Packwerkによる管理の有無や、外部からのアクセスをインターフェース経由に限定するかどうかなど、複数の観点からパッケージの独立度を段階的に定義したものです。レベルが上がるほどパッケージの境界が整理され、チームごとに独立して開発できる状態に近づきます。各パッケージの状況や重要度に応じて目指すレベルを定めることで、現実的なペースでモジュラモノリス化を進める仕組みとして活用しています。
そしてさらに踏み込んだ判断として、一部のコードはそもそもパッケージに切り出さず、依存関係の強制対象外とする放置領域として明示的に位置づけることにしました。パッケージ分割を進める上ではすべてのコードをパッケージに切り出すという選択肢もありましたが、あえてそうしないという判断です。
この判断には2つの理由があります。1つは、2025年上期に推進チーム間で共有していた他社事例を通じて、いきなり全てをパッケージ化する必要はないという学びを得ていたからです。もう1つは、アプリケーション全体で共通して使われているため、パッケージ化しても依存関係の強制という点で意味が薄いと判断したからです。すべてのコードに一律でルールを適用するのではなく、パッケージ間の重要な境界に絞って取り組むことで、現実的なペースで改善を進めるという方針を取っています。
また、Public APIを利用する側のパッケージには、 app/gateways ディレクトリにある種の「腐敗防止層」を導入して、この層からのみPublic APIを呼び出せる設計にしました。これは、Public APIを利用する箇所を限定することで、仕様変更やレガシーなデータ構造がドメインロジックに直接流入することを防ぐための防護層です。利用する側のパッケージを外部の変更から保護する役割と、提供側のパッケージの変更の影響範囲を限定する役割を担っています。

2026年上期の取り組み:知見のガイドライン化とイネイブリング
2026年上期は、2025年下期で蓄積した知見を組織全体へ広げるフェーズに移行しました。技術的な解消パターンはある程度整いつつありましたが、それを各チームが実践できる形に落とし込み、推進チームなしでも自律的に取り組める状態を目指すことが求められました。
このフェーズでは、まず解消パターンをガイドラインとして整備することに注力しました。実際の作業を進めながら内容を継続的に磨いており、現在も更新を続けています。
また、ガイドラインの活用を効率化するため、その内容をAIエージェントスキルとして実装する取り組みも進めています。実装時の補助やレビューをエージェントが担うことで、開発効率の向上とコスト低減を図っています。
各機能開発チームへの知識展開については、推進チームで蓄積した知識を各チームへ伝えるだけでなく、自律的に実践できる状態まで引き上げることが求められます。チームごとに開発スタイルや優先度が異なるため、各推進メンバーが個別にアプローチを工夫しながら活動しています。勉強会の開催に加え、実際の違反解消作業を通じて依存関係の解きほぐし方を実践的に学んでもらうなど、試行錯誤を続けています。
現在直面している課題
これらの取り組みを通じて多くの改善が得られましたが、実際の運用を進める中で新たな課題も見えてきました。
Packwerk導入による副作用
Packwerkを導入することで、違反解消というタスクが明確に見えるようになりました。しかしこれは諸刃の剣で、違反解消自体が目的化してしまい、本来目指していた認知負荷の低減というゴールに目が向きづらくなるという状況が生まれています。違反数を減らすことへの注力が、認知負荷の改善状況と切り離されて語られるケースも見受けられ、何のために取り組んでいるのかという軸を常に意識し続けることの難しさを実感しています。
Packwerkのツールとしての限界
Packwerkの思想においては、パッケージ間の循環参照は禁止されています。しかし私たちのシステムの仕様上、一部の循環参照を意図的に許可したいケースが存在します。Packwerkには、RuboCop が備えているような、特定の行にコメントを追加するだけで検査対象から除外する機能のような仕組みがなく、柔軟な運用が難しい場面があります。こうした限界を踏まえ、社内の技術戦略ではPackwerkを段階的に廃止し、開発標準をより適切に保証できる別の仕組みへ移行することも検討しています。
認知負荷低減の定量化
認知負荷がどれだけ低減できているかを測定する指標が、現状では存在しません。違反数の推移といった技術的な数値は取得できますが、それが開発者の実感としての改善につながっているかを客観的に示す手法がなく、新たに設計する必要があります。「コードの健康状態を把握し、自律的な行動が取れる状態にする」という技術戦略上の目標に対して、測定の仕組みを整えることは急務の課題です。
機能開発との統合
モジュラモノリスの考え方を組織に根付かせるためには、推進チームが主導する形での推進活動だけでは限界があることが分かってきました。開発標準が整備されても、日々の機能開発の中で実践されなければ意味をなしません。今後は機能開発の文脈の中にモジュラモノリスを組み込み、推進チームなしでも自然と実践される状態を目指していく必要があります。具体的にどう実現するかはまだ模索中ですが、この課題こそが今後の取り組みの核心だと捉えています。
モジュラモノリス導入前に抱えていた課題は解消されたのか
2024年から取り組みを開始し、現在に至るまでのモジュラモノリス推進について、元々解決したかった課題がどの程度改善されたのかを振り返ります。
認知負荷は低減できているのか
結論から言うと、部分的には改善されているものの、すべての認知負荷が解消されたわけではありません。
最も大きな改善は、依存関係の可視化です。これまで暗黙的だった依存関係が明示的になり、「このパッケージはどこに依存しているのか」が把握しやすくなりました。新しいメンバーからは「自分が触るべき範囲が分かりやすくなった」という声が聞かれるようになり、コードベースの構造理解が格段に容易になっています。
さらに重要な成果として、新しい認知負荷を作り込みづらくなった点が挙げられます。Public APIの導入と腐敗防止層の設置により、パッケージ間の通信が制御され、意図しない依存関係が生まれにくい構造を実現できました。
また、かつて開発者を悩ませていた「調査しきれない依存関係」への不安も軽減されています。CIで違反が自動検出されるため、コードレビューの時点で問題を発見し対処できるようになったことで、変更に対する心理的な障壁も下がってきています。
現場エンジニアの実感はどうか
現状では、現場エンジニアの実感を定量的に測る指標はまだ作れておらず、アンケートなどで体系的に声を集められているわけでもありません。より正確な評価ができる仕組みを設計している最中であり、今後取り組んでいく必要があると認識しています。
また、そもそもモジュラモノリスが解決できる課題には限界があります。人事労務という業務ドメイン自体が持つ複雑さは、パッケージ境界を明確にしても変わりません。 当初直面していた課題の中には認知負荷以外の問題も存在しており、それらはモジュラモノリスでは解決できないものとして依然として残っています。
こうした経験から、認知負荷には種類があり、モジュラモノリスはそのうちの技術的な依存関係の複雑さに起因するものにアプローチする手段のひとつに過ぎないという認識が、取り組みを通じてより明確になってきました。
学んだこと
認知負荷はゼロにするものではない
推進チームで取り組みを進める中で、チームメンバーから重要な指摘がありました。認知負荷はゼロにすべきものではなく、筋トレのように開発者自身がビルドアップして、その負荷に耐えられるようになることも必要なのではないかという視点です。
推進チームとしては、認知負荷が課題であること、ドメインの複雑さが変えられないことは認識していました。しかし、「認知負荷をどのように改善していくか」という具体的な方向性は明文化されていませんでした。この指摘を通じて、私たちが目指すべきは認知負荷を「悪いもの」として排除し続けることではなく「適切な水準まで下げること」であり、それと同時に組織自体も認知負荷に耐えられるよう育てていく必要があるという考え方を言語化できたことは、推進チームにとって大きな収穫でした。
開発工数の増加は避けられない
リアーキテクチャを進める以上、開発工数の増加は避けられません。インターフェース設計、ADRの作成、違反解消作業など、様々なコストが発生します。時に機能開発を圧迫することもあり、モジュラモノリスの推進を後回しにせざるを得ない場面も出てきます。
それでも、推進し続けることで、これまで開発者が感じていた機能追加に伴う影響調査の困難さ、コードを読み込む際の手がかりのなさ、変更に対する不安といったものが少しずつ解消されていきます。変更の安全性、設計の透明性、将来の柔軟性は、こうした積み重ねの先にあります。
技術よりも組織が難しい
最も難しかったのは、技術的な導入よりも組織的な運用です。アーキテクチャを変えるということは、コードの構造だけでなく、それを扱う組織の動き方まで変えることになります。コンウェイの法則が示す通り、システムの構造は組織の構造を反映するからです。
技術的な方針はある程度議論できますが、その方針を100人以上の開発者が日常的に実践できる状態にするためには、どうコミュニケーションをとり、どうイネイブリングするかという組織的な問いに向き合い続ける必要があります。一方でモジュラモノリスを推進しながら、もう一方で認知負荷に耐えられる組織の力を育てていく、この両輪を同時に動かしていくことの難しさを、身をもって学んでいます。
今後の取り組み
パッケージ全体の状態定義へ
これまでは個別のパッケージにおける違反解消に焦点を当ててきましたが、今後はフェーズを移行し、パッケージ全体を俯瞰してシステムとしてあるべき姿を定義していく段階に入ります。いつまでにどのようなアーキテクチャの状態を目指すのかを明文化し、組織全体で共有した上で、その状態に近づくための具体的なロードマップを技術戦略として提示していくことを考えています。
一方で、依存違反の解消は引き続き必要な取り組みです。そのためのガイドラインの整備やAIエージェントスキルの拡充を続け、より効率的にモジュラモノリスを推進できる環境を整えていきます。
開発標準の運用と組織のビルドアップ
日々の開発においてパッケージに変更を加えるときや、他パッケージと連携する必要が生じたとき、開発者がどのような判断でどのようなアクションを取るべきかをまとめた開発標準を定め、運用・アップデートしていきます。例外が発生した場合のエスカレーション先も含めて明文化することで、推進チームを介さずに判断できる状態を目指します。
引き続きイネイブリング活動も継続しながら、組織としての認知負荷への耐性を徐々に高めていきます。ただし、この取り組みを無期限に続けることはリソース的に難しいため、明確な期限と目標状態を設定した上で進めていく方針です。
地味に見えるかもしれませんが、こうした取り組みを一つひとつ積み重ねた先に、システムがより触りやすく変化しやすい状態になり、開発者の認知負荷が下がり、その先でお客様により多くの価値を届けられると考えています。
まとめ
本記事では、SmartHRにおけるモジュラモノリス推進の取り組みを、背景から現在に至るまで振り返りました。
私たちが直面していた課題は、10年以上にわたる継続的な機能追加の中で生まれた、暗黙的な依存関係に起因する認知負荷でした。PackwerkとPublic API・腐敗防止層の導入により、既存の認知負荷を軽減しながら新しい認知負荷を作り込みにくい構造を実現できています。一方で、業務ドメインが本質的に持つ複雑さはモジュラモノリスでは解決できず、取り組みの範囲と限界が明確になったことも大きな収穫です。
組織的な観点では、2025年下期の推進チームによる知見の蓄積と技術的な基盤作りを経て、2026年上期からはイネイブリングフェーズへと移行しました。各チームが自律的にモジュラモノリスと向き合える状態を目指しながら、その道のりは決して平坦ではなく、技術的な問題よりも組織的な課題の方がはるかに難しいということを身をもって学んでいます。
モジュラモノリスは、技術的な側面から認知負荷に対処する手段のひとつに過ぎません。それを推進しながら、一方で認知負荷に耐えられる組織としての力を育てていくこと、この両輪を動かし続けることが重要だという認識に至っています。
この取り組みは現在も継続中であり、完成という状態はありません。地道な取り組みを一つひとつ積み重ねた先に、システムが触りやすく変化しやすい状態が生まれ、その結果としてお客様により多くの価値を届けられると信じて、引き続き取り組んでいきます。
本記事が同様の課題に向き合うチームの参考になれば幸いです。
We Are Hiring!
SmartHRでは一緒に働く仲間を絶賛募集中です!
日々のプロダクト開発の傍ら、希望があればこういった技術改善の取り組みにも携わることができます。モジュラモノリスのような大規模な技術改善プロジェクトに興味がある方、認知負荷の高いコードベースの改善に挑戦したい方、ぜひお話しましょう!
少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう!