はじめに:フォーク・トラップ(Forking Trap)とは

Meta(旧Facebook)は、Messenger、Instagram、Cloud Gaming、Meta Quest VRキャスティングなど、数十億のユーザーのリアルタイムコミュニケーションにWebRTCを活用してきました。しかし、オープンソースライブラリをモノレポ(monorepo)にフォークした瞬間から「フォーク・トラップ」が始まります。当初は些細な最適化やバグ修正から始まったとしても、アップストリームが進化し、内部機能が蓄積されるにつれて、アップストリームのコミットをマージするコストは指数関数的に増大します。

Metaは数年にわたる大規模マイグレーションを経て、50以上のユースケースを最新のアップストリームベースのモジュラーアーキテクチャに移行しました。本稿では、その過程で得られた重要な知見を共有します。

参考資料: 本記事はMeta Engineering Blogの原文を基に再構成しています。原文の全文はこちらでご確認ください。

Dual stack architecture diagram showing shim layer between application and two WebRTC versions System Abstract Visual

核心アーキテクチャ:シムレイヤー(Shim Layer)とデュアルスタック(Dual-Stack)

Metaが直面した最大の技術的課題は、C++静的リンカのOne Definition Rule(ODR)違反でした。同じライブラリの2つのバージョンを同一バイナリに静的にリンクすると、数千のシンボル衝突が発生します。Metaはこの問題を解決するために**シムレイヤー(Shim Layer)**を導入しました。

シムレイヤーの動作方式

// 例: シムレイヤーによるバージョンディスパッチ
// shim/api.h (統一API)
namespace webrtc_shim {

enum class Flavor {
  LEGACY,
  LATEST
};

class VideoEncoderFactory {
 public:
  virtual std::unique_ptr<VideoEncoder> CreateEncoder(
      const SdpVideoFormat& format) = 0;
  virtual ~VideoEncoderFactory() = default;
};

}  // namespace webrtc_shim

// shim/encoder_factory_adapter.cc (テンプレートベースのアダプター)
#include "shim/api.h"
#include "webrtc_latest/api/video_codecs/video_encoder_factory.h"
#include "webrtc_legacy/api/video_codecs/video_encoder_factory.h"

template <typename T>
class VideoEncoderFactoryAdapter : public webrtc_shim::VideoEncoderFactory {
 public:
  explicit VideoEncoderFactoryAdapter(std::unique_ptr<T> impl)
      : impl_(std::move(impl)) {}

  std::unique_ptr<webrtc_shim::VideoEncoder> CreateEncoder(
      const webrtc_shim::SdpVideoFormat& format) override {
    // 実際の実装に委譲
    return impl_->CreateEncoder(ConvertFormat(format));
  }

 private:
  std::unique_ptr<T> impl_;
};

// ファクトリ関数: グローバルフレーバー設定に基づいて適切な実装を生成
std::unique_ptr<webrtc_shim::VideoEncoderFactory>
CreateVideoEncoderFactory() {
  if (GetGlobalFlavor() == webrtc_shim::Flavor::LATEST) {
    return std::make_unique<
        VideoEncoderFactoryAdapter<webrtc_latest::VideoEncoderFactory>>(
        std::make_unique<webrtc_latest::VideoEncoderFactory>());
  } else {
    return std::make_unique<
        VideoEncoderFactoryAdapter<webrtc_legacy::VideoEncoderFactory>>(
        std::make_unique<webrtc_legacy::VideoEncoderFactory>());
  }
}

重要なポイント

  1. 自動名前空間変更(Renamespacing): スクリプトを使用して、すべてのC++名前空間を webrtc::webrtc_latest::webrtc_legacy:: に自動変更しました。
  2. マクロ衝突の解決: RTC_CHECKRTC_LOG などのマクロは、不要なインクルードの削除、使用頻度の低いマクロの名称変更、共通モジュール(rtc_baseなど)の共有によって解決しました。
  3. 後方互換性の維持: using 宣言を使用して、既存の webrtc:: 名前空間に新しいフレーバーのシンボルをインポートし、既存コードを修正せずに済ませました。
  4. コード生成の自動化: AST解析に基づいてシムコードを自動生成し、1日1シムから3〜4シムへと生産性を向上させました。

このアプローチにより、バイナリサイズの増加を約38MBから5MBへ、87%削減しました。

Engineers collaborating on monorepo WebRTC fork migration and symbol collision resolution Technical Structure Concept

第二の課題:モノレポでの継続的アップグレード(Feature Branches)

Metaは機能ブランチをサポートしないモノレポを使用しているため、アップストリームパッチを追跡しリベースする別の方法が必要でした。最終的に選択したのは、別のGitリポジトリで機能ブランチを管理する方法です。

ワークフロー概要

# 1. アップストリームリリースタグをベースにブランチを作成
git checkout -b base/7499 tags/7499

# 2. 各パッチごとに機能ブランチを作成(例: debug-tools)
git checkout -b debug-tools/7499 base/7499
# ... パッチを適用してコミット ...

# 3. アップストリームアップグレード時(例: 7499 → 7559)
git checkout debug-tools/7499
git merge base/7559  # コンフリクト解決
git branch -m debug-tools/7559

# 4. すべての機能ブランチを順次マージしてリリース候補を作成
git checkout -b rc/7559 base/7559
git merge debug-tools/7559
git merge hw-av1-fixes/7559
# ...

この方式の利点は:

  • 並列化が容易で、多数のブランチを同時に処理可能
  • Gitの履歴とコンテキストが自動的に保存される
  • 将来のLLMベースの自動コンフリクト解決に適している
  • 各機能ブランチをそのままアップストリームにコントリビュート(Pull Request)できる

Meta WebRTC continuous upgrade pipeline with automated A/B testing and AI conflict resolution Coding Session Visual

結果と示唆

Metaはこのプロジェクトを通じて、WebRTCのバージョンをM120からM145にアップグレードし、主要アプリでCPU使用率を最大10%削減、クラッシュ率を最大3%改善、バイナリサイズを100〜200KB(圧縮時)削減するという目に見える成果を上げました。

日本の開発エコシステムにおける適用コンテキスト

日本のSIerや大規模サービスにおいても、オープンソースライブラリをフォークするケースは少なくありません。特に金融系のように安定性を最優先する環境では、フォーク・トラップに陥りやすいと言えます。本記事のアプローチは、以下のような状況に応用できるでしょう:

  • レガシーWebRTCベースのビデオ会議ソリューションを運用している企業
  • 大規模モノレポを使用している組織(例:メルカリ、LINE、楽天)
  • A/Bテストが必須なリアルタイム通信機能を開発しているチーム

注意点: このアーキテクチャはC++テンプレートと名前空間操作に対する深い理解が必要であり、初期構築コストが大きいです。小規模プロジェクトや短期的なフォークにはオーバーエンジニアリングになる可能性があります。

合わせて読みたい記事

次のステップとしての学習方向性

  • WebRTCの深堀り: SDPネゴシエーション、ICE、DTLSなどのプロトコルレベルの理解
  • C++モジュール化: C++20モジュールを活用した、よりクリーンなシムレイヤー設計
  • AIによるメンテナンス: Metaが言及したAIエージェントを活用したビルドエラーの自動修正やコンフリクト解決手法の探求
本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。