Nguyen Le Phong

ソフトウェアアーキテクチャの基礎全 6 回中第 6 回

Micro-Frontends:いつ価値があり、何が実際にかかるか

フロントエンドを独立してデプロイ可能なピースに分割することでチームが解放されることも、複雑さに埋もれることもあります。Angular ホスト+ React モジュールをスケールで出荷した経験から:Micro-Frontends が見返りをもたらす場面と、それに伴うコストを正直にお伝えします。

二十人の開発者のための整然とした Angular アプリとして始まったリポジトリが、三年後には五十人以上のエンジニアが毎日コミットしていると想像してください。すべてのプルリクエストが同じバンドルに触れます。チェックアウトフローのバグ修正が、誰かがこっそり変更した共有ユーティリティを両方インポートしているためにオンボーディングウィザードを偶然壊します。リリースカレンダーはテトリスゲームのように見えます――五つのチームが一つのスケジュールされたデプロイウィンドウに機能を並べようとしています。全員が全員を待っており、誰も望むほど速く出荷できません。

これがMicro-Frontendsというフレーズをフロントエンドアーキテクトが囁き始める痛みです。アイデアは魅力的に聞こえます:マイクロサービスがバックエンドチームをモノリスから解放したなら、UIでも同じことができないのか?各チームに独自の独立してデプロイ可能なフロントエンドスライスを与え、ブラウザー(またはサーバー)がそれらを一つのシームレスなプロダクトにつなぎ合わせるようにします。

しかし、そのアナロジーは両方向に切れます。マイクロサービスは本物の自由と本物の運用上の痛みをもたらしました。Micro-Frontends も同じです。複数チームの会社で Angular ホストに React 製フィーチャーモジュールを出荷したことから、正直なバージョンをお伝えします:うまくいったこと・痛かったこと・そして分割を始める前に答えるべき質問。

Micro-Frontends とは何か

この用語は2016〜2017年頃に、マイクロサービス革命がブラウザーに届いていないことにチームが気づいたとき広まりました。古典的なシングルページアプリケーションでは、一つのモノリシックなフロントエンドバンドルがすべてを所有します:ルーティング・状態・すべてのコンポーネント・すべてのチームの機能。Micro-Frontends はUIレイヤーに同じ分解のアイデアを適用します。

Micro-Frontend は一つのチームがエンドツーエンドで所有する、独立してビルド可能で独立してデプロイ可能なUIのピースです。そのチームは独自のリポジトリ(または少なくとも独自のビルドパイプライン)・独自のリリースサイクル・合意されたバウンダリー内での独自の技術選択を管理します。実行時には、シェルアプリケーション――ホストまたはコンテナとも呼ばれる――がこれらのピースをユーザーが見る統一されたプロダクトに組み合わせます。

重要な変化はオーナーシップです。共有コードを持つモノレポでは、共有ユーティリティへの変更がどのチームの機能も壊す可能性があります;調整は常に必要です。Micro-Frontends では、チームAのチェックアウトモジュールのデプロイはチームBのダッシュボードチームの承認を必要としません。彼らの間の契約は共有ソースコードではなく、合意された統合インターフェースです。

トップのシェル/コンテナアプリが、チームA・チームB・チームCからの独立してデプロイされたフロントエンドモジュールをブラウザーで一つのページに組み合わせます。 Shell / Container App routing · auth · shared nav · orchestration TEAM A Checkout MFE React · own deploy TEAM B Dashboard MFE Angular · own deploy TEAM C Profile MFE Vue · own deploy v2.4.1 · deployed v1.9.0 · deployed v3.1.2 · deployed BROWSER — composed at runtime into one seamless product
シェルアプリはルーティング・認証・グローバルナビを所有します。各チームは独自のケイデンスで独自の Micro-Frontend を出荷します。ブラウザーはそれらを一つの体験に組み立てます――三つのチームが独立してデプロイしたにもかかわらず、ユーザーには一つのプロダクトとして見えます。

統合アプローチ

「Micro-Frontends」は単一のテクノロジーではなく、技術の家族です。ピースをどうつなぎ合わせるかはチームの自律性・パフォーマンス・運用上の複雑さに大きな影響を与えます。五つの主なアプローチを紹介します:

アプローチどう機能するか主なトレードオフ
ビルド時統合(npmパッケージ) 各 Micro-Frontend がバージョン管理された npm パッケージとして公開される。シェルはそれらを依存として インストールし、すべてをバンドルします。 設定が簡単ですが、チームはリリースを調整しなければなりません――リモートを更新するにはシェルを再デプロイする必要があります。本当には独立していません。
サーバーサイドコンポジション リバースプロキシまたはエッジレイヤー(例:Nginx・Next.js エッジ関数・Zalando の Tailor)が異なるサービスから HTML フラグメントを取得し、レスポンスがブラウザーに届く前に組み立てます。 SEOと初期描画に優れていますが、インフラの複雑さとサービス間の新しいレイテンシ面を追加します。
Module Federation によるランタイム統合 Webpack 5(または Rspack/Vite の同等物)により、ビルドが別の CDN URL から実行時にシェルによってロードされるモジュールを公開できます。再バンドルなし。 本当の独立性――リモートはシェルに触れずにデプロイできます――しかしバージョンのずれ・共有依存の交渉・デバッグツールが難しい。
iframe 各 Micro-Frontend が独自の iframe で実行されます。分離はほぼ完璧で;通信は postMessage 経由です。 岩のように堅固な分離とセキュリティバウンダリーですが、UX がひどい(スクロール・フォーカス・ディープリンク・アクセシビリティはすべてカスタム配管が必要);時代遅れに感じられます。
Web Components 各 Micro-Frontend がカスタム HTML 要素(<checkout-app>)を公開します。シェルがページに要素を配置し;ブラウザーがライフサイクルを処理します。 設計上フレームワーク非依存ですが、SSR サポートが未熟で、複雑な共有状態はまだグローバルイベントバスまたはコンテキストソリューションを必要とします。

実際には、Module Federation が本物のランタイム独立性を望む大規模チームの支配的な選択になっています。それを出荷する Webpack 5 プラグインは Rspack に移植されており、Vite の同等物もあります(例:@originjs/vite-plugin-federation)。今日「Micro-Frontends をやっている」と言う人は、ほぼ常に Module Federation を意味します。

ヒント:SEOが重要なら最初はサーバーサイドコンポジション

アプリが検索結果でランクされる必要があり、Micro-Frontend のアイデアに初めて触れているなら、サーバーサイドコンポジションはブラウザーが触れる前に最もクリーンな HTML を提供します。Module Federation はパワームーブですが、見返りをもたらす前により成熟したデプロイストーリーが必要です。

チームが採用する理由

Micro-Frontend に移行する動機は、私が見てきた企業全体で一貫しています。ほとんど常に四つのプレッシャーのいずれかに起因しています:

  • 独立したデプロイ。最も多く挙げられる理由。十五のチームが一つのフロントエンドビルドを共有していると、デプロイは調整の税金です――全員が全員の作業が QA をクリアするのを待ちます。Micro-Frontends はチームAがチームBの未完成の機能を待たずに火曜日に出荷できるようにします。リリース頻度が上がり;リリースごとの影響範囲が下がります。
  • チームの自律性とオーナーシップ。自分のスライスをビルド・テスト・デプロイできるチームはより速く動き、より責任を感じます。「フルスタックオーナーシップ」は、フロントエンドが全員が躓く共有コモンズでなければ本物になります。
  • 段階的なテクノロジー移行。これは過小評価されています。五年前の AngularJS アプリを動かしていて React に移行したいなら、全部を一度に書き直すことはできません。Micro-Frontends は残りの AngularJS アプリを動かし続けながら、一度に一つのルートを新しい React モジュールに置き換えることを可能にします。ストラングラーフィグパターンをフロントエンドに適用したものです。
  • 障害の分離。チェックアウト Micro-Frontend での JavaScript ランタイムエラーはチェックアウトモジュールをクラッシュさせますが、アプリ全体はクラッシュさせません。シェルはエラーバウンダリーをキャッチし、フォールバックを表示し、ユーザーがナビゲートできるようにします。モノリスでは、キャッチされないエラーがしばしばページ全体を壊します。

本当のコスト

ここで多くのブログ記事が静かになります。Micro-Frontends は本物の請求書を持っており、申し込む前にそれを明確に見るべきです。

バンドルと依存の重複。三つの Micro-Frontend がそれぞれ独自の React のコピーをバンドルすると、ユーザーは React を三回ダウンロードします。Module Federation の共有スコープメカニズムは実行時に重複排除できますが、バージョンがずれるときにチーム間で正しく設定することは自明ではありません。ナイーブな Micro-Frontend アーキテクチャは実際に、よく最適化されたモノリスと比べてペイロードを膨らませることがあります。

デザインシステムの共有。統一されたルック&フィールは共有コンポーネントライブラリを要求します。そのライブラリがビルド時(npm)に消費されるなら、それを更新するすべての Micro-Frontend が再デプロイしなければなりません。Module Federation 経由で実行時に消費されるなら、バージョニングと互換性の戦略が必要です。どちらにしても、デザインシステムはクロスチームの調整ポイントになります――それを排除しようとしていたまさにそのもの。

グローバル状態と Micro-Frontend をまたぐコミュニケーション。Micro-Frontends は独立しているべきですが、ユーザーは全体的です。シェルの通知バッジはチェックアウトモジュールのアクションを知る必要があります。一つのモジュールの認証イベントはどこにでも伝播しなければなりません。解決策は共有 Redux ストア(密なカップリング)からカスタムイベントバスまたはグローバル window オブジェクトの共有コンテキストまで多岐にわたり――これらはすべて規律なしに使うと問題になるアンチパターンです。

バージョンのずれ。チームが独立してデプロイするため、特定の瞬間にシェルがリモートエントリー形式 v1 を期待する Module Federation のバージョンを実行している一方で、チームCの最新デプロイが形式 v2 を発行することがあります。これらの不一致はローカルで再現しにくく、本番でトレースするのがさらに難しい不可解なランタイムエラーとして現れます。明示的な互換性契約と段階的劣化戦略が必要です。

ランタイムパフォーマンス。複数の非同期バンドルロード・ランタイムモジュール交渉・リモートエントリーのウォーターフォールフェッチ――Micro-Frontends はすべてが静的にバンドルされたモノリスには単純に存在しないレイテンシを導入します。慎重なプリロード・CDN 戦略・HTTP/2 プッシュはすべて助けになりますが、積極的な投資が必要です。

より重い運用と観測可能性。N個のデプロイパイプライン・N個の CDN キャッシュバスティングルール・N個のビルド設定・そして何かがモジュールバウンダリーをまたいで間違ったときに相関付けるN個のエラーログが生まれます。DevOps オーバーヘッドは本物です。本番に行く前に分散トレーシング・Micro-Frontend バージョンを含む構造化ログ・共有アラートダッシュボードが必要です。

複雑さは常にどこかに行く

モノリスを独立したピースに分割しても総複雑さは減りません――それはソースコードから統合レイヤー・運用ツール・クロスチームの契約に移動します。もし組織がその運用インフラへの投資の準備ができていなければ、分散モノリスになるでしょう:モノリスのすべてのカップリングに加えて、分散システムのすべての運用オーバーヘッド。

Angular ホスト+ React モジュールの出荷:正直な記録

数年前、私は大規模な Angular プラットフォーム――数十万行・五つのプロダクトスクワッド・ホスタージ状況のように感じられた四半期リリースケイデンス――を Module Federation アーキテクチャに移行したチームの一員でした:独立してデプロイされた React フィーチャーモジュールをホストする Angular シェル。

本当にうまくいったことを紹介します。

  • 独立したデプロイサイクルが文化を変えました。二ヶ月以内に、歴史的に四半期ごとに出荷していたスクワッドが毎週出荷するようになりました。フィードバックループが圧縮されました。エンジニアは観測可能性をもっと気にし始めました、なぜなら彼らが自分たちのデプロイが出た後のダッシュボードを見ていたからです。
  • フィーチャーの分離でリグレッションの表面積が劇的に減少しました。課金モジュールへの変更がユーザー設定ページを壊す理論的なパスがなくなりました。チームごとのリグレッションテストスイートの範囲が縮小しました;インテグレーションテストはアプリ全体ではなく契約ポイントに焦点を当てました。
  • 段階的な移行が命綱でした。六ヶ月の「大爆発」の書き直し凍結がありませんでした。React モジュールは十八ヶ月にわたって一度に一つのルートで Angular ビューを置き換え、プロダクトは出荷を続けました。ビジネス関係者は移行にほとんど気づきませんでした――それがまさに望んでいることです。

痛かったことを紹介します。

  • 共有状態は絶え間ない頭痛の種でした。最終的にグローバル window オブジェクトにカスタムイベントバスを持つことになりました――機能はしますが、脆弱。二つのチームが独立してイベントのペイロード形状を変更したとき、特定のナビゲーションシーケンスでのみ現れる無音のバグが発生しました。最終的に Micro-Frontend をまたぐイベントを内部APIのようにモデル化し、スキーマレジストリを作りました。それは大いに助けになりましたが、構築に何週間もかかりました。
  • 重複した依存がバンドルを膨らませました。Angular と React という二つの異なるビルドシステムにわたって Module Federation の shared 設定を正しく行うには本物の努力が必要でした。何スプリントもの間、ユーザーは私たちが気づく前に RxJS の二つのコピーとグラフライブラリのほぼ二つのコピーをダウンロードしていました。CI での自動バンドル分析が不可欠になりました。
  • バージョン調整は完全にはなくなりませんでした。シェルの Angular バージョンと React モジュールの依存マトリックスは緩やかに互換性を保たなければなりませんでした。Angular がメジャーアップデートをリリースしたとき、シェルをアップグレードするだけではできませんでした;まず各モジュールのピア依存関係を調査しなければなりませんでした。調整コストはモノリスよりも低かったですが、消えはしませんでした。

最終評価:そのアーキテクチャはそのスケールのその組織にとって正しい選択でした。しかし正直に言えば、私たちは運用への投資を約三十パーセント過小評価しており、共有状態の問題が予測した二倍の時間がかかりました。目を開けて取り組んでください。

Micro-Frontends を使うべきでないとき

Micro-Frontends が状況に合っていない最も明確なサインは、フロントエンドの痛みの主な源がチームスケールの調整ではなく、まったく別のものであるときです。

  • 一つの小規模チーム。フロントエンドの全員が一つのビデオ通話に収まるなら、調整の問題はありません。整理すべきコードベースがあります。Micro-Frontends はチームの自律性の利点なしにすべての運用オーバーヘッドを与えます。代わりに、よく強制されたモジュールバウンダリーを持つ Modular Monolith フロントエンドを使ってください。
  • 小規模なアプリケーション。フロントエンド全体が少数のルートと数千行であれば、分割するとプロダクト自体よりも多くのインフラ表面積を作ります。Module Federation の設定とマルチパイプライン CD のオーバーヘッドが利益をはるかに上回ります。
  • 良いバウンダリーを持つモノレポで十分な場合。Nx・Turborepo・類似ツールにより、厳密なモジュールバウンダリーを強制し、影響を受けるパッケージのみのビルドを実行し、チームにある程度のオーナーシップを与えることができます――ランタイムコンポジションの複雑さなしに。20〜80人のエンジニア範囲の多くの企業にとって、よく構成されたモノレポの方が良いトレードオフです。リファクタリングも劇的に簡単です。
  • チームがまだ基礎に慣れていない場合。CI/CD パイプラインが不安定・観測可能性のストーリーが薄い・未解決のクロスチームのコミュニケーション機能不全がある場合、Micro-Frontend の複雑さを追加するとそれらの問題すべてを増幅します。まず基盤を直してください。

これはバックエンドの決定と密接に類似しています。すべてのバックエンドがマイクロサービスの群れであるべきではありません――そして同じ推論がここにも適用されます。モノリス → マイクロサービスの解説をまだ読んでいなければ、バックエンドを分割する前に尋ねる質問はフロントエンドにほぼそのまま当てはまります:独立したスケーリングニーズ・独立した障害ドメイン・本当に自律的なチームがありますか?そうでなければ、モノリス――または Modular Monolith――おそらく良い答えです。

Modular Monolith のスイートスポット

厳格なリントバウンダリー・チームごとに所有されたパッケージ・高速な増分ビルドシステムを持つよく整理されたフロントエンドモノレポは、運用コストのほんの一部で自律性の利点の70〜80%を与えます。Module Federation に手を伸ばす前に、現在のコードベースのよりクリーンなモジュールバウンダリーが実際の問題を解決するかどうかを尋ねてください。

会社の規模ごと

この決定に対する最も有用なレンズの一つは単純に:何人のフロントエンドエンジニアがいて、チームはどれだけ独立して運用する必要があるかです?

組織の規模典型的なフロントエンドチーム構成推奨実例パターン
小規模(FEデベロッパー15人未満) 一〜二スクワッド、全員がお互いのコードを知っている。 使わない。Modular Monolith またはよく構成されたモノレポを使う。Micro-Frontends の調整オーバーヘッドが利点を上回る。 初期 SaaS スタートアップ:フィーチャーフォルダーと厳格なインポートを持つ Next.js アプリ――速く出荷でき、推論しやすい。
中規模(FEデベロッパー15〜60人) 三〜八スクワッド、デプロイの競合とオーナーシップの摩擦を感じ始めている。 場合によっては、シームで。最も摩擦の高いバウンダリーのみを抽出することを検討する――例えばチェックアウト・レポートダッシュボード――すべてを分割するのではなく。ビルドキャッシングを持つモノレポが先にそれを解決するかもしれない。 スケールアップeコマース:ほとんどの機能にモノレポ、決済フローのみ Module Federation リモート(PCI分離チーム・別のデプロイ)。
大規模 / エンタープライズ(FEデベロッパー60人超) 多くのスクワッド、しばしばタイムゾーンをまたいで、ハードなチームオーナーシップバウンダリーと別のロードマップ。 多くの場合正当化される。共有デプロイの調整オーバーヘッドは本物で測定可能です。専任プラットフォームチームを持つ Module Federation またはサーバーサイドコンポジションは妥当な投資です。 大手銀行・通信会社・グローバル小売:プラットフォームチームが所有するシェルアプリ;各自のCD パイプラインとバージョン契約を持つ機能部族が所有する数十の Micro-Frontend。

Spotify のエンジニアリングブログは「スクワッドモデル」とそれに伴うフロントエンドアーキテクチャの決定を文書化しています。Zalando はTailorサーバーサイドコンポジションアプローチについてオープンに書いています。IKEA のデジタルプラットフォームチームはスケールでの Module Federation について議論してきました。これらの企業の共通点はテクノロジーではありません――スケールです:本当に独立したロードマップを持ち、そうでなければ毎日お互いをブロックするであろう多くの自律的チーム。

スペクトルの反対側では、20〜50人の開発者の範囲で私が見てきた最も生産的なフロントエンド組織のいくつかは、厳格に強制されたモジュールバウンダリーと高速な増分 CI を持つ単一の Nx モノレポで全てを動かしています。彼らは高速なビルド・明確なオーナーシップ・ゼロのランタイムコンポジションバグを得ています――ランタイムコンポジションがないからです。会社が成長するにつれて六ヶ月ごとに Micro-Frontend の質問を再検討し、それがまさに正しいです。

まとめ

  • Micro-Frontends はマイクロサービスの分解アイデアをUIに適用します:独立してビルド可能で独立してデプロイ可能なフロントエンドスライス、それぞれが一つのチームに所有され、一つのプロダクトにランタイム(またはビルド時・サーバーサイド)で組み合わせられます。
  • Module Federation(Webpack 5 / Rspack / Vite)は支配的なランタイムアプローチです――本当のデプロイ独立性を提供しますが、慎重な共有依存の設定とバージョン契約管理が必要です。
  • コアの利点はデプロイ独立性・チームの自律性・段階的なフレームワーク移行・障害の分離です。スケールでこれらが本当に必要でなければ、コストを払っても見返りがありません。
  • 本当のコストはバンドルの重複・共有デザインシステムのガバナンス・Micro-Frontend をまたぐ状態の複雑さ・バージョンのずれ・ランタイムレイテンシ・より重い DevOps です。これらはどれも致命的ではありません――しかしすべてが積極的な投資を必要とします。
  • 小規模チーム・小規模アプリ・よく構成されたモノレポが実際の摩擦を解決する場合は Micro-Frontends を使わない。Modular Monolith は過小評価されています。
  • アーキテクチャをチームトポロジーに合わせる:小規模チーム → Modular Monolith;中規模 → モノレポまたは外科的な MFE 分割;大企業 → 専任プラットフォームチームを持つフル Micro-Frontend プラットフォーム。
  • 複雑さは常にどこかに行きます。Micro-Frontends はそれをソースコードから統合契約と運用インフラに移動します。コミットする前に組織がそのシフトを所有する準備ができているかどうかを確認してください。

この記事はフロントエンドとバックエンドアーキテクチャのシリーズの一部です。ここに最初に来た場合は、シリーズが始まるところに戻ることをお勧めします――Ports & Adapters――これは Hexagonal Architecture パターンと、周りにあるフレームワークやデリバリーメカニズムに関係なく、コアビジネスロジックをクリーンでテストしやすい状態に保つ方法をカバーしています。アイデアは補完的です:単一のバックエンドサービス内に明確なバウンダリーを置く同じ考え方が、より大きな粒度でフロントエンドチーム間のバウンダリーに適用されます。より多くのアーキテクチャの記事が来る予定です――サインアップするかまた来てください。ここでお会いできることを楽しみにしています。