パフォーマンス向上のTips
具体的なパフォーマンスの向上方法について、解説します。
“RepeatingGroup”内の検索を工夫する
“RepeatingGroup”内にある要素で行う処理は、セルごとに毎回行われます。
例えば、メッセージアプリで各スレッドの未読メッセージの数とスレッドのリストを表示したい場合を考えてみましょう。未読メッセージの数を表示する方法として、以下のように実装したとします。
この方法だと、全てのセルで”Message”の検索が行われてしまいます。したがって、100スレッドがある場合、各行に正しい数の未読メッセージを表示するために100回の検索が必要になります。検索回数は少ないほどパフォーマンスの向上につながります。検索回数が減らせるような改善案は次のようになります。
ページの表示されない部分に”RepeatingGroup”を追加します。ここで現在の”User”が未読のメッセージを全てまとめて先に検索しておきます。そしてスレッドを表示するための”RepeatingGroup”の中の各セルでは、先ほど検索しておいた未読メッセージから、現在のセルのスレッドに当てはまるもののみをフィルタリングします。
この実装方法だと、未読メッセージの検索は1回になり、あとは直接フィルタリングされるため、より高速になります。
- “RepeatingGroup”のセル内で検索を使用すると、各セルごとに検索するため、パフォーマンスが悪化する
- 改善策としては以下の2点
- ページのどこかに”RepeatingGroup”を設置し、先に検索しておく
- 上記をfilterdすることで、検索回数を減らすことができる
入れ子で使用する”Do a search for”を最小化/排除
複数の”Thread”を持つ単一の”Room”があり、それぞれが複数の”Message”を持つデータ構造を想像してみましょう。特定の”Room”内のすべての”Message”を見つけたい場合は、以下のような検索を行い、”Room”にリンクされている”Thread”に属するすべての”Message”を見つけることができます。ただし、この入れ子で使用された検索(検索内の検索)は、Bubbleが最初に”Room”に属するすべての”Thread”を見つけてから、それらの”Thread”の1つに属するすべての”Message”を見つける必要があるため、時間がかかります。
改善案としては、各”Message”オブジェクトを”Room”オブジェクトに直接リンクする方法です。これは冗長に見えますが(“Message”が属する”Thread”が属する”Room”を直接的に参照できるため、検索をより高速にすることができます。
この実装方法は、プライバシールールの設定の簡略化にも効果的です。
- “Do a search for”を入れ子で使わない
“Ignore empty constraints”の使用に注意
画像の実装方法だと、”Ignore empty constraints”にチェックされているにもかかわらず、Emailフィールドが「Group email」の値に設定されています。この場合、Group emailが空になってしまうと、検索はemailの制約を無視して、全てのuserを返してしまいます。解決方法としては、3つあります。
1, “Ignore empty constraints”を使わないという方法です。こちらは簡単に解決できる反面、問題が出てきてしまう場合もあります。例えば、すべてのユーザーを表示する”RepeatingGroup”と、その繰り返しグループの上にユーザーがキーワードを入力して繰り返しグループをフィルタリングできる検索ボックスがある場合は、”Ignore empty constraints”オプションを使用することが効率的です。こうすることで、キーワードが入力された時だけ”RepeatingGroup”に検索がかかります。
2, グループが空にならないようにする方法です。こちらは少し難しいですが、上の画像の場合だと、”When page is loaded”を使い、”Group email”の値を設定することで対応できます。しかしページが読み込まれる前に一瞬グループが空になってしまい、その間に”RepeatingGroup”が全てのユーザーを読み込もうとする可能性があり、アプリケーションの動作が重くなります。
3, Conditionalを使って、グループがからでない時のみ”Ignore empty constraints”を使う、という制御をする方法です。
- 原則「Ignore empty constraints」を使わないようにする
- 実装上どうしても使用しなければいけない時は、Conditionalで「条件が空じゃない場合」という制御のもと、使用する
検索をせずリストを使った方がいい場合
データベースに”Project”というオブジェクトと”Invoice”というオブジェクトがあるとします。各”Project”は複数の”Invoice”を持つことができます。通常のデータベース構造では、各”Invoice”に”Project”のフィールドを作成し、その後、「Do a search for Invoices where Project is equal x」というような検索を行います。
この一見通常な処理ですが、検索を省くことでよりパフォーマンスを上げることができます。
具体的には、”Project”オブジェクトに”Invoice”をリスト型で持たせ、直接そのリストを参照するという方法です。これにより、毎回の検索処理を避け、アプリケーションの処理速度を向上させることができます。
リストより検索を使った方がいい場合
上記はリストが比較的数ない場合のみ有効になります。別の場合を考えてみましょう。
“Song”というオブジェクトと”Tag”というオブジェクトがあるとします。各”Song”には複数の”Tag”を適用できます。この場合、各”Tag”に””Song”をリスト型で持たせると、非常にリストが大きくなってしまいます。大きいリストは扱いづらく、処理が遅くなる原因にもなりかねません。
そのためこの場合は、各”Song”に”Tag”のフィールドを作成する方が効率的です。特定の”Tag”を持つ”Song”を探す場合は、”Song”に検索をかけていく必要ああります。
リストを使った方がいい場合 | 検索を使った方がいい場合 |
子レコードが少ない | 子レコードが多い |
子レコードは一つの親レコードを持つ | 子レコードが複数の親レコードを持つことができる |
- Listを参照する際は、パフォーマンスを考慮して以下のように使い分ける。
- レコードが30件以下であれば、親レコードに紐づいている「List of」で参照する
- レコードが30件以上であれば、子レコードに紐づいている親レコードを条件に、検索によって参照する
“filter advanced”を最小化/排除
“filter advanced”は高度なフィルタリングをすることができ便利な機能ですが、注意しないとユーザーの速度が大幅に低下する可能性があります。
Bubbleの仕組みとして、ブラウザはまずフィルタリングが必要なすべてのレコードをダウンロードしてから、フィルタリングを開始するようになっています。
例えば、”Swooo”というテキストを含むメールアドレスを持つすべてのユーザを見つけることを考えてみましょう。高度なフィルタを使用してこれを行うと、アプリケーションはブラウザにユーザーのバッチをダウンロードし、この条件に一致するかどうかを確認し、一致するユーザーが繰り返しグループを満たさない場合は別のバッチをダウンロードします。ユーザーの数にもよりますが、多ければ多いほど処理に長い時間がかかってしまう可能性が高まります。例えば、900人のユーザーがいるアプリでは、約300人のユーザーと4 MBのデータがページにダウンロードされ、通常よりも20秒長くページを読み込むという結果もあります。
- フィルタリングしているリストに含まれるオブジェクトの数が少ない場合 (およそ 2 ~ 100 個のオブジェクト)、高度なフィルタは比較的迅速に実行できます。
簡単な解決策としては、”Swooo email”のようにUserオブジェクトにyes/noフィールドを割り当て、それを検索式の条件として含める方法です。
この場合はUserのEmailを割り当てる際に、Swoooというテキストが含まれているか検証し、そのUserの”Swooo Email”にyesかnoを割り当てましょう。
“filter advanced”を使用しており、それらを削除したい場合は、フィルター対象のオブジェクトに直接フィールドを追加することを検討してください。オブジェクトに新しいフィールドを追加し、これらの新しいフィールドに新しいデータを保存するためのワークフローを作成し、既存のすべてのアプリデータに対してそのフィールドの値を計算または更新するAPIワークフローを設定する必要があります。
フィルタリングする必要のあるリストの数が最終的に数百または数千になる可能性がある場合、”filter advanced”の使用はできるだけ避けて、パフォーマンスの向上を目指しましょう。
- “filter advanced”はなるべく使わないようにする
- “filter advanced”を使わなければ実現できない場合は、直接フィールドを追加する
デフォルトで要素をhiddenに設定する
パフォーマンスを向上させるもう1つの方法は、最初に読み込まれたときにページ上の要素を非表示にすることです。最初のレンダリングの時の要素が少なくなり、後の要素のレンダリングには時間がかかるため、ユーザーはページの最初のコンテンツをより早く見ることができます。
これを行う良い例は、ある種の内部タブナビゲーションを持つページを構築しているときです。ページがロードされると、ナビゲーションメニュー、ヘッダー、およびフッターのみがロードされ、ページは後でタブのコンテンツをロードします。いくつかのビューをページのデフォルトビューに設定し、ページの読み込み時に表示する方が自然に思えるかもしれませんが、これにより不要なコンテンツが一瞬追加され、ページの読み込み時間が長くなります。
- 最初に読み込まれたときにページ上の要素を非表示にすることで、ページ速度が改善される
プライバシールールの設定
アプリケーションのプライバシールールを設定することデータのセキュリティを保つためにとても大切です。
その他にも、プライバシールールを設定すると、ブラウザに送信されるデータの量はプライバシールールによって制限されます。そのため、データの漏洩や不必要な送信を防ぐことができます。
また、取得したデータに対して操作を行う場合や、”RepeatingGroup”を使用する際に、間違えた処理を設定してしまい、不必要なデータの取得が行われようとした場合でも、プライバシールールによってデータの制限が行われます。これにより、プライバシールールの設定は、パフォーマンスの向上にも役立つ場合があります。
- プライバシールールを設定することで、ブラウザに送信されるデータ量を減らすことができるため、ページ速度のパフォーマンスが向上する
長時間のアクションをAPIワークフローに移行
アプリケーションを開発する中で、非常に長いワークフローが必要になることがあります。
特に、外部API呼び出し、リストの変更やコピー、複雑な検索などが含まれる場合、処理に時間がかかってしまう場合があります。
この解決策としては、ワークフローの一部をAPIワークフローに移行するという方法があります。
ページ上で実行する必要のあるもの(”alert”など)のみを実行し、その他はAPIワークフローに必要なパラメーターを渡して処理をします。
この方法を使うことで、物事をよりモジュール化できるという利点もあります。ロジックを再構築することなく、アプリケーションの別の部分から同じAPIワークフローを呼び出すことができます。
- ワークフローが長くなる場合は、ワークフローの一部をAPIワークフローやCustom Eventに移行する
Data APIを有効に活用する
Data APIを使うことで、処理をより効率化できる場合があります。以下の場合を考えてみましょう。
登録時に、各ユーザーが30個のリマインダーオブジェクトを作成するリマインダーアプリを構築しています。これには以下の3つの実装方法があります。
1, ページ上で全てのオブジェクトを作成する方法です。この方法は複雑で処理がおそくなってしまう可能性があります。オブジェクトを1つずつ作成するので、ページ上に不要なワークフローが発生します。
2, スケジュールAPIワークフローを使用してリストアクションですべてのオブジェクトを作成する方法です。この方法は処理的にはシンプルにまとまるため良いのですが、欠点として非同期的になってしまいます。オブジェクトの作成が終了したタイミングを簡単に知ることができず、作成したリストも参照することができません。
3, Data APIの一括作成機能を使う方法です。この方法も処理はシンプルにまとめられており高速な上に、同期的です。作成されたオブジェクトのリストを返すことができます。
- 一括でデータを作成・更新する際は、以下のように使い分ける
- 同期的、またはデータを参照したい場合:Data API
- 非同期、かつデータを参照しなくてもいい場合:Schedule API Workflow on a List
Chromeのネットワークタブを活用する
Chromeの開発者ツールのネットワークタブを使用して、ページがどのように読み込まれているか、何が最も時間、スペースを占めているかを確認できます。簡単に使い方を紹介します。より詳細な情報はこちら
1, 確認したいページ上で右クリックをし、出てきたメニューの中にある「検証」をクリックします。
2, 「Network」タブに切り替えます。(画像1を参照)
3, 「Size」をクリックし、サイズ順に並び替えます。
4, 上部に「search」または「msearch」という項目が表示されている場合、それらはアプリケーションが実行している検索を表します。検索アクションを調べるためにその項目をクリックします。
5, 詳細情報が表示されたら、「Preview」タブを展開し、どのようなデータが表示されているかを確認できます。このプレビュー情報により、アプリケーションがどのようなデータを取得または送信しているかが分かります。(画像2)
要素が多すぎる場合の問題点
ページやデータビューを表示するために、数千の異なるHTMLノードを読み込む必要があると、読み込み時間が劇的に増加する可能性があります。これは、大量のデータ(100以上)を含む可能性がある”RepeatingGroup”を使用する場合に特に問題となります。
例を挙げると、”RepeatingGroup”が各タブに20のHTML要素をレンダリングする場合、50のデータポイントを表示するためにページに1000のHTML要素が表示されることになります。これはユーザーのデバイスが非常に高速でない場合、読み込みにかなりの時間がかかる可能性があります。
上記の場合だと、読み込みが遅くなるだけで表示はできますが、表示ができなくなってしまう例としては、”RepeatingGroup”内で再利用可能な要素を使用することです。”RepeatingGroup”内に”popup”要素やメニューがある場合、それらは各セルでレンダリングされます。データテーブルには3〜4つの異なるオプションがあり、それぞれに独自のポップアップが必要で、いくつかは複数の入力を必要とする場合、タブごとにレンダリングされる要素の数が大幅に増加することがあります。(タブごとに要素の数が10倍以上になることもあります)
この問題を回避するためには、以下の2つの方法があります。
1, これらのポップアップやメニューが必要かどうか考え、再利用可能な要素を削除する。
2, ダッシュボードがあるページに、これらのポップアップを直接配置する。再利用可能な要素からカスタムステートを使って、ダッシュボードがあるページでの”Do when condition is true”このワークフローをトリガーにできます。
“RepeatingGroup”によってロードされる要素の数を推定する
ページ上に実際どれくらいの要素があるのか、ChromeまたはFirefoxのJava Scriptコンソールを使用して簡単に調べることができます。
1, 確認したいページ上で右クリックをし、出てきたメニューの中にある「検証」をクリックします。
2, 「Console」タブを開きます。
3, ページが完全に読み込まれたら、次のテキストをコンソールに貼り付けます。
document.getElementsByTagName(“*”).length;
4, Enterを押します。
参考までに、この方法で取得されるいくつかの測定値を以下に示します。
ページの一部を読み込んで非表示にすると、それらの要素もHTML要素の数にカウントされます。
Webページ | HTMLの数 |
Google home page (google.com) | 251 |
Facebook home page (logged in user, facebook.com) | 4383 |
Twitter landing page (not logged in, twitter.com) | 668 |
エディタを遅くする要素が多すぎる可能性
Bubbleエディターで速度の問題が発生している場合は、1つのページに要素が多すぎる可能性があります。
これは、そのページのグループを再利用可能な要素に変換することで解決できます。再利用可能な要素内のBubble要素はBubbleエディタ内ではレンダリングされず、ページを変更するためにロードする必要のあるものの数が減少します。
再利用可能な要素を作成した後、次のいずれかに該当する場合、要素のロジックを変更する必要があります。
1, 再利用可能な要素内の要素が、再利用可能な要素の外部の要素を参照していた場合。
2, 再利用可能な要素内のワークフローが、再利用可能な要素の外部のページ上の要素を参照していた場合。
3, 「Do when condition is true」のワークフローが、再利用可能な要素内の要素を使用して設定されていた場合。
4, 再利用可能な要素内にある要素を参照していた外部の要素やワークフローが存在する場合。
再利用可能な要素を導入することで、Bubbleエディター内でのページの読み込み速度を向上させることができます。ただし、要素やワークフロー間の相互参照が変更される場合、それに応じてロジックを調整する必要があります。
- 1つのページに要素が多すぎると、Bubbleエディターの速度が遅くなってしまう。
- この問題は、一部をReusable Element化することで、改善される。
容量を増やす
可能な限りのことをしても、以下のような警告が表示される場合は、アプリケーションに容量を追加する価値があるかもしれません。Bubbleの「boost capacity」機能を使用して、支払いを行う前に最初に試すことができます。