一.简介
庞大な一塊のバックエンドサービスによる変更と拡張の制限を解決するために、マイクロサービスアーキテクチャ(Microservices) が現れました:
微服务是面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒度服务,并通过轻量级的通信协议组织起来
具体地,将应用构建成一组小型服务。这些服务都能够独立部署、独立扩展,每个服务都具有稳固的模块边界,甚至允许使用不同的编程语言来编写不同服务,也可以由不同的团队来管理
しかし、ますます重くなるフロントエンドエンジニアリングも同様の問題に直面しており、自然にマイクロサービスの思想を適用(そのまま)フロントエンドに応用することを考えつき、こうして*マイクロフロントエンド(micro-frontends)*の概念が生まれました:
Micro frontends, An architectural style where independently deliverable frontend applications are composed into a greater whole.
つまり、独立して配信可能な複数のフロントエンドアプリケーションで全体を構成するアーキテクチャスタイルです。具体的には、フロントエンドアプリケーションをより小さく、よりシンプルで独立して開発、テスト、デプロイ可能な小块に分解し、ユーザーからは依然として凝集した単一の製品として見えるようにします:
Decomposing frontend monoliths into smaller, simpler chunks that can be developed, tested and deployed independently, while still appearing to customers as a single cohesive product.
二.特点
簡単に言えば、マイクロフロントエンドの理念はマイクロサービスに似ています:
In short, micro frontends are all about slicing up big and scary things into smaller, more manageable pieces, and then being explicit about the dependencies between them.
庞大な全体を制御可能な小块に分割し、それらの間の依存関係を明確にします。主な利点は以下の通りです:
-
コードベースがより小さく、より凝集性が高く、保守性が向上
-
疎結合で自律的なチームの拡張性が向上
-
段階的にアップグレード、更新、さらには一部のフロントエンド機能の書き換えが可能になる
简单、松耦合的代码库
一塊のフロントエンドコードベースと比較して、マイクロフロントエンドアーキテクチャ下のコードベースはより小さく/シンプルで、開発が容易になる傾向があります
さらに重要なのは、モジュール間の不合理な暗黙の結合による複雑さの上昇を回避すること���す。明確に定義されたアプリケーション境界によって予期せぬ結合の可能性を低減し、サブアプリケーション間の論理結合のコストを増やし、開発者にアプリケーション内のデータとイベントの流れを明確にさせることを促します
增量升级
理想的なコードは当然、モジュールが明確で、依存関係が明確で、拡張が容易で、保守が convenient なものです……しかし、実践では様々な理由により:
-
歴史プロジェクト、先祖伝来のコード
-
納品プレッシャー、当時は速さを追求
-
近くて慣れている、当時は安定を追求……
常にそれほど理想的ではないコードが存在します:
-
技術スタックが古く、さらには無理に複数の技術スタックを混用
-
結合が混乱しており、手が出せず、一部を動かすだけで全体に影響
-
リファクタリングが不徹底、リファクタリング - 中途半端、別の方法でリファクタリング - また中途半端……
これらのコードを完全にリファクタリングする場合、最大の問題は十分なリソースを用意して一気に完了するのが非常に困難 ということです。段階的にリファクタリングしながら、中間バージョンがスムーズに移行できることを確保すると同時に、新機能を持続的に配信する必要があります:
In order to avoid the perils of a full rewrite, we'd much prefer to strangle the old application piece by piece, and in the meantime continue to deliver new features to our customers without being weighed down by the monolith.
したがって、漸進的リファクタリングを実施するために、新旧コードが調和して共存し、その後徐々に旧コードを変換し、リファクタリングが完了するまで続けることができる増分アップグレードの能力が必要です
この増分アップグレードの能力は、製品機能の低リスクな部分置換 を可能にします。依存項のアップグレード、アーキテクチャの置き換え、UI の改版などを含みます。一方、技術選択の柔軟性をもたらし、新技術、新しいインタラクションモードの実験的試行錯誤に役立ちます
独立部署
独立デプロイの能力はマイクロフロントエンドシステムにおいて極めて重要で、変更範囲を縮小し、関連リスクを低減できます
したがって、各マイクロフロントエンドは独自の継続的デリバリーパイプライン(ビルド、テスト、本番環境へのデプロイを含む)を持つべきであり、独立してデプロイ可能で、他のコードベースやデリバリーパイプラインの現在の状態を過度に考慮する必要はありません:

古いシステムが固定周期の四半期リリースまたは手動リリースであっても、隣のチームが未完成または問題のある機能を誤ってリリースしても問題ありません。つまり、マイクロフロントエンドがリリース準備完了であれば、いつでもリリース可能で、開発保守しているチームによって決定されるべきです
P.S.さらに BFF モード と組み合わせて、さらに一歩進んだ独立性を実現することもできます:

团队自治
コードベースおよびリリースサイクルの結合解除に加えて、マイクロフロントエンドは完全に独立したチームの形成にも役立ち、異なるチームがそれぞれ製品機能の构思からリリースまでの全過程を担当し、チームは顧客に価値を提供するために必要なすべてを完全に所有し、迅速かつ効率的に運営できます
そのために、技術機能に基づいて分割するのではなく、ビジネス機能を中心に縦方向にチームを編成すべきです。最も簡単には、最終ユーザーが見ることができるコンテンツに基づいて分割できます。例えば、アプリケーション内の各ページをマイクロフロントエンドとして、1 つのチームに全権负责させます。技術機能または横断的関心事(スタイル、フォーム、検証など)に基づいて編成されたチームと比較して、この方式はチームの仕事の凝集力を向上させることができます

三.实现方案
実装上、重要な問題 は以下の通りです:
-
複数の Bundle をどのように統合するか?
-
サブアプリケーション間でどのように影響を隔離するか?
-
公共リソースをどのように再利用するか?
-
サブアプリケーション間でどのように通信するか?
-
どのようにテストするか?
多 Bundle 集成
マイクロフロントエンドアーキテクチャには通常、*コンテナアプリケーション(container application)*があり、各サブアプリケーションを統合します。責任は以下の通り:
-
公共のページ要素をレンダリング、例えば header、footer
-
横断的関心事(cross-cutting concerns)を解決、認証やナビゲーションなど
-
各マイクロフロントエンドを 1 つのページに統合し、マイクロフロントエンドのレンダリング領域とタイミングを制御
統合方式は 3 種類に分類されます:
-
サーバー側統合:例えば SSR テンプレート組み立て
-
ビルド時統合:例えば Code Splitting
-
ランタイム統合:例えば iframe、JS、Web Components などの方式
服务端集成
サーバー側統合の鍵は各部分のテンプレート(各マイクロフロントエンド)が独立してリリースできることをどのように保証するかです。必要であれば、サーバー側にもフロントエンドに対応する構造を構築することもできます:

各サブサービスが対応するマイクロフロントエンドをレンダリングしてサービスを提供し、メインサービスが各サブサービスにリクエストを送信
构建时集成
一般的なビルド時統合方式は、サブアプリケーションを独立した npm パッケージとしてリリースし、メインアプリケーションの依存項として共同で、デプロイ用の JS Bundle を 1 つ構築生成することです
しかし、ビルド時統合の最大の問題はリリース段階で結合を引き起こすこと です。サブアプリケーションに変更があると、全体を再コンパイルする必要があり、製品の部分的な小変更でも新バージョンをリリースする必要があることを意味します。したがって、この方式は推奨されません
运行时集成
統合タイミングをビルド時からランタイムに遅らせれば、リリース段階の結合を回避できます。一般的なランタイム統合方式には以下があります:
-
iframe
-
JS:例えばフロントエンドルート
-
Web Components
直感的には iframe は良くないように思えます(パフォーマンス、通信コストなど)が、ここでは確かに合理的な選択肢です。iframe は間違いなく最もシンプルな方式で、スタイル隔離およびグローバル変数隔離を自然にサポートしているからで���
しかし、このネイティブな隔離性は、アプリケーションの各部分を一緒に結びつけるのが非常に困難であることを意味し、ルート制御、履歴スタック管理、ディープリンク(deep-linking)、レスポンシブレーアウトなどが異常に複雑になり、iframe 方案の柔軟性を制限します
もう 1 つの最も一般的な方式はフロントエンドルートで、各サブアプリケーションがレンダリング関数を公開し、メインアプリケーションが起動時に各サブアプリケーションの独立 Bundle をロードし、その後ルート規則に基づいて対応するサブアプリケーションをレンダリングします。現在看来、最も柔軟な方式です
もう 1 つの類似方式は Web Components で、各サブアプリケーションをカスタム HTML 要素としてカプセル化し(フロントエンドルート方案のレンダリング関数ではなく)、Shadow DOM によるスタイル隔離などの利点を獲得します
影响隔离
サブアプリケーション間、およびサブアプリケーションとメインアプリケーション間のスタイル、スコープ隔離は必ず考慮すべき問題で、一般的な解決策は以下の通り:
-
スタイル隔離:開発規範(例えば BEM)、CSS 前処理(例えば SASS)、モジュール定義(例えば CSS Module)、JS で記述(CSS-in-JS)、および shadow DOM 特性
-
スコープ隔離:様々なモジュール定義(例えば ES Module、AMD、Common Module、UMD)
资源复用
リソースの再利用は UI の一貫性とコードの再利用に重要な意味を持ちますが、すべての再利用可能なリソース(コンポーネントなど)を最初に再利用のために引き出す必要があるわけではありません。推奨される做法は、前期にある程度の冗長性を許容し、各 Bundle がそれぞれのコードベースでコンポーネントを作成し、比較的明確なコンポーネント API が形成されるまで待ってから再利用可能な公共コンポーネントを構築することです
一方、リソースは以下の 3 種類に分類されます:
-
基礎リソース:ロジック機能を全く含まないアイコン、タグ、ボタンなど
-
UI コンポーネント:一定の UI ロジックを含む検索ボックス(自動補完など)、テーブル(ソート、フィルタ、ページネーションなど)など
-
ビジネスコンポーネント:ビジネスロジックを含む
その中で、サブアプリケーション間でのビジネスコンポーネントの再利用は推奨されません。高度な結合を引き起こし、変更コストを増加させるためです
公共リソースの所属と管理については、一般的に 2 つのモードがあります:
-
公共リソースはすべての人に所属、つまり明確な所属がない
-
公共リソースは集中管理、专人负责
実践経験から見ると、前者は明確な規範がなく、技術ビジョンから逸脱した寄せ集めになりやすく、後者はリソース作成と使用の脱節を引き起こします。比較的推奨されるモードはオープンソースソフトウェアの管理模式です:
Anyone can contribute to the library, but there is a custodian (a person or a team) who is responsible for ensuring the quality, consistency, and validity of those contributions.
つまり、誰もが公共リソースを補充できますが、品質、一貫性、正確性を保証するために监管する人(またはチーム)がいる必要があります
应用间通信
カスタムイベント を通じた間接通信は直接結合を回避する一般的な方式です。さらに、React の単方向データフローモデルも依存関係をより明確にでき、マイクロフロントエンドに対応すると、コンテナアプリケーションからサブアプリケーションにデータとコールバック関数を渡します
さらに、ルートパラメータは共有、ブックマークなどのシナリオに使用できるだけでなく、通信手段としても使用でき、多くの利点があります:
-
構造が定義されたオープンスタンダードに従う
-
ページレベル共有、グローバルアクセス可能
-
長さ制限により、必要な少量データのみを渡すことを促す
-
ユーザー向け、ドメインモデリングに役立つ
-
宣言的、意味的により一般的("this is where we are", rather than "please do this thing")
-
サブアプリケーション間に間接通信を強制し、直接相手を依存しない
しかし原則として、どの方式を採用しても、サブアプリケーション間の通信を可能な限り削減すべき です。大量の弱い依存による強い結合を回避するためです
测试
各サブアプリケーションは独自の完全なテスト方案を持つべきで、特殊な点は、ユニットテスト、機能テストに加えて、統合テスト も必要です:
-
統合テスト:サブアプリケーション間の統合の正確性を保証、例えばサブアプリケーション横断のインタラクション操作
-
機能テスト:ページ組み立ての正確性を保証
-
ユニットテスト:底层ビジネスロジックとレンダリングロジックの正確性を保証
下から上へピラミッド構造を形成し、各層はその下層でカバーしきれない部分のみを検証すればよいです
四.示例
-
オンライン Demo:https://demo.microfrontends.com/
-
ソースコードアドレス:micro-frontends-demo/container
五.缺点
もちろん、このアーキテクチャモードは百利あって一害なしではなく、いくつかの問題も随之而来ます:
-
依存項の冗長を引き起こし、ユーザーのトラフィック負担を増加
-
チーム自治度の増加、コラボレーションを破壊する可能性
流量负担
独立構築は公共リソースの冗長を意味し、ユーザーのトラフィック負担を増加します
非常に理想的な解決策はありません。シンプルな方案は公共依存を(サブアプリケーションの)構築産物から除外することですが、ビルド時の結合を導入します:
Now there is an implicit contract between them which says, "we all must use these exact versions of these dependencies".
操作/管理上的复杂性
マイクロフロントエンドを採用する前に、まずいくつかの問題を考慮する必要があります:
-
既存のフロントエンド開発、テスト、リリースフローをどのように拡張して多くのアプリケーションをサポートするか?
-
分散した、制御が弱化されたツールシステムおよび開発実践は信頼できるか?
-
様々な���ロントエンドコードベースに対して、どのように品質基準を構築するか?
总之、以前と不同的是、マイクロフロントエンドは一堆の小さいものを生成します。したがって、この方法を採用するために必要な技術と組織の成熟度を備えているかを考慮する必要があります
六.总结
バックエンドに対するマイクロサービスに似て、フロントエンドビジネスもある規模に発展した後、複雑さを分解するためのアーキテクチャモードが必要になり、こうしてマイクロサービス思想のフロントエンド領域での応用、すなわちマイクロフロントエンドが現れました。主な目的は以下の通り:
-
技術アーキテクチャ上のさらなる拡張性(モジュール境界が明確、依存関係が明確)
-
チーム組織上の自治権
-
開発フロー上で独立開発、独立デリバリーが可能
最大の意義は複数技術スタック並存の能力をアンロックしたことで、特に漸進的リファクタリング中のアーキテクチャアップグレード過渡期に適しています:
Suddenly we are not tightly coupled with one stack only, we can refactor legacy projects supporting the previous stack and a new one that slowly but steadily kicks into production environment without the need of a big bang releases (see strangler pattern).
低コストで新技術スタックを試すことを許可し、さらには最も適切な技術スタックを選択して異なることを行うことを許可します(マイクロサービスで異なる言語で異なるサービスを書くことを許可するのと同様):
we can use different version of the same library or framework in production without affecting the entire application, we can try new frameworks or approaches seeing real performances in action, we can hire the best people from multiple communities and many other advantages.
参考資料
-
[I don't understand micro-frontends.](https://medium.com/ @lucamezzalira/i-dont-understand-micro-frontends-88f7304799a9)
-
[Micro frontends—a microservice approach to front-end web development](https://medium.com/ @tomsoderlund/micro-frontends-a-microservice-approach-to-front-end-web-development-f325ebdadc16)
コメントはまだありません