この記事は、Bill One開発Unitブログリレー2025の第7弾、およびSansan Advent Calendar 2025、8日目の記事です。

こんにちは、Bill One Engineering Unitでチーフアーキテクトを担当している加藤です。この記事では、Bill Oneで実施している、複数のマイクロサービスに緩やかに統一感を持たせるための試みである「Service Matrix」をご紹介します。
背景
Bill Oneではマイクロサービスアーキテクチャを採用しており、現在は16個の主要マイクロサービス*1を27チームで開発・運用しています。マイクロサービス単位の開発体制の構築により、チーム間でのコミュニケーションのオーバーヘッドを減らして、アジリティ高く開発できています。
マイクロサービスアーキテクチャには、マイクロサービスごとに自由な技術選定を行えるメリットもあると言われます。しかし、マイクロサービス間で技術の差異が大きいと、ナレッジの共有が行いづらかったり、メンバーがチーム間を異動したときにキャッチアップのコストが大きくなったりします。このため、特別な理由がない限りは、使用する技術を揃える方が良いと考えています。
一方で、独自フレームワークや独自プラットフォームを作り、ガチガチに統一してしまうのも考えものです。良さそうな新しい技術を一部のマイクロサービスで試してみることが難しくなり、各チームの自律性や独自性が失われます。そこで生まれたのが、緩やかな標準化を促すService Matrixです。
Service Matrixとは
Service Matrixはシンプルなスクリプトで、マイクロサービス群のソースコードを走査し、それぞれのマイクロサービスがConcern(統一したい・追跡したいトピック)を満たしているか確認します。
Concernの例には次のようなものがあります。
- Artifact Registryへの移行: Cloud RunでContainer Registryを使っているサービスをArtifact Registryに移行したい(完了済み)
- 共通ライブラリの導入: マイクロサービス間の重複実装を共通ライブラリに置き換えたい(進行中)
- Flyway CLIへの移行: DBマイグレーションに使うFlywayの実行方法をGradleからCLIに変更する(進行中)
マイクロサービス × Concernの組み合わせでMatrixを作り、Google Spreadsheetに保存・可視化します。実行例は次のようになります。

縦軸がマイクロサービス、横軸がConcernに対応し、対応状況がtodo/doing/doneで表されています。Concernは必ずしも全部のサービスが対象になるものではないので、対象外のセルは空白になっています。なお、枠線で強調されているセルは、前月からの差分があるセルです。
これを見ると、どのサービスがどのConcernに対応済みであるかが一目瞭然です。現在では、対応完了したものを除いて、15個程度のConcernがトラッキングされています。
マイクロサービスにおいて推奨されるべき方針を決めたとしても、チームごとの状況も異なるので、必ずしも全マイクロサービスに同時に展開できるわけではありません。Service Matrixによってマイクロサービスごとの展開状況を可視化することで、対応すべきことを忘れないようにして、自然と対応した方がよいと感じさせることができます。
Service Matrixの実装
Service MatrixはDenoスクリプトとして実装しており、各ConcernはTypeScriptのクラスに対応します。あまり厳密性が求められるものではないので、ファイルに文字列が含まれているかどうかのザックリとした判定を多用しています。
例えば以下のようなイメージです。私たちは複数のマイクロサービスのソースコードを1つのGitHubリポジトリに格納するモノレポ構成を採用しており、リポジトリ内の全マイクロサービスを対象に getStatus メソッドが呼び出され、判定結果を返します。
export class Concern extends BaseConcern { override name: string = "Artifact Registry"; override url: string = "https://www.notion.so/*****"; override async getStatus(service: string): Promise<Status> { const deployShellContent = await getDeployShellContent(service); if (deployShellContent?.includes("asia.gcr.io")) { return "todo"; // Container Registryを使用中 } if (deployShellContent?.includes("asia-northeast1-docker.pkg.dev")) { return "done"; // Artifact Registryだけを使用中 } return ""; // 対象外 } }
Concernは、汎用的なLinterのような存在です。プログラムコードに対するLinterであれば、既存のものがあるので、それを使えば十分です。今回はマイクロサービスの設定など、特定のプログラミング言語に縛られないチェック処理が必要だったので、スクリプトを独自実装することとしました。
新しいConcernは、AIエージェントにお願いすれば、サクッと実装してくれます。
他のアプローチとの比較
ここまでService Matrixについて説明してきましたが、他のアプローチと比較してみましょう。統一感を出すためのアプローチは大きく3段階で考えられます。下のものほど、強制力が強い一方で仕組みの構築・保守にコストがかかります。
- ガイドライン
- 「こうすべき」を文書で示します。文書を書くだけで簡単に始められ、状況に応じた判断もしやすい反面、書いてあることが守られていなくても気づくのが難しくなります。
- ガードレール
- 「こうすべき」をLinterで自動チェックして指摘します。ある程度(1日〜数日で可能な規模)の実装は必要ですが、方針が守られているかを自動でチェックし、可視化できます。ただし、自動で修正できるわけではなく、修正するかどうかはチームの判断に委ねられます。
- 標準化
- 「こうすべき」をフレームワークなどの仕組みとして強制します。全サービスが自動的に標準に従うので、強制力を持って統一できます。一方で、初期の実装や保守に一定のコストを支払う必要があります。フレームワークが適切に保守されない場合、柔軟性が失われて変化に対応するのが難しくなってしまうリスクがあります。

Service Matrixは、マイクロサービスのコードだけでなく設定などを含めた汎用的なガードレールとなることを目指して作成しました。フレームワークを作って標準化するほどのコストはかけずに、Platform Engineeringの最初の一歩を踏み出すことができると考えています。
Service Matrixの運用と効果
私たちの組織では、Bill Oneの開発者向けに「Bill One Tech Now」というイベントを毎月開催しています。その中では、最近作成されたADR (Architecture Decision Record) や、技術バックログの進捗状況を共有するほか、このService Matrixについても前月との差分を見て、改善状況を共有しています。
Service Matrixは緩やかな統一を促す仕組みなので、強制力を持って一気に改善されるわけではありません。それでも皆の取り組みによって毎月少しずつ改善があり、機械的にチェックして可視化する仕組みの効果を実感しています。
また、Concernを追加する際には、マイクロサービスのテンプレートにも改善を適用しておくのが大切です。これによって、マイクロサービスを新しく作ったときには、すべてのConcernを満たした状態で作成されるようになります。
最後に
組織の規模や状況に応じて、狙うべき自由度や当てはまる解決策は異なります。本格的なPlatform Engineeringに取り組むにはまだ早いと感じられる組織において、こういう解決策もありなんじゃないかという意味でService Matrixをご紹介しました。
もっとよい方法があるよと思われる方は、ぜひ教えていただけると幸いです。
Sansan技術本部ではカジュアル面談を実施しています
技術本部では中途・新卒採用向けにカジュアル面談を実施しています。Sansan技術本部での働き方、仕事の魅力について、現役エンジニアの視点からお話しします。「実際に働く人の話を直接聞きたい」「どんな人が働いているのかを事前に知っておきたい」とお考えの方は、ぜひエントリーをご検討ください。
*1:小さいものを含めると40程度