イン 私は、グーグルが現代の誘惑に無礼に「ノー」と言ったことを称賛しました。 Google Calendarの秘密のエンジニア兵器:制限 Fullstack Engineerを読んでくれてありがとう! 新しい投稿を受け取るために無料でサブスクリプトし、私の仕事をサポートしてください。 サイン "Use a frontend framework." No. JavaScript. "Use Typescript." No. Javascript. "Use a trendy CSS tool." No. CSS classnames. "Give us a native desktop app." No. Browser. "Give us dark mode." No. "Make it really fast." No. 彼らのシンプルさへのコミットメントは、GCalが数十億人の普通の人々のデフォルトカレンダーとしての地位を守るのに役立ちました。 しかし、API クライアントにとって、同じシンプルさが人生を悲劇的に複雑にします。 その複雑さがどのように浮かび上がるのか、そして私たちは建設者としてそれから何を学ぶことができます。 タグ: Data In-Sync Cool Calendarと呼ばれるクールな新しいカレンダーを構築しています。 ユーザーが始めるのを助けるには、既存の Google カレンダーをインポートすることを許可します。 これは、ユーザーのGoogleカレンダーデータにアクセスする必要があります。 あなたはGCal APIを見て、典型的な容疑者を見る: “Cool,” you think. “I just gotta get the , 次に、そのカレンダーのすべてのイベントを取得します. イベントを更新する必要がある場合は、 『GET』 答え » calendarId eventId events これらすべてをいくつかの簡単な機能で行うことができます: すべてのイベントはあなたのDBにあり、ユーザーがUIからイベントを更新した後もユーザーのGCalに表示されます。 あなたはGCalアプリを開いて、「Denny'sで祝う」という新しいイベントを作成し、あなたのシナモンロールパンケーキを楽しみにしています。 Cool Calアプリは開いているが、新しいイベントは表示されない。 あなたの空っぽの胃は、あなたがソリューションの半分(CoolCal → GCal)だけを実装したことに気付くように沈む。 GCal 変更が Cool Calendar (GCal → CoolCal) に拡散することを確認する必要があります。 否定 あなたは、他の人がこれまでこの用例に遭遇したことを知っていますので、GCal APIドキュメントを再訪問します。 幸いなことに、あなたは「ガイド」と呼ばれるガイドを見つけました。 」 資源を効率的に同期 ガイドは短く、あなたを楽にします。 どうやら、ほんの数回の呼び出しを追加する必要があるようだ。 何件のイベントが更新されたか、またはいつ更新されたかを知らないので、すべてを取得するためのループが必要です。 意味がある。 幸い、ドキュメントにはJavaでこれらのすべての部分が含まれています。 しかも使っているのはThe あなたを賢く感じさせるループング戦略。 do-while 確かにあなたはそれをJavaScriptに変換して進むことができます。 怒り 1時間経ち、あなたはスニップをJavaScriptと呼ばれる機能に成功して変換しました。 あなたの API を更新します。 syncGcal() 効きます! 走るたびに ユーザーの新しい GCal データが CoolCal に追加されます。 syncGcal() あなたはあなたの悩みのためにニューヨークスタイルのチーズケーキを含むことに決めます。 あなたが外に出る途中、あなたの疲れた脳にいくつかの質問が生じます。 syncToken はどこにも持続しない syncGcal() は、手動で呼び出されたときにのみ動作します。 How often should I run syncGcal() ? 毎時間? 毎分? Where will I store the token? 地元の倉庫? THE コレクション? user 新しいコレクション? What happens if the token becomes invalid? 引き続きリハーサルできますか? バックアップとして完全なインポートを行う必要がありますか? 配分制限はどうでしょうか。 このプロセス中にユーザーが変更した場合はどうなりますか? あなたは怒る - ガイドがこれらのエッジケースについてあなたに警告しなかったため、それからそれは必要であると仮定したあなたの天真さに。 交渉 「私は1人ではありません - 私は助けを求めることができます」あなたは、あなたがセラピーで練習したように、自分自身に言います。 あなたは、APIドキュメントには、呼ばれる方法があることを確信しています。 あなたが無視したもの。 syncResources() それともサービスとして提供されますか? あなたのためにすべてのデータを魔法で同期するYC会社のように。 少なくとも、あなたがクロードを指すことができるMITのレポを持っているリチャード・スタルマンの弟子がいるでしょう。 > clone the two-way sync stuff from github.com/stallman-cal. no bugs. 鬱 オフィシャルドッグはまだまだ。 すべてのYC企業はビルドエージェントです。 Stallman は、あなたの利益のためのカレンダーアプリを信頼しません。 (MITと呼ばれるプロジェクトがあります。 星は200個しかないが、信頼できない。 Compass スケジュール 誰もあなたの双方向の同期機能を気にしない。 実は、あなたは一人ぼっちです。 あなたの機械キーボードに一滴の涙が落ちて、あなたは今日デニーのところに行かないことに気づきます。 受け入れ 自家製のフランスのトーストと食後の散歩の後、あなたは本当のエンジニアのように行動し、それを自分自身で行う運命と合意します。 数週間後、ようやく終わりました。 But you still can't stop wondering 「なんでGCalはこんな風にやったの?」 「こんなに複雑でなければいけないのか?」 要求事項 You put yourself in Google's shoes by reverse-engineering the requirements in the form of a (PRD) 製品要件 Doc 解決策 それは面白かったので、それらの要件を満たすための解決策を文書化します。 (TDD) テクニカルデザイン Doc 分析 最後に、GCalの「Give 'em a token」ソリューションが良いかどうかを判断する資格があります。 Token Paginationの強み 彼らはクライアントから複雑さを隠すことができますので、すべてを理解する必要はありません(たとえば、多地域複製) Opaque tokens protect the client from overwhelm. トークンの有効期限を制御することで、GCalは、クライアントが増加同期中に削除を常に見ることを保証することができます。 Cleanly handles deletions. Googleは、クライアントに影響を与えずにストレージバックエンド、シェアディング戦略、またはトポロジーを完全に変更することができます。 ( ) Easier implementation changes. highscalability.com より 弱点 Webhook は何かが変わったことを示しますが、何が変わったかを示します。これは、すべての push 通知が新しい増加式同期呼び出しを引き起こすことを意味します。これは、パワーユーザーが頻繁にトイレを作るときにチャットするようになります。なぜ、push パワーロード自体に軽量な diff を含めないのか、または少なくともイベント ID が変更されたのかを示さないのですか? Push is disconnected from sync. . Incremental syncs are incompatible with the そして パラメータ. あなたは、あるいは別の方法を選択しなければなりません. これは、トークンよりも時間の面で考える人間のためのバカバカです。 Some filters are incompatible timeMin timeMax ページのトークンはエフェミリアルです。クライアントが中間のページ面(7ページの3ページ後)に故障した場合、彼らは全体の同期を再起動しなければなりません。 大きなカレンダーの場合、これは痛ましいです。 代替策は、セッションを通じて生き残る持続可能なページトークン、または同期の進行をチェックポイントすることです。 No partial sync recovery. 選択肢(そしてなぜ使用されなかったのか) Bottom Line sync token + cursor pagination は、 これは、Microsoft Graph (delta tokens)、Stripe (pagination cursors)、およびほとんどのエンタープライズ API によって使用される同じパターンです。 pragmatic, battle-tested pattern Googleは、内部の複雑さを隠し、カレンダーの使用例の99%に「十分に良い」同期セマンティクスを提供することを可能にするため、それを選択しました。 代替案(イベントソーシング、CRDT、OT)は、GCalがリアルタイムのコラボレーションまたは真のオフラインファーストP2P同期を必要とする場合にのみ有意義になります。 全画像 GCal で Google の目標が収益を生み出すことだったら、より多くのドキュメント、ビデオ、ウェブセミナーを提供するでしょう。 npm i gcal しかし、GCalとのGoogleの目標は、それほど野心的なものではない。 >> Don’t annoy regular users so much that they download Apple Calendar. 無料のAPIからそんなに期待するのは不公平です。 最初にGCalと統合できるのは驚くべきことです。 GCalは、アプリケーションの基本的な部分としての責任を尊重し、採用の便利さよりも信頼性を優先します。 多くの失敗は起こらない。 APIはドキュメントが言っていることを行いますが、それらがあまり言わない場合でも。 彼らは破壊的な変化であなたを驚かせません。 まだ、 彼らが最初に考えたとき、「私は知っています、私はGCalと統合するだけです。 there is a gap between the developer’s expectations and reality 現在、開発者はそのギャップを時間、努力、そして無邪気さの喪失で埋めなければなりません。 しかし、Googleはより多くのリソースを提供することによって痛みを軽減することができます。 たとえば、ドキュメントはより多くの実装ガイドラインを提供することができます。 コードサンプルは、裸のレポからデモアプリケーションに進化する可能性があります。 バランス上、APIをシンプルに保つことは正しい動きでした。 原始的なAPIは、電源ユーザーを悩ませる可能性があります。 しかし、それがUX、収益、保持、またはブランドに影響を与えない場合は、それを単純にしてください。 Takeaways for Builders(建設者向け) Public Sync API を作成するとき Keep it boring: use existing standards ここでは、GCal の API がどのようにカルソーパジネーションと同期トークンに基づいて構築されているかを見ました。そのイベント モデルはまた、既定の標準に基づいて構築されています: CalDAV、iCalendar、RRULEs。 彼らの最適化されたバージョンを発明する代わりに、彼らは基本に固執しています. これは、彼らのAPIが2006年に公開されて以来(Yahooとは異なり)多くの成功したGCal統合が行われた大きな理由です。 Use cursor pagination when the data is a moving target 読書中に書き込みが起こるときは、複製や欠落した行を避けるためにページ間の一貫性が必要です。 Examples: Calendars, feeds, audit logs, append-only streams. 例えば、カレンダー、フィード、監査ログ、添付のみのストリーム。 Use offset pagination when the data is stable データが静的で並行書き込みがない場合は、より単純なアプローチで取り除くことができます。 例:ページ番号を含む検索結果、小さなデータの管理テーブル。 Don’t oversell the API あなたはPRを終えるために朝にエキサイティングになり、それから徒歩で ... それはあなたが思ったよりも複雑で、翌日の午後まで日光が見えないことに気づくために、どのように感じるかを知っています。 Google の API は、すべてのことをあなたのためにすることを約束しません。 最終製品はAPIを販売します:製品と統合する開発者を喜ばせることを心配する前に、ユーザーを喜ばせる時間を費やします。 Don’t break things もし、あなたの統合が他人の製品に基づいているのなら、ゆっくりと進んでください。 移住のテストに時間を費やす 起動する前にドキュメントに関するフィードバックを得る。 「ヘッドアップ」メールやターミナルメッセージを送信して、誰も驚かない。 これには「クレークヘッド・ヴィブ・コーデー」から「規律のあるソフトウェアエンジニア」へのアイデンティティの転換が必要です。 必ずしも正しいとは限りませんが、責任を真剣に受け止めます。 1つの変更は3つの機能が良いものよりも多くのダメージを与えます。 GCalのAPIは安定しているので、幸いなことに睡眠スコアはそれを使用して以来落ちていません。 Public Sync API を統合する場合 Don’t start with an integration 「しかし、私のユーザーは、すでに使用しているツールと統合しない限り、私のアプリを使用しません。 「しかし、私のユーザーは、すでに使用しているツールと統合しない限り、私のアプリを使用しません。 もしかしたら、でも、そう言わせてあげてください。 統合を追加することは、あなたの製品市場に適した旅のための高価なサイドクエストです。 値プロンプトが十分な場合は、新しいアカウントを作成し、ゼロからデータを追加するのに問題はありません。 Accept that Pareto is right つまり、最後の20%のタスクは時間の80%を要します。 エッジケースとゴッチャの表面は、実装するにつれて拡大します。 Googleのドキュメントは、物事がシンプルで無料であると考えるよう誘惑する唯一のものではありません。 彼らの約束は、リトリ、idempotency、fallback、delta syncs、offline、token invalidation、quotas、および conditional requests (ETags) を考慮することによって制限されます。 あなたはあなたのMVPのためにそれらをすべて必要としませんが、彼らが最終的に現れることを期待します。 Simplicity for one party means complexity for another シンプル UI 複雑なバックエンド 普通のユーザーにとっては良い、電力ユーザーにとっては難しい。 シンプルな価格→複雑なR&D シンプル API → 複雑な統合 次回、「この無料のAPIを使おう」と思ったら、簡単に見えます。 It’s either free or simple; Someone always pays. さあ、パンケーキを買おう。