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

目次
はじめに
こんにちは、Bill One Engineering Unit の阿左見です。
現在はワークフロー領域で PdM とエンジニアを行き来しながら、プロダクトの体験づくりに向き合っています。
日々の開発ではアーキテクチャの議論に触れる機会が多くありますが、プロダクトをユーザーに届ける立場として実感するのは、設計上の選択が UX に直結するという点です。
たとえば UI 上では、
- 更新が反映されない
- バリデーションが遅い
- 関係のない画面が巻き添えで失敗する
といった現象が起きます。
しかし、ユーザーが感じるのは 「進まない」「なんだか不安」「気持ち悪い」 といった体験上の違和感です。
この“体験としての違和感”をたどっていくと、高い確率で サービス間通信の構造 に行き着きます。
Bill One では 20 を超えるマイクロサービスが稼働しており、そのつながり方ひとつで体験は大きく変わります。
そこでこの記事では、マイクロサービスを「技術の話」としてではなく、
“どうすればより良い体験を届けられるか”
という視点から、サービス間通信を捉え直してみたいと思います。
マイクロサービスとは
マイクロサービスの理解を深めるために、まず従来の「モノリシックアーキテクチャ(モノリス)」と比較してみます。
モノリス
モノリスは、アプリケーション全体をひとつの大きなまとまりとして構築する方式です。コードベースもデータベースも一つで、デプロイもまるごと行います。この構造はシンプルで理解しやすく、開発初期には大きなメリットがあります。 しかし、プロダクトの規模が大きくなるにつれ…
- ある機能の修正が全体に影響する
- デリバリー速度の鈍化
- 責務の境界が曖昧になり、チーム間で衝突が起きる
- スケール戦略が“一点集中”になりがち
といった課題が目立つようになります。
マイクロサービス
マイクロサービスは、責務ごとにシステムを分割し、サービス単位で独立させていく考え方です。(ワークフローサービス、仕訳サービスなど) データストアもデプロイもスケール戦略もサービス単位で完結でき、組織構造とアーキテクチャが綺麗に一致しやすいという利点があります。
しかし、独立させた途端にもうひとつの問題が立ち上がります。
サービス同士をどうつなぐか、です。
どれほど独立性を高めても、実際のプロダクトでは「認証情報が必要」「他サービスのマスターデータを参照したい」「権限を確認したい」など、サービス間のやり取りを避けて通れません。
そしてこの“つなぎ方”こそが UX の良し悪しを決定づけます。
体験設計の観点で見た「マイクロサービス間通信」
たとえば、ある画面を開くときに、ユーザー情報は A、認証状態は B、権限は C、ステータスは D から取得するとします。設計時は自然に見えるかもしれませんが、ユーザーの目線に立つと途端に問題が表面化します。
画面表示のたびに複数サービスへの問い合わせが発生すれば、当然動きは重くなります。どれか一つが遅くなると、画面全体が引きずられます。さらに下流に障害が起きれば、たとえ別領域のサービスであっても体験に影響してしまう。
ユーザーは「どのサービスが遅いか」なんて気にしません。「重い」「進まない」だけが印象として残ります。その裏側にどれほど複雑な構造があっても、表に現れるのは UX の“重さ”だけです。
この瞬間、通信方式は単なる技術的な選択肢ではなく、体験設計そのものに制約を与える最重要ポイントになります。
サービス間通信方式とUXへの影響
通信方式を大きく分けると 同期通信(Request/Response) と 非同期通信(Event-Driven) があります。どちらも一般的な手法ですが、UX という切り口で見ると、まったく異なる特徴が見えてきます。
同期通信
同期通信は最も馴染みのある方式で、一般的には HTTP や gRPC を使用したリクエスト/レスポンスの流れです。
- A → B に問い合わせる
- B が結果を返すまで A は待つ
- UI もその間は待つ
即時性が必要なケースでは非常に強力で自然な体験を提供できる反面、UX の視点から見ると以下のようなリスクが生じます。
● ① 遅いサービス=遅い画面
サービス B が 2000ms かかれば、画面全体が 2000ms 引きずられます。 さらに、B が C を呼び、C が D を呼んでいる……という構造であれば、遅延はそのまま積み上がります。
ユーザーにとっては、内部構造など関係なく「画面が 2 秒遅い」という事実だけが残ります。
加えて、同期通信では「レスポンスを待つ間、通信コネクションを保持し続けなければならない」という構造的な制約があります。
呼び出しが重なったり、下流(依存される側)の応答が遅れたりすると、その分だけコネクションが専有され、積み上がっていきます。
加えて、API のコネクションだけでなく DB のコネクションプールも圧迫されていき、枯渇が発生する ことも珍しくありません。どこか一つのサービスでコネクションが詰まると、同期している上流(依存する側)の画面全体に遅延が伝播していきます。
結果として、負荷の瞬間的な高まりがそのまま UI の操作性に跳ね返ってきてしまう。これも同期通信が抱える避けがたい弱点です。
● ② 障害が連鎖する
下流のサービスが落ちると、上流が必ず巻き込まれます。
- 顧客情報サービスが遅延すると、画面が表示されない
- マスターデータサービスが落ちると、各画面で更新処理が失敗する
UX への影響があまりに直接的すぎる構造です。
もちろん同期通信でも適切に設計すれば、障害の波及をある程度抑えることはできます。しかし顧客情報やマスタのような根幹サービスに同期的に依存している場合、その遅延や障害が そのままUXに直結しやすい構造 であることは変わりません。
また、同期的に複数のサービスを横断する処理の場合、整合性を保つために Saga などの分散トランザクションパターンが必要になります。しかし、これらは実装も運用も複雑になりやすく、障害時にはロールバックや補償処理が UI 体験に直接影響するという構造的な弱さも抱えています。
非同期通信:操作感を滑らかにする一方で、一貫性の設計が必要
非同期通信は、Pub/Sub や Kafka といったイベント基盤を用いて「起きたことだけを通知する」方式です。
- A はイベントを発行するだけ
- B はそのイベントを購読して自身の状態を更新する
- A → B の直接問い合わせが不要になる
UX 観点では以下の強みがあります。
操作が“軽くなる”
ユーザー操作の完了を待つ必要がないため、UI はすぐに次の動作へ進めます。 更新処理がどれだけ複雑でも、UI はそれに引きずられません。
障害を隔離しやすい
非同期は、処理をサービス間で直接連鎖させません。 A はイベントを発行するだけなので、B やその先のサービスが一時的に落ちていても UI の操作性は保たれます。
同期通信と比べて、障害の境界がはっきりしやすいことも非同期の採用が増える理由です。
これらの強みがある反面、以下ようなの難しさも存在します
非同期先のエラーをどうフィードバックするかが難しい
A → B の問い合わせがないため、「B で失敗した」という事実をユーザーにどう伝えるか、という問題が発生します。
失敗の情報を即座に通知すべきか、一定時間後に反映すればよいのか、UI のどの単位で「失敗」を扱うべきか、どのように通知するのか。これらは技術設計の観点だけ判断できない領域です。
整合性をどう成立させるかの設計が必須になる
非同期では、状態の反映タイミングがサービス間で揃いません。
たとえば、ワークフローのステータスを別のサービスに非同期で連携する場合、反映前にユーザーが操作しようとすると
「あれ?さっき変更したはずなのに、別の画面で見る同じデータが古いまま?」
という疑問につながります。
非同期化は UX に強いが、整合性をどう見せるかという別の UX 課題が生まれるということです。
依存との向き合い方
サービス間通信における本質は、最終的には「依存をどう扱うか」という話になります。
依存は多すぎても、強すぎても、曖昧でも UX に影響が出ます。そして実は、依存の“向き”そのものが正しく設計されているかどうかも重要なポイントです。
依存を“消す”
最初に考えるべきは、そもそもその依存関係が必要なのかという点です。
キャッシュで代替できないか、コピーを持てないか、リアルタイム性が本当に必要なのか。まずは仕様レベルでその依存が本当に必要な依存なのかを見直してみましょう。 なぜなら、ひとつ依存を減らすだけで、体験は大きく変わるからです。
依存を“弱める”
完全に依存を断ち切ることが難しい場合でも、依存の強度を弱めることはできます。たとえば、同期取得しつつ失敗時はキャッシュに切り替える、最小限のデータだけを同期し、重い情報は後追いするなど、段階的な依存にすることで UX への負荷を和らげられます。
依存を“見える化する”
どの画面がどのサービスに依存しているのか。どの遅延がどの体験に影響するのか。これをチーム全体で共有しておくことは、正しい意思決定をするための前提条件になります。依存関係を図として可視化するだけでも、プロダクトのボトルネックは驚くほど見えやすくなります。
依存を“正しい方向に揃える”
依存の有無や強度と同じくらい重要なのが、依存の向き(方向性)が適切かどうかです。
特に問題になりやすいのは、サービス同士が互いを参照し合う 相互依存 の状態です。
片方の遅延や障害がもう一方に伝播し、最終的には UI 全体の不安定さにつながりやすくなります。
これに対し、依存方向をドメインの性質に沿って
“上流 → 下流” に揃えておく と、フローが整理され、どこにリスクや負荷が集まりやすいかを把握しやすくなります。
もちろん、上流で障害が起きれば下流にも影響は及びます。
依存方向を揃えたからといって波及範囲が物理的に小さくなるわけではありません。
しかし構造が明確であることで、
- どこが障害ポイントになりうるか
- どこを同期/非同期で分けるべきか
- どこを疎結合化すべきか
といった設計判断を行いやすくなり、
結果的に UX を損なわないアーキテクチャを選択しやすくなります。
逆に依存の方向が曖昧だと、暗黙の同期フローや循環参照が生まれ、
障害時の切り分けや変更の影響範囲の把握が難しくなるなど、長期的なリスクにつながります。
まとめ
同期通信は体験として自然に見える反面、負荷や遅延、障害の影響がそのまま UI に現れやすい構造を持っています。
非同期通信は操作感を滑らかにできる一方で、整合性の揺らぎやエラー伝達の設計が欠かせません。
依存の量・強さ・向きは体験に直結し、間違った依存は UX の安定性を大きく損ないます。
だからこそ、PdM とエンジニアが共通の視点で、
「この通信方式は、ユーザーの体験をどう変えるだろうか」
と議論し続けることが、プロダクトの体験品質を守り、進化させるうえで最も重要だと考えています。
Sansan技術本部ではカジュアル面談を実施しています

技術本部では中途・新卒採用向けにカジュアル面談を実施しています。Sansan技術本部での働き方、仕事の魅力について、現役エンジニアの視点からお話します。「実際に働く人の話を直接聞きたい」「どんな人が働いているのかを事前に知っておきたい」とお考えの方は、ぜひエントリーをご検討ください。