re:Invent 2024: AWSとFormula1が語るMicro-frontendsの実践と効果
はじめに
海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!
📖 AWS re:Invent 2024 - The ideal micro-frontends platform (ARC325)
この動画では、Micro-frontendsの概念と実践的な導入事例について詳しく解説されています。AWS Principal Serverless SpecialistのLuca Mezzaliraが、Micro-frontendsの基本的な考え方や、Componentとの違い、実装時の重要な決定事項を説明します。また、Formula One Digital TechnologyのIvan Rigoniが、Formula1.comウェブサイトのMicro-frontends移行事例を紹介し、First Contentful Paintが2.0秒から0.8秒に改善するなど、具体的なパフォーマンス向上の成果を示しています。Micro-frontendsの導入により、チームの独立性確保、認知負荷の軽減、デプロイメント時間の短縮など、組織的なメリットが得られることも説明されています。
※ 画像をクリックすると、動画中の該当シーンに遷移します。
re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!
本編
Micro-frontendsの概要と本セッションの紹介
みなさん、Micro-frontendsに関するこのセッションへようこそ。過去10年間、私たちは分散システムの進化を目の当たりにしてきました。思い返してみると、最初にバックエンドで問題に取り組み始め、Microservicesが生まれ、その後Cell-based Architectureへと発展しました。10年前、私たちは同じ原則を複数の層に適用し始めました。フロントエンドではMicro-frontends、データサイドではData Meshです。なぜなら、小さな問題に分割することで、より効果的に解決できるからです。このシステムをチーム間で適切に分散させることで、より短時間で多くのことを達成できるようになりました。
今日は、その進化の一つであるMicro-frontendsについてお話しします。これを説明するために、ケーススタディを用意し、この設計の本当の価値を見ていきたいと思います。私はLuca Mezzaliraと申します。ロンドンを拠点とするAWSのPrincipal Serverless Specialistです。 そして本日は、Formula One Digital TechnologyのDigital Solutions ArchitectであるIvan Rigoniさんをお迎えしています。
Micro-frontendsの基本概念と設計原則
まず最初に取り組むべき問題は、フロントエンドアプリケーションをどのようにスケールさせるかということです。これは私が約10年前、大きな可能性を秘めたライブスポーツストリーミングプラットフォームで働いていた時に直面した問題です。私たちは18ヶ月もたたないうちに、数十人規模から数千人規模へと急成長しました。想像していただけると思いますが、このような問題に対処するには、スケールについて考える必要があります。バックエンドには解決策がありましたが、フロントエンドには解決策がありませんでした。
通常、フロントエンドアプリケーションを考えるとき、私たちはComponentsについて考え始めます。ヘッダーやマーケティングメッセージなどのComponentsについて検討します。しかし、分散システムで作業する場合、異なる考え方が必要です。それらを分割し、異なるチームが異なる部分で作業できるようにすることを考える必要があります。 一見簡単そうに見えます。なぜなら、異なるチームが異なるComponentsを担当し、それらのComponentsを各チーム間で再利用できるからです。しかし、これは完全な解決策とは言えません。なぜなら、特に分散システムにおけるアーキテクチャは、技術的な部分だけではないからです。エンジニアリングカルチャー、組織構造、ガバナンス、オーナーシップ、そして分散システムを成功に導くその他の特性など、多くの側面について考える必要があります。
先に進む前に、同じ認識を持っておきましょう。ComponentとMicro-frontendは大きく異なります。これは、初めてMicro-frontendsを採用する多くの企業でよく見られる典型的な間違いの一つです。オーストラリアからSilicon Valleyまで、世界中の何百ものチームがMicro-frontendsへの移行を支援してきた経験から、ComponentsとMicro-frontendsを混同するというアンチパターンをよく目にします。 例えば、典型的なボタンComponentを例に取ってみましょう。最初は、ラベルを設定するプロパティを公開します。そのボタンがシステム内で成功を収めると、アイコンとの関連付けを追加するかもしれません。組織内での人気が高まるにつれて、ボーダーカラーの変更、異なるロールオーバーアニメーション、自動サイズ調整など、機能を追加できます。私たちはComponentsを作成することで、重複を減らし、再利用性を最適化します。
しかし、再利用性は結合の一形態であるため、システムには問題があります。これは私の言葉ではなく、ThoughtWorksのDirector of ArchitectureであるNeal Fordの言葉です。では、ComponentsとMicro-frontendsの違いは何でしょうか?多くの人がこの点で悩んでいます。
Micro-frontendはコンテキストをよく理解しています。実際、操作すべき状態をカプセル化しているのです。Buttonについて考えてみると、Buttonはすべてのプロパティを公開していますが、どのように振る舞うべきかを指示する誰かが必要です。通常、Buttonのコンテナにドメインをリンクしますが、これは他のComponentでも同様です。一方、Micro-frontendは状態をカプセル化しているため、どのように振る舞うべきかを知っています。
おそらくセッショントークンや商品IDなど、2、3のプロパティは持つかもしれませんが、それ以外は持ちません。なぜなら、Micro-frontendはコンテキストを理解しているからです。そうでなければ、ドメインの漏洩が発生してしまいます。つまり、チームの依存関係の範囲を減らすことはできず、他のケースと同様に調整のコストが発生し始めます。これは分散システムでは避けたいことです。通常、入力と出力を定義します。Domain Driven Designにおけるバウンデッドコンテキストについて話すとき、システムやサービスとの通信に使用するAPIと、サービスの出力を特定します。これは非常に重要で、通常は拡張性が低くなります。最大限の再利用性を目指してMicro-frontendsを構築しているわけではありません。
これはComponentsに関してですが、先ほど述べたように、Micro-frontendsはコンテキストを理解しており、チームが強い独立性を持てるようにすべきです。そして、外部依存関係を排除するのではなく、削減しているのです - これは非常に重要です。私は、適切なMicro-frontendsの境界を作成しているかどうかを理解するための経験則を作成し、現場で広く使用されています。通常、公開するAPIは多くありません。Buttonについて考えると、再利用性を持たせたいため、多くのプロパティを公開することになります。Micro-frontendsでは、そのようなプロパティは多くありません。時には規約として、セッショントークンをローカルストレージやCookieで確認し、クエリ文字列でIDを確認するといった方法を取ります。
2番目のポイントは、先ほど議論したように、コンテキストを理解しているということです。3番目のポイントは、どこでも再利用されるMicro-frontendを作り始めた場合、それは警告サインかもしれないということです。これは重要なポイントです - たとえばFooterについて考えると、コードの変更頻度が非常に低いため、複数の場所で再利用可能だと考えるかもしれません。最後に重要なポイントとして、Micro-frontendsはより粒度が粗いということです。経験則として、1つのViewに5-6個のMicro-frontendsがあれば十分です。もし数十個のMicro-frontendsを持つことになった場合、おそらく分散Componentsを構築していることになり、これは避けるべきことです。
Micro-frontendsの定義と実装における重要な考慮事項
そのため、私はこの定義を約10年前に作り出しました。開発者にとって理解が難しい概念を表現する必要があったからです。9年前、Microという用語が存在しなかった時代を想像してみてください。私が何百人もの技術者の前でこれを説明すると、彼らは「一体何をしようとしているんだ?」という表情で見つめていました。実際のところ、Micro-frontendsはビジネスサブドメインの技術的な表現であり、同じまたは異なる技術を使用して独立した実装を目指すものです。共有するコードを最小限に抑え、単一のチームが所有します。
これから、理想的なMicro-frontendsプラットフォームを作るために、この定義の特徴を一つ一つ詳しく見ていきましょう。しかしまず、重要な点から始めましょう:なぜMicro-frontendsが必要なのでしょうか?なぜ私たちはそれを採用すべきなのでしょうか?まず第一に、私はMicro-frontendsを段階的なアップグレードのために使用したいと考えているお客様を見てきました。毎月、あるいは2ヶ月ごとのリリースサイクルのために、Micro-frontendのデプロイに1ヶ月も待たなければならないことに疲れているのです。私は以前、ある企業で働いていましたが、そこではMicro-frontendごとのリリース頻度を月2回から1日24回に増やすことができました。これこそが私たちが目指すものです - それを可能にするGuardrailsを持ちたいのです。
Microservicesと同様に、分散化を実現したいのです。Microservicesについて考えるとき、単に技術的な分離やシステムの一部のスケーラビリティだけを目指しているわけではありません。組織を成長させたいのであれば、システム内でチームを柔軟に追加・削除できる可能性を持つ必要があることを知っているため、分散化を目指すのです。
Micro-frontendsでは、認知負荷を減らすことを目指しています。これは非常に重要な側面です。なぜなら、新しく参加したメンバーが大規模なコードベースを理解するのに1ヶ月もかかってしまうと、本番環境へのデプロイまでに時間がかかってしまうからです。数週間で本番環境へのデプロイを開始できたお客様を見てきましたが、それは素晴らしいことです。そして最後に、しかし重要なこととして、分散システムは技術システムをスケールするためだけでなく、社会技術システム、つまり組織をスケールするためにも存在することを覚えておいてください。
Conway's Lawについて聞いたことがある方はどれくらいいらっしゃいますか?Conway's Lawの考え方は、通常、組織構造を反映したデザインを生み出すというものです。これは新しいものではなく、ご覧の通り1967年まで遡ります。当初、Melvin Conwayの考えは信じられていませんでしたが、10年から15年後、人々はそれを目の当たりにし始めました。そのため、分散システムでは、アーキテクチャと組織構造という2つの次元を考慮することが重要です。私は3つ目の次元としてエンジニアリングカルチャーを追加しましたが、それは後ほど触れることにします。
集中型のマインドセットについて考えてみると、私も昔はこのように働いていましたが、Value StreamチームやEngineeringチームの開発者として、自分のシステムの担当部分に取り組んでいました。チーム間のインプットとアウトプットに関する明確な理由付けはなく、技術リーダーシップが特定の事項を定義し、通常、開発者は自分のコードを塀の向こう側に投げ、誰か他の人が運用するという形でした。しかし、分散システムで作業する場合、分散型のマインドセットで考える必要があります。
このような場合、Topologyが解決策となります。Topologyは2019年に登場した概念で、価値を生み出すことに専念するStream-aligned team を持つという考えから始まります。しかし、もちろん彼らだけでは実現できません。Complicated subsystem team が必要で、これらのチームはシステムの特定の領域を担当し、他のValue Streamチームが特定の要件を達成するのをサポートします。この例では、Data Scienceチームがランディングゾーンや、UIからのクリックストリームなどのデータを提供するためのAPIを提供しています。 そして、Platformチームがインフラストラクチャーとシステムの基盤部分を提供します。
最後に重要なのが、SecurityやDeveloper Experienceなどのenabling teamです。特にDeveloper Experienceは、このフロントエンドとバックエンドのシステムにおける重要な成功要因の1つです。 しかし、アーキテクチャーと組織の関係も理解する必要があります。そこで、これら2つの側面、つまりPlatformチームとStream-aligned teamについて詳しく見ていき、アーキテクチャー側での機能を反映させ、このようなプラットフォームの所有権を分割することの意味を考えていきます。
開発者体験とデプロイメントの最適化
まずはPlatformチームから始めましょう。 グレーアウトされていない部分です。下部のPlatformチームとEnablementチーム、この2つがシステムの基盤部分を作成します。Micro-frontendsを始める際に私が提案するのは、Micro-frontends decision frameworkを定義するための仮想チームまたは専任チームを作ることです。このフレームワークは2019年に考案され、すべてのMicro-frontendsプラットフォームで必要な4つの重要な決定で構成されています。Server-side renderやClient-side renderは常に同じです。これら4つの決定がシステムの基盤部分となります。
Micro-frontendとは何か、どのように構成するか、ページ間のルーティングをどうするか、Micro-frontends同士がどのように通信するかを特定する必要があります。私は数十、あるいは数百のアーキテクチャーでこれを試し、適用してきました。これらの質問に答えることができれば、システムの素晴らしい出発点となります。 通常、Micro-frontendsの特定について話す際、Vertical splitとHorizontal splitの2つのタイプがあります。Vertical splitは右側にあるもので、ページまたはページグループがMicro-frontendを表します。そしてHorizontal splittingは、同じページ内に複数のMicro-frontendsがある場合です。
これらのタイプは相互に排他的なものではありません。システムで表現したいことを理解し始めると、両方を同じシステムで使用できます。典型的な例として、ウェブサイトの「マイアカウント」エリアを考えてみましょう。そこには支払い情報があり、ユーザーアカウントという別のドメインがあり、さらにギフトコードの履歴などの履歴情報があるかもしれません。これらは同じページでユーザーに表示される3つの異なるドメインですが、組織内では3つの異なるチームに割り当てられています。このように水平分割が可能です。一方で、カタログがあり、その中にカタログに関連するすべてのものが含まれている場合、1つのチームがそれを担当するだけで十分かもしれません。つまり、コードの変更頻度に応じて、同じチームが扱う固有のまとまりとしてカタログを特定したいのです。
次に、Micro-frontendsのコンポジションに移ります。左側に示されているように、クライアントサイドでコンポジションを行うことができます。そこには Application shell と呼ばれるものがあります。これは、アプリケーションの起動時に読み込まれる空の要素で、Micro-frontendsをどのように組み合わせるかを知っています。iframeを通じてか、Import mapを通じてか、Module federationを通じてかは問題ではありません。Application shellがその方法を把握しているのです。サーバーやCDNには、各チームが構築するArtifactがあります。
次にRoutingの部分があります。Routingは次のように機能します。あるページから別のページに移動する際、一連のMicro-frontendsを読み込む必要があります。この場合、通常クライアントサイドのApplication shellが、適切なページ、より正確には適切なMicro-frontendを読み込んで組み合わせるためのロジックを持っています。同様に、Server-side renderingでは、コンポジションがサーバー上で行われるため、Routingもサーバー上で行われます。
最後に、水平分割を行う場合、Micro-frontends間でのコミュニケーションが必要になることが多いです。例えば、Eコマースで誰かが商品を選択し、カート内の数字を増やす必要がある場合を想像してください。この場合、通常は通信が必要な水平分割があります。よくあるアンチパターンは、Micro-frontends間で共有されるState managementを使用することですが、これはMicroservices間でデータベースを共有するようなものです。スキーマを変更すると、他のすべてを変更する必要が出てきます。そのため、Pub-subパターンを使用する必要があります。したがって、Event emitter、Custom events、Reactive streamsが最適な選択となります。また、水平分割でも垂直分割でも、CookieやLocal storage、Session token、あるいはQuery string parameterのIDのような一時的なデータを通じて情報を共有できます。
さて、Application shellについて考慮すべき別の点があります。アプリケーションの起動時に読み込まれるこの空の要素は、ユーザーセッション全体を通じて存在し続けます。 まず第一に、できるだけVanillaである必要があります。多くの企業がAngularやReactなどのフラームワークを使用しているのをよく見かけますが、複数のフレームワークを扱う必要が出てきたり、ReactからVue.jsへ、またはその逆に移行したい場合に、より複雑な問題が発生します。第二に、コンテキストを意識しないようにする必要があります。良い経験則として、Application shellが自分のアプリケーションだけでなく、他のどのアプリケーションでも読み込めるなら、それは良い方向に進んでいます。第三に、初期設定を公開することです。特にClient-side renderingでは、最初に行うのは通常、APIの呼び出し、つまりStartup APIやInitialization API(呼び方は自由です)で、これには異なるMicro-frontends間で共有される初期設定が含まれています。最後に重要なのは、先ほど見たように、RoutingとComposingの責任を持つことです。
もう1つの非常に重要な部分は、開発者体験について考えることです。私たちは特定のアーキテクチャ特性を表現し、できるだけ左にシフトするよう努める必要があります。開発者にとって素早いフィードバックループを持つことが重要です。そのため、パフォーマンステストやパフォーマンスのモニタリングなど、非常に興味深いことができます。
以前の職場での典型的な例を挙げると、開発者がバージョン管理システムでPull Requestを開くたびに、Lambda関数で処理されるWebhookがトリガーされていました。Micro-frontendをその場でビルドし、そのサイズが設定した閾値の30%を超えた場合、メインブランチへのマージをブロックしていました。これを実装した理由は、Micro-frontendsを使用することがパフォーマンスは重要でないということを意味するわけではないからです。実際、アプリケーション全体ではなく必要なコードのみを読み込むため、パフォーマンスはさらに重要になります。
もう1つの考慮点は、共有ライブラリの更新方法です。私がよく目にする典型的なシナリオは、Design Systemがあり、複数のMicro-frontendsに影響を与える新バージョンがリリースされる場合です。各チームに最新バージョンへの更新を個別に依頼するのではなく、そのプロセスを自動化したいところです。Dependabotのようなソリューションを使用して、毎晩パッケージバージョンをチェックし、Design Systemのバージョンが最新かどうかを確認するように設定できます。最新でない場合、自動的にPRをオープンするか、チームにダイジェストメールを送信することができます。
また、必要なセキュリティポスチャーを維持する必要があります。例えば、誰もフロントエンドにAPI IDを追加していないことを確認したい場合があります。セキュリティポスチャーを損なうようなコードがないことを確認するため、すべてのバージョン管理をスキャンすることになります。これらは単なる例に過ぎません。より多くの対策を実装できますが、これらの側面について考えることが重要です。なぜなら、アプリケーション開発を加速し、開発者が特定のアーキテクチャ特性を気にすることなく、本当に重要なことに集中できるようになるからです。
Formula One Digital Technologyにおけるケーススタディ
もう1つの重要な側面は、デプロイメントについて考えることです。開発者体験とデプロイメントは、しばしば密接に関連しています。Micro-frontendsのデプロイメントを設計する際には、いくつかの特性を念頭に置いています。まず、可能な限り頻繁に、かつ段階的にデプロイする必要があります。最も重要なのは、Micro-frontendsが独立していることです。チームが常にデプロイメントを調整している状況を目にすると、それは境界づけられたコンテキストの中に取り除く必要のある結合が生じているため、ホワイトボードに戻る必要があるというシグナルです。
これらの問題の解決策を考え始めたとき、 discoveryパターンと呼ばれるものを発見しました。このパターンは、MicroservicesやCMSでよく見られるものです。クライアントアプリケーションのShellがDiscoveryサービスを呼び出し、読み込むべきMicro-frontendsを取得する仕組みを見たとき、この部分は簡単に抽象化できると気づきました。素晴らしいのは、Micro-frontendsを遅延読み込みしているため、デプロイ方法も自由に決められることです。私たちは、Microservicesの一括デプロイメントは避けるべきで、Canaryリリースやブルー・グリーンデプロイメントを採用すべきだということを、苦い経験から学びました。
この問題を包括的に解決するため、AWSの複数のアーキテクトと私で、Frontend Discovery Serviceと呼ばれるものを作成しました。これはAWS Labsで公開されているオープンソースのサービスです。 このサービスは主に2つの領域で構成されています:新しいMicro-frontendsの作成とデプロイメントを管理するためのAPIを備えたバックエンド、 そしてサーバーまたはクライアント上のアプリケーションShellが適切なMicro-frontendを取得するために使用するフロントエンドです。アプリケーションは、一括デプロイ、Canaryリリース、ブルー・グリーンデプロイメントなど、お好みの方法でロールアウトを処理します。
このプロジェクトはAWS Labsで利用可能で、アクセスするためのリンクも用意されています。 すでに数十社の顧客が利用しており、Micro-frontendsのデプロイメントの課題を効果的に解決しています。 では次に、Micro Value Streamチームについて見ていきましょう。緑色で示されているのが3つのチームです。
Micro Value Streamチームと3つのチームの定義に関して、これは同じ技術や異なる技術で何度も見てきた問題です。複数の技術があり、それらを最適化しようとすると、ThoughtWorksが 2017年、2018年に定義したMicro-frontendsのアナーキー状態に陥ってしまいます。これは避けるべき最適化です。現在のアーキテクチャからMicro-frontendsへの移行期間中は、2つか3つのフレームワークを持つかもしれません。しかし、単一のフレームワークに最適化すべきです。なぜなら、開発者のための遊び場を作っているのではなく、顧客のためのソリューションを構築しているからです。そのため、開発者が複数のフレームワークを使用することを決めたからといって、顧客がそのペナルティを負うべきではありません。
考慮すべきもう一つの点は、 コード共有を最小限に抑えることです。フロントエンドコミュニティでこのアイデアを提案したとき、賛同を得るのは非常に困難でした。しかし実際には、コードを共有すると、厄介な抽象化のリスクが生じる可能性があります。 したがって、本当に考えるべきは外部依存関係を減らすことです。それが主な目標です。システムを分散させる際は、チームの高速なフローを最適化し、 Leanマインドセットを取り入れることが重要です。今、複数のチームでシステムの一部を重複させ、後で抽象化することを決めた場合、最初から抽象化を始めて後で分割しようとするよりも、はるかに成功し、抽象化の方法と場所についてより多くの知見を得ることができます。
典型的な例として、システム内での変更頻度をヒューリスティックとして考えてみましょう。logging、analytics、design system、data layerは、システム内で共有される典型的なものです。loggingは変更頻度が低いので問題ありません。analyticsライブラリの場合、おそらく半年から1年に1回程度の変更です。Design systemは比較的頻繁に変更されますが、通常は初期段階で多くの労力が必要で、新バージョンへの更新が必要になります。ただし、長期的に見ると毎日変更されることはありません。しかし、data layerはどうでしょうか?このレイヤーは非常に頻繁に変更される可能性があります。そのため、私は通常、data layerを共有して複雑性やロジックの保守を負担するよりも、各Micro-frontendが独自のdata layerを管理する方が好ましいと考えています。問題はコードを書くことではなく、コードを保守することなのです。
所有権の定義の最後の部分に進みましょう。Micro-frontendを適切に設計する場合、チームが単独でコーディングできるようにする必要があります。これまで見てきたように、独立してテスト、デプロイ、モニタリングができるということは、ツールを提供する必要がないということではありません。むしろ、guardrailsに従いながら、チームが必要なときにデプロイを決定できるということです。これらの4つの要素はすべてのチームに必要不可欠です。
Formula1.comのMicro-frontends移行プロジェクト
さて、先に進む前に、私が説明したこれらの異なるルール以外に、Micro-frontendsがビジネスに大きな影響を与えられることを実証したいと思います。そのために、Ivanに来ていただいて、その話をしてもらいます。ありがとうございます、Luca。私はFormula Oneのdigital technologyのSolutions Architectです。Formula OneのDigital Technology部門とドメインについて説明させていただきます。これは3つのサブドメインで構成されています。1つ目は私が所属するコアドメインで、Formula1.comウェブサイトとFormula Oneアプリを含みます。2つ目はF1 TVのウェブサイト、アプリ、スマートTVアプリです。そして3つ目はFantasyで、これはFormula Oneチームマネージャーになりきってシーズン中にポイントを獲得できるゲーム化された体験です。
Formula One Digital Technologyのコアドメインでは、私たちは使命を持って取り組んでいます。ウェブとアプリのトラフィックを増やし、より多くのコンテンツや広告を消費してもらうことを目指しています。もちろん、最終的な目標は、無料コンテンツのF1 Unlockedとサブスクリプション型ストリーミングのF1 TVへのサインアップを増やすことです。しかし、人間の本質に対応する必要があります。2015年にAkamaiが実施した大規模な調査によると、
ユーザーの49%が、ウェブサイトやアプリが操作に対して2秒以内に反応することを期待し、さらに30%が1秒以内の反応を期待しているということがわかりました。つまり、2015年の時点ですでにユーザーの79%がそのように考えていたということです。これは何を意味するのでしょうか?つまり、これを見ているとき、1秒経過すると、あなたの注意は完全に別のところに向いてしまうということです。
まず、micro-frontendsの導入によって達成したことからお話しさせていただきます。 第一に、ビジネス面についてですが、先ほどWebとアプリのトラフィックを増やしたいと申し上げました。画面に表示されている34%増という数字は、今年1月から9月までのF1 UnlockedとF1 TVの新規サブスクリプションと登録数の増加分のみを示しています。現在はさらに高い数字になっているかもしれません。これはmicro-frontendsの導入だけが要因ではなく、コンテンツの質の向上も確かに貢献していますが、Webサイトが高速化したことで、micro-frontendsが大きく貢献していることを示す数字と言えます。
財務面では、Amazon EC2からAWS Fargateにワークロードを移行しただけで、プラットフォームコストを26%削減できました。これは何を意味するのでしょうか?つまり、AWSリソースをより効率的に使用できるようになったということです。これは環境にもやさしく、コスト面でもメリットがあるということですね。 こちらはWebとモバイルWebのLighthouseパフォーマンススコアの向上を示しています:Webで30%増、モバイルWebで56%増という大幅な改善です。このパフォーマンス向上の詳細な内訳については、後ほどご説明させていただきます。
ソフトウェアエンジニア、つまりこの会場にいらっしゃる多くの方々にとってのメリットも忘れてはいけません。認知負荷が減少し、単一のmicro-frontendにより集中できるようになりました。プラットフォーム全体の回帰テストを行うことなく、各micro-frontendを個別に開発、テスト、デプロイできます。ユーザー体験が高速化されたことで、テストの実行も速くなり、より多くの成果を出せるようになりました。もう一つのメリットは、デザインシステムの自動化との統合です。新しく承認されたデザインの提出から、Storybookでしっかりと文書化されたWeb componentsの作成まで一貫して行えます。エンジニアは新しいWeb componentを取得し、ビジネス面で必要なロジックを適用し、そしてChromaticでアクセシビリティの回帰テストを行うデプロイメントパイプラインにコードをプッシュします。
もちろん、デメリットもあります。ただし1つだけです:Webサイトの見た目は変わっていないということです。2024年4月のFormula1.comの数ページを訪れ、その後現在の同じページを訪れたとしても、確かにコンテンツは異なり、より魅力的になっています。これは私たちが前進し、チャンピオンシップがより興奮するものになったからです。しかし、見た目は同じままです。ただし、大幅に高速化されています。
それでは、実際に変更が行われたフード下の部分を見ていきましょう。 2018年まで、Formula1.comは従来型の3層モノリシックアーキテクチャで運用されており、データベース、アプリケーションサーバーでのHTML生成、Javaのサーバーサイド処理を行っていました。このようなシステムの限界は皆さんご存知の通りです。ビジネスの拡大に伴って制限やデメリットに直面し始めるまでしかスケールアウトできません。また、リリースは実際に厄介な作業となります。なぜなら、どんな小さな変更でも、何も悪影響を受けていないことを確認するために、Webサイト全体の回帰テストを行う必要があるからです。そのため、回帰テストを1回で済ませるために、より多くの変更を1つのリリースにまとめる傾向があり、リリースはよりリスクの高いものとなります。私たちはより柔軟なアーキテクチャを望み、まずは編集機能の抽出から始めました。
モノリスの外側についてお話しします。このクリーンな分離により、Adobe Experience Managerのモノリスは依然としてページ、テンプレート、データなど必要なものを提供していますが、コンテンツはContentfulから取得されています。私たちは4つのコンテンツアトムを作成しました。これが私たちの初期のMicro-frontendsとなりました:ヘッダー、ナビゲーションバー、コンテンツエリア、そしてフッターです - これがFormula Oneウェブサイトの基本的な構造のすべてとなっています。
2022年に、より本格的な取り組みを始めた時期に話を進めましょう。ドメイン駆動の観点から、モノリスの他の部分との依存関係がほとんどないか、まったくない領域の境界を特定しました。それがFormula One TVのサブスクリプション購入のジャーニーです。この自己完結型のドメインは、新しいアーキテクチャへの切り出しが容易でした。これはECSクラスターpropsで表現されています。propsはサブスクリプションの購入を提案するプロポジションページを指し、Application Load Balancerがフロントに配置されています。ユーザーがサブスクリプションを購入しようとする場合、インバウンドトラフィックはpropsページにルーティングされ、それ以外はすべて従来通りモノリスに向かいます。CloudFront Functionsが利用可能になるとすぐに、この振る舞いをCloudFront Functionsに移行しました。
興味深いことに、propsページの構造は維持されました。 唯一の違いは、Application Shellと呼ばれる外側のフレームが、Next.js 12アプリケーションによって実装されるようになったことです。この実験は非常に成功を収め、 Formula1.comウェブサイト全体をMicro-frontendsで再構築するプロジェクトを開始することになりました。
Micro-frontendsの実装と成果
まずはビジネス要件から始めましょう。どのプロジェクトでも、なぜこの取り組みを行うのかを正当化する必要があります。どこかに価値を見出す必要があるのです。私たちは、より高速で、スケーラブルで、高い同時接続性を持つウェブサイトを目指していました。高速であることは、より多くのエンゲージメントを生み、最終的にはより多くのサブスクリプションにつながります。スケーラブルで高い同時接続性が必要なのは、Formula Oneビジネスの性質によるものです - どのスポーツストリーミングプラットフォームでも、スポーツイベントの開始時にユーザーが殺到し、週の残りの期間は低いトラフィックとなります。より多くのことを、より速く提供したいのです。より現代的なツールは、より速い開発とアクセシビリティの向上につながります。私たちはユーザーベースを拡大し、特別なニーズを持つユーザーにもFormula Oneを最大限楽しんでいただけるようにしたいと考えています。そして最後に、ABテストやマルチバリエートテストを通じて、より迅速に実験できるようにしたいと考えています。
では、Micro-frontendsはどのようにしてこれらの要件に対応できるのでしょうか?独立したテストとデプロイメントにより、デザインシステムと完全に統合された形で、より迅速に変更を提供することができます。興味深いことに、より細かいキャッシュポリシーを実装することができます。これはFormula1.comにとって重要です。なぜなら、1950年代のシーズン順位表のように、更新される可能性が低い領域がある一方で、速報ニュースエリアのように頻繁に更新される領域もあるからです。そのため、それぞれ異なるキャッシュポリシーを持ち、最後に、より優れたアクセシビリティのサポートを実現しています。
マイクロフロントエンドへの完全移行を決めた後は、次に何をすべきでしょうか?私やLucaのようなマイクロフロントエンド移行の経験者を採用することもできますが、今日では幸運なことに、たくさんの文献が存在します。ここで恥ずかしながら、Lucaの著書「Building Micro-Frontends」第2版を宣伝させていただきますが、この本にはすでにマイクロフロントエンドの意思決定フレームワークに関する章が含まれています。
アーキテクトである私にとって、最も重要な仕事は、将来的に変更が困難な決定をサポートすることです。なぜなら、それらの決定がソリューション設計の形を決定づけるからです。 Formula1.comウェブサイトのページ構造内でドメイン境界を特定する際、各セクションが何であり、組織的に誰がそのセクションを所有しているかを決定する必要があります。垂直分割された単一ページアプリケーションが明確な選択肢でした。記事一覧、動画一覧、そして統計、順位、ドライバー、チームの情報など、それぞれ異なるページがあるからです。これらは異なるドメインによって所有されていますが、ページ構造はヘッダー、フッター、ナビゲーションバー、そして複数のマイクロフロントエンドを含むことができるコンテンツエリアという標準的なものです。
次の決定はコンポジションに関するものです - クライアントで構成するのか、サーバーで構成するのか?私たちにとって、この選択は簡単でした。先ほど触れた最新ニュースのように、コンテンツが頻繁に変更されるページであっても、同じレスポンスを何百万回も配信します。そのため、クライアントで生成する意味はありません。サーバーで生成してCloudFrontにプッシュします。サーバーサイドレンダリングが明らかな選択でした。
次はルーティングです。フロントエンドでもバックエンドでもルーティングできますが、サーバーサイドレンダリングを選択すると、選択肢はサーバーサイドに限定されます。それでも、複数のオプションがあります。NGINXでリバースプロキシを使用できますが、Lambda@EdgeやCloudFront Functionsもあります - なぜ使わないのでしょうか?とてもよく機能します。 最後に、マイクロフロントエンド間のコミュニケーションについて、様々なマイクロフロントエンド間でデータを受け渡す必要があるか、あるいはパブリッシュ-サブスクライブメカニズムが必要かを判断する必要がありました。以前のウェブサイトを調査したところ、90%のケースではマイクロフロントエンド間のコミュニケーションは不要であることがわかりました。Application Shellから読み込まれたマイクロフロントエンドへの一方向のコミュニケーションだけが必要でした。
これらの変更を実現するには、新しいシステムを作成して準備が整ったら切り替えるというビッグバンアプローチを取るか(これはリスクが高いことは分かっています)、あるいは私たちが選択したテストと学習の反復的なアプローチを取るかのいずれかです。レガシーシステムには、コンテンツの編集、テンプレート作成、FIA公式データの取り込み、チーム、ドライバー、サーキットなど、数多くの機能がありました。そのシステムから、一つずつ機能を切り離し、既存の機能からトラフィックを減らし、Stranglerパターンを利用して新しいマイクロフロントエンドベースのシステムで提供される新機能にトラフィックを移行していきました。その過程で、F1 TVやFantasyなど他のドメインでも使用できる機能(チーム、ドライバー、サーキットのデータの使用など)を発見しました。その部分をData Abstraction Layerと呼ばれる独立したシステムとして抽出し、画像メディアアセットについても同様にCloudinaryに委譲して他のドメインでも使用できるようにしました。残りの機能はマイクロフロントエンドに移行されました。マイクロフロントエンドを決定し、実装アプローチを選択した今、実際のリリース計画をご覧になりたいかもしれません。
Digital社のご協力により、Formula1.comウェブサイトをMicro-frontendsへと変革するために実際に使用しているデリバリープランをご紹介します。まず最初に、ヘッダー、フッター、そして記事一覧のMicro-frontendsを含むApplication Shellをデリバリーし、その後リリースごとに機能を追加していきます。右側に移動していくマゼンタ色のボックスは、トラフィックを100%移行するまで、各リリースで追加される新機能を表しています。
最終的なアーキテクチャは、現在画面に表示されているものです。右側の2つのボックスは、複数のECSクラスターに置き換えられており、それぞれがFormula1.comウェブサイトの各ページを表し、複数のMicro-frontendsを集約しています。Application Load Balancerによって制御され、ルーティングはCloudFront Functionsで行われ、また2つの新しいシステムも確認できます。
先ほど触れたパフォーマンスについて、KPIの詳細を見ていきましょう。一般的なKPIとして、皆さんもよくご存知のWeb Vitalsを使用しています。最初にデリバリーした「最新のF1ニュース」ページを見てみましょう。ウェブでは、First Contentful Paintが従来システムの2.0秒から新システムでは0.8秒になり、素晴らしい成果です。Speed Indexは4.3から3.0に改善されました。さらに、トラッキングピクセルや広告など、不要なコードをすべて削除すると、0.6まで下がり、これは非常に印象的な数値です。
次のスライドで、モバイルウェブの同じページを見てみましょう。特に注目していただきたいのはLargest Contentful Paintです。従来システムでは8.7秒と、控えめに言っても酷い数値でしたが、新しいMicro-frontendsベースのシステムでは3.2秒まで改善されました。Speed Indexは7.3から5.2に改善され、さらに不要なコードを取り除くと2.0になります。最後に、これまでご覧いただいた数値をすべて1つの数字で表すLighthouseパフォーマンススコアは、53から83に向上しました。これは大幅なパフォーマンス向上と言えます。
Micro-frontendsの利点と結論
Micro-frontendsの実践的な事例で、皆様を楽しませ、興味を持っていただけたことを願っています。では、Lucaにバトンを戻します。誰もが知っているウェブサイトの実際の事例を聞き、さらにその移行についても見ることができ、非常に興味深い内容でした。しかし、終わる前に、もう少しお話ししたいことがあります。Micro-frontendsは時として非常に議論を呼ぶテーマとなることがあります。当初、コミュニティでは、Micro-frontendsはパフォーマンスを向上させないどころか、パフォーマンスを損なうという批判がありましたが、実際にはそうではないことが分かりました。
これはFormula 1だけの話ではありません。ページの表示に必要なコードだけを読み込むことで、あらゆるデバイスで大幅なパフォーマンス向上が得られた多くの事例をお話しできます。Johnの前に、私はライブスポーツストリーミングプラットフォームで働いていましたが、そこではリビングルームデバイスやセットトップボックスなど、多くの低スペックデバイスに対応する必要がありました。これらは私たちが現在使用しているクアッドコアや8コア、20コアのMacintoshとは比べものにならないデバイスです。そこでSingle Page ApplicationからMicro-frontendsに移行することで、アプリケーションの起動時間を40秒から10秒程度まで短縮することができました。想像していただけると思いますが、Micro-frontendsを導入するだけでこれほどの成果が得られるのです。なぜなら、フロントエンド全体のパッケージサイズを考えるのではなく、必要な部分だけを考えればよくなり、ユーザーが常にサイト全体を読み込む必要がなくなるからです - 必要な部分だけを読み込んで利用することができます。
2番目のポイントは、Micro-frontendsがMicroservicesを補完する戦略だということです。分散システムについて考えるとき、私たちが目指しているのはチームの独立性です。外部依存関係を減らすことで、今日お話ししたような高速なフローを実現できます。したがって、バックエンドで分散システムを採用している場合、フロントエンドでも同様のアプローチを取りたいと考えるのは自然なことです。これは文脈によって必ずしもそうとは限りませんが、Micro-frontendsの検討を推奨する大きな理由の一つです。
Micro-frontendsは、チームの認知負荷を軽減し、ドメインエキスパートとしての成長を促進します。組織内での意思決定のロジックと適用すべきロジックを分散化することで、高速なフローの実現が可能になります。より迅速なデプロイメント時間を実現し、責任を持って適切にデプロイできるチームを作るには、明確な境界を持つMicro-frontendsによって、コードを書くだけでなく、先ほど見てきた他のすべての側面にも注意を払う時間を確保することができます。
最後に、しかし重要な点として、Micro-frontendsはチームを独立させます。現在の開発者にとって、オーナーシップは重要な要素です。開発者はコードを書くだけでなく、意思決定にも関与しています。他に影響を与えることなく、パターンを適用して境界を設定できる可能性は、プラットフォーム構築の成功につながります。このセッションを楽しんでいただけたことを願っています。まだ10分ほど時間がありますので、いくつか質問を受け付けたいと思います。ご参加ありがとうございました。
※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。
Discussion