Craftの自社開発同期プロトコルの誕生物語

デバイス間のシームレスなコラボレーションと将来の成長を支えるために、独自の同期プロトコルをどのように構築したかをご紹介します。

公開日
12/30/2024
Building Craft
Craftの自社開発同期プロトコルの誕生物語

はじめに

Craft のようなアプリケーションでは、複数のデバイスにまたがってドキュメントにアクセスし、共同作業を行うことは不可欠な機能です。ユーザーは、ノートパソコン、タブレット、スマートフォンで同じドキュメントを開いて編集し、オフライン状態であっても他のユーザーとシームレスに共同編集できることを期待しています。

これは、プロダクトの最初のプロトタイプの段階から Craft のアプローチの根幹をなしてきました。当初、Craft には iOS 開発者が 2 名しかおらず、カスタムのデータ同期プロトコルを構築するためのエンジニアリングリソースはありませんでした。当時、唯一実現可能な選択肢は、同期処理の重い部分を既製のソリューションに任せることでした。その目的に最適なツールが、データベースソリューションであり MongoDB Atlas Device Sync の前身でもある Realm でした。Realm のクラウド機能は、私たちの初期段階において基盤的な役割を果たしました。しかし、プロダクションレベルの品質を実現するためにアーキテクチャを見直す必要があり、現在 Craft は自社開発の同期プロトコルに依存しています。

Craft のコアデータ

Realm はモバイルアプリケーション向けに永続的なストレージを提供するオープンソースのデータベースであり、私たちはブロックコンテンツやドキュメントのメタデータを含むすべてのコアドキュメントデータをこれに保存していました。また Realm は、Realm Sync 拡張ライブラリを通じてクラウド機能も提供しており、Realm Cloud を介してデータベース全体を複数のデバイスにシームレスに同期することを可能にしていました。

このプロセスはバックグラウンドで自動的に行われ、サーバーインフラ管理の負担を排除していました。ユーザーがドキュメントを編集すると、Craft の基盤となるデータモデルへの変更が Realm データベースに保存され、Realm Sync が自動的に変更を Realm Cloud にアップロードしました。他のデバイスはリアルタイムで変更を受信してローカルデータベースを更新し、一方 Realm はドキュメントへのブロック追加のような競合する変更を自動的に解決していました。さらに、Realm Cloud が提供するパブリック API を通じて、ドキュメントデータはオンラインサービスからも利用可能でした。

5.png

データの公開

私が最初のバックエンド開発者として、そして最初のウェブ開発者とともに Craft に加わったとき、最初の目標は Craft の公開機能の初期バージョンを実装することでした。これを実現するためには、Craft のドキュメントをウェブアプリケーションからも利用できるようにする必要があり、いくつかの選択肢を検討しました:

  • Realm Cloud の継続利用
  • 別の既製同期ソリューションの採用
  • 独自同期プロトコルの開発

指針は明確でした:採用するソリューションは、デバイス間でシームレスかつ競合なく即時に同期できること、そして柔軟で迅速なサーバーサイド開発を可能にすることが必要でした。

Realm Cloud の継続利用は、エンジニアリング上の課題に対処するいくつかの選択肢を提供しているため、次の論理的なステップのように思えました。最もシンプルなアプローチは Realm Cloud のパブリック API に依存することでした。別の選択肢として、Realm のコネクタコンポーネントを使用してより柔軟性の高いクラウドプラットフォームにデータを同期することも考えられました。AWS は最も成熟したエコシステムの一つであり、私もそれに関して豊富な実践経験があるため、AWS をプラットフォームの基盤として選択することは自然な決断でした。

しかし、このアプローチには重大な欠点がありました。プロダクション利用のために、Realm Cloud のユーザーごとのライセンスを購入する必要があり、それは私たちが導入を検討していた「フリーミアム」モデルでは経済的に持続不可能でした。また、Realm は MongoDB に買収されており、すべての機能は引き続き利用可能でしたが、Realm は MongoDB Atlas 製品スイートに完全統合される可能性が高いと予測していました。Realm の将来に関するこの不確実性は、実行可能な選択肢にはならないことを意味していました。

6.png

他の既製同期ソリューションも調査しました。AWS AppSync はセットアップが簡単で他の AWS サービスとの統合も良好ですが、SQLite をベースに使用する独自のクライアントサイドライブラリを持つ主観的なフレームワークです。これを iOS と統合するためには多大な労力が必要でした。

カスタムプロトコルの構築

これらの課題が、独自の同期プロトコルを作成するという決断につながりました。より大きな初期投資が必要でしたが、スタックを完全に所有することで、新興スタートアップとして必要な長期的な柔軟性が得られると確信していました。

モバイルアプリケーションのドキュメントデータのオフラインストレージとして Realm を維持しながら、スタックから Realm Cloud を完全に排除することにしました。その代わりに Craft Sync Service を開発しました。これはモバイルアプリとサーバー間の双方向通信に socket.io を使用しています。このサービスはすべてのスペース関連データを RDS Postgres インスタンスに保存し、他のサービスもアクセスできます。たとえば、Publishing Service はパブリックにアクセス可能なエンドポイントを提供しており、Publish Page ウェブビューアーがシークレットリンクのドキュメントデータを取得するために使用しています。

Realm Connect の代わりに、中央の Sync Service と通信する独自のアプリ内同期コンポーネントを構築しました。ローカルデータベースで変更が発生するたびに、または別のデバイスがクラウドに変更をアップロードするたびに、私たちのプロトコルがすべてをデバイス間で自動的に同期することを保証します。

7.png

このプロトコルを作成するにあたり、リアルタイムコラボレーションに使用されるプロトコルや、AppSync のような他のソリューションがどのように同期を実装しているかなど、さまざまな情報源からインスピレーションを得ました。同期プロトコルの詳細については、近日公開予定のブログ記事でお伝えする予定です。

プラットフォーム化

プロダクトが成熟するにつれて、内部の複雑さも増していきました。開発者が効率的に作業し、ミスのリスクを最小限に抑えられるようにする必要がありました。そのために、モバイルとバックエンドシステム、そして新しいウェブベースのエディタのプラットフォーム化を始めました。

このプロセスでは、システム内に明確な境界を設けることが求められました。モバイルおよびウェブアプリケーションにとっては、UI コンポーネントとデータコンポーネントの完全な分離が含まれていました。それぞれの開発には異なるエンジニアリングのマインドセットが必要だからです。UI 開発はより創造的なアプローチを必要とし、素早いイテレーションと頻繁な実験が伴います。一方、データコンポーネントの開発は、一貫したデータを確保するためにより緻密なアプローチが求められます。UI 開発者は、データ操作や同期の複雑さを心配する必要がなく、ユーザーインタラクション向けに特別に設計された明確に定義されたプラットフォーム API に頼ることができるべきです。

バックエンドサービスのプラットフォーム化では、明確なデータ所有権の定義と、他のサービス向けの内部 API の公開が含まれていました。最も重要なコアサービスである Craft Sync Service は、すべてのドキュメント関連データを所有しています。他のサービスはこのデータに直接アクセスまたは変更することはできず、明確に定義された内部 API を経由する必要があります。これにより、ドキュメントデータの一貫性が維持され、アプリケーション間で自動的に同期されます。

さらに、独自の同期プロトコルを持つことで、フロントエンド固有のカスタマイズの機会が生まれました。たとえば、ウェブエディタは、モバイルアプリとは異なる同期ニーズを持っています。モバイルアプリは Craft スペース全体を同期し、スペースを開くとすべてのドキュメントデータがオフラインで利用可能になります。それとは対照的に、ウェブエディタは主にオンラインで動作し、個々のドキュメントを同期します。同期プロトコルを完全にコントロールすることで、ウェブエディタのこのドキュメント単位のシナリオに合わせてカスタマイズすることができます。

8.png

まとめ

Craft の同期機能を構築・進化させてきた歩みは、Craft の成功において不可欠なものでした。複数のデバイスにまたがるシームレスなコラボレーションとアクセスを実現してきたのです。同期スタックを完全に所有することで、アプリケーションの固有の要求に応える柔軟性とコントロールを手に入れました。このアプローチにより、優れたユーザー体験を提供できると同時に、Craft が進化するにつれてスケールし適応できる体制も整えています。

Craft の基盤として Realm からスタートしたことで、強力な同期ソリューションを備えたプロトタイプを迅速に構築でき、コンセプトの検証が可能になりました。しかし、ユーザーベース、プロダクト、チームが成長するにつれて、既製ソリューションの限界が明らかになり、私たちは独自の同期プロトコルを開発しました。

同期スタックを完全に所有することで、アプリケーションの固有の要求に応えるために必要な柔軟性とコントロールを獲得しました。このアプローチにより、優れたユーザー体験を提供できるようになり、Craft の進化とともにスケールし適応できる体制を整えることができました。

今後も革新を続けるにあたり、Craft のプラットフォーム化への取り組みが、迅速な開発と長期的な安定性の両方を支える、クリーンで効率的なアーキテクチャの維持を保証します。

ブログをもっと読む