Skip to main content
OutSystems

OutSystemsモバイルアプリのベストプラクティス

モバイルアプリはまったく新しい考え方を開発モデルにもたらします。ユーザーは、モバイルアプリのエクスペリエンスに対して大きな期待を持っています。一方で、デバイスの制約とネットワークの制約がそのエクスペリエンスに大きく影響を及ぼすことがあります。ユーザーはそういった状況や制約にかかわらず、モバイルアプリに魔法のような機能を期待しています。

ユーザーに最高のモバイルエクスペリエンスを提供するモバイルアプリを開発するために、常に念頭に置くべき重要なルールがいくつかあります。

モバイルユースケースを対象にして開発を進める
優れたモバイルエクスペリエンスを実現するために最適なユースケースを選択します。簡単なことから始め、繰り返します。最適化した少数のコンテンツを使用します。重要なものを先に表示します。OutSystems UIフレームワークで提供されているものなど、一般的なモバイルパターンを使用します。
負荷が大きいロジックはサーバー側で実行する
クライアント側の情報はできるだけシンプルに保ちます。複雑なデータ処理や計算は、できるだけ少ないサーバーリクエストを使用してサーバー側で実行します。クライアント側では実行結果をキャッシュします。
 
JavaScriptよりもOutSystemsのローコードを選択する
実行時に最適なパフォーマンスを提供するため、OutSystemsは自動的にコードを最適化します。JavaScriptは、OutSystemsのローコード言語ではできない操作や高度な拡張シナリオでのみ使用してください。
実際のシナリオでアプリをテストする
モバイルアプリが使用される状況を把握し、本番環境へのデプロイ前に十分にテストします。デバイスの制約、ネットワークの制約オフライン時間が優れたユーザーエクスペリエンスの妨げにならないことを確認します。

この記事では、これらの基本ルールに重点を置きながら、OutSystemsのモバイルアプリのユーザーエクスペリエンスとパフォーマンスに影響を及ぼす一般的なリスクの回避に役立つベストプラクティスについて説明します。オンライントレーニング「Becoming a Mobile Developer」をまだ受けていない場合は、まずこのトレーニングで高品質なモバイルアプリの開発方法について学習してください。

この記事は今後も更新し、新しい内容を追加する予定です。

ユーザーインターフェイス

優れたUIエクスペリエンスにより、ユーザーはモバイルアプリが高速で操作しやすいように感じます。このセクションでは、OutSystemsのモバイルアプリのUIエクスペリエンスを向上させるためのベストプラクティスを示します。

OutSystemsコンポーネントを見つけて利用する

一般的なモバイルパターンを一から開発するのは大変手間がかかるうえに、完成品を作り直すようなものです。

推奨事項

一般的なモバイルパターンを多く提供するOutSystems UIフレームワークやOutSystems Forgeコンポーネントを使用します。改良された最新版のメリットを得るため、必ず最新のものを使用します。

コンテンツ取得時の空の状態を設計する

ユーザーが画面を遷移すると、通常は静的コンテンツが最初に描画されます。動的コンテンツは非同期的に取得されるため時間がかかります。このため、動的データの描画中はコンテンツが不完全な状態で画面が表示され、UIエクスペリエンスが低下します。

推奨事項

動的コンテンツの取得中に表示される空の状態の画像を設計することで、ユーザーエクスペリエンスを向上させます。FacebookやLinkedInがよい例です。

Design an Empty State for Content Being Fetched

この方法は、ブロック、カード、リストアイテムといった画面のあらゆる動的コンテンツで有効です。空の状態から取得したコンテンツに切り替わるときに、ちらつきを感じる場合があります。このちらつきを防ぐには、ぼやけた灰色の線やスピナーなどの画像を1つ選択し、スムーズに画面が遷移できるようにします。

画面コンテンツの描画の優先順位を指定する

OutSystemsのデフォルトでは、モバイルアプリの画面データの取得に特定の優先順位はありません。関連性が高く、最初に描画すべきコンテンツが画面に含まれているにもかかわらず描画の優先順位を指定していない場合、ユーザーエクスペリエンスが低下することになります。たとえば、画面の主要な情報より先に広告バナーが表示される場合などです。

推奨事項

二次的なコンテンツの描画を遅らせ、主要なコンテンツが先に描画されるようにします。そのためには、以下の手順を実行します。

  1. 二次的なコンテンツをIfウィジェットのTrueブランチ内のブロックに配置します。このブロックに二次的なコンテンツを取得するためのロジックをすべて含め、ブロックが描画されたときにのみ二次的なコンテンツのデータ取得が実行されるようにします。

  2. IfウィジェットのFalseブランチに空の状態を配置し、二次的なコンテンツの取得時にコンテンツが移動するのを防ぎます。

  3. If条件をデフォルトでFalseとなる変数に設定します。

  4. 変数をTrueに設定するロジックを画面のOn Renderイベントに追加し、二次的なコンテンツの描画が開始するようにします。

Prioritize Screen Content Rendering

Imageウィジェットの幅と高さを設定する

Imageウィジェットの幅と高さを設定していない場合、最後の画像のダウンロード中にユーザーがちらつきを感じることがあります。たとえば、画像の高さが設定されていないと、ウィジェットの高さが0pxから最後の画像の高さに変化するため、画像の読み込みが完了するまでの間に画面全体の高さが変化する場合があります。

推奨事項

Imageウィジェットの幅と高さを予測される最後の画像のサイズに設定します。

clipboard_e8a64cf35f459fe507336b34b0503affd.png

パフォーマンス

特にモバイルシナリオにおけるデータの処理やロジックの実装は、モバイルアプリのパフォーマンスに大きく影響を及ぼすことがあります。パフォーマンスに優れたモバイルアプリを開発するには、このセクションのベストプラクティスに従ってください。また、他のセクションのベストプラクティスもご覧ください。パフォーマンスに直接関係はしないものの、パフォーマンスの向上につながる場合があります。

パフォーマンスに関する警告を修正する

OutSystemsでは、Development環境でのモバイルアプリの開発中に、潜在的なパフォーマンス上の問題が自動的に検出されます。こうした問題に注意を払わないと、アプリケーションのパフォーマンス低下につながるおそれがあります。 

Performance Warnings

推奨事項

[TrueChange™]タブに表示されるパフォーマンスに関する警告を確認して修正します。

軽量なローカルストレージを設計する

オフラインシナリオやキャッシュシナリオなどでデバイスのローカルストレージに大量のデータをため込むと、ローエンドデバイスのパフォーマンス低下の原因になる場合があります。

推奨事項

以下の手法を使用して軽量なローカルストレージを設計します。

  • 対応するサーバーエンティティのすべてのアトリビュートを使用するのではなく、必要なアトリビュートのみを使用して、ローカルストレージのデータモデルを設計します。複数の結合を含むなどのクエリの複雑化を避けるため、ローカルデータモデルの非正規化を検討します。

    Design a Lightweight Local Storage

  • ユースケースに最適なデータ同期パターンを特定し、必要なときに実行されるように設計します。

  • ローカルストレージにすべてのレコードを保存するのではなく、ユースケースに必要なエンティティレコードのみを保存します。たとえば、すべてのタスクを取得するのではなく、特定の期間内に開かれたタスクのみを取得します。

  • データを小さなグループに分け、最も関連性の高いデータから順番に同期することを検討します(たとえば、テキスト情報のみを先に同期し、写真やその他の画像は後で同期することができます)。

スプラッシュ画面をシンプルかつ高速に保つ

モバイルアプリを起動すると、内部オペレーションが実行される間、スプラッシュ画面が表示されます。スプラッシュ画面に負荷の高いオペレーションや時間がかかるオペレーションを追加すると、アプリを使用するまでのユーザーの待機時間が長くなります。また、スプラッシュ画面内に複雑なUIがある場合、スプラッシュ画面が描画されるまで空白の画面が表示されることがあります。

Keep the Splash Screen Simple and Fast

推奨事項

シンプルで読み込みが速いスプラッシュ画面を保つには、以下のようなものを避ける必要があります。

  • サーバーへのリクエスト
  • 重いロジック
  • 複雑なUI(ブロックが多すぎるUI)

たとえば、以下のようなアプローチを検討します。

  • サーバーリクエストはできる限り、後の段階で実行されるOn Readyなどのイベントハンドラ内で行います。アプリの初期化段階でサーバーデータを取得する必要がある場合は、サーバー呼び出し数を最小限にします(たとえば、読み込み段階用に設計された単一のサーバーアクションを使用してデータを取得するなどします)。

  • モバイルアプリの起動時に時間のかかるオペレーションを実行しないようにします。たとえば、アプリの最初の画面で使用されるデータを同期する必要がある場合、データの転送を最小限に保ち、二次的なデータの転送は後回しにします。

ヒント: 優れたユーザーエクスペリエンスを提供するため、ネイティブのスプラッシュ画面をカスタマイズすることも推奨しています。

画面のサーバーデータ取得を最適化する

サーバーのAggregateのOn After Fetchを使用して他のAggregateを連続して実行すると、複数のサーバーリクエストが生成され、アプリケーションが遅くなります。

推奨事項

適切な順序でAggregateを含むデータアクションを作成します。このアクションはサーバーで単一のリクエストで実行され、すべてのデータを返します。

Optimize Fetching Server Data for a Screen

リストの読み込みを最適化する

リストでは複数のレコードの取得と描画が同時に実行されます。慎重に使用しないと、特にローエンドデバイスの場合やネットワーク接続が良好ではない場合に、エクスペリエンスが悪化する可能性があります。

推奨事項

リストを最大限に活用して優れたエクスペリエンスを実現するには、以下のルールに従います。

データをオンデマンドで取得する
すべてのレコードを一度に取得するのではなく、必要に応じて取得します。最初は最小限のレコード(たとえば、10レコード)を取得します。ユーザーが下にスクロールしたときに、On Scroll Endingイベントを使用して次のレコード(たとえば、続きの10レコード)を取得します。
この動作を理解するには、画面のリストをスキャフォールディングします。このメカニズムはデフォルトで用意されています。
リストアイテムをシンプルに保つ
Google Mapsなどのマップを読み込むJavaScriptのような複雑なロジックやウィジェットを使用するリストアイテムを設計しないようにします。リストに描画されるアイテムの数に応じて複雑さが増大します。
リストアイテム内でコンテンツの展開を避ける
トリムされて[Show All...]リンクがある説明のように展開可能なコンテンツを含むリストアイテムを設計しないようにします。これにより、リストの描画中の動作が影響を受けます。SplitScreenMasterDetailなどのSilk UIパターンを代わりに使用します。
リストデータの取得方法をオンデマンドで微調整する
最初に読み込まれるレコードの数、下スクロール時の増加数、On Scroll Endingイベントをトリガーするスクロールしきい値を調整します。これにより、表示に関する問題やリストのスクロール速度の低下を避けることができ、リスト使用時のユーザーエクスペリエンスが向上します。 
使用する値は、レコードのサイズに依存します。
  • 最初の取得アイテム数は、データ取得速度と追加レコードのリクエストが行われるまでの実用的なスクロール量のバランスがとれるようにします。
  • スクロールによってトリガーされる取得アイテムの増加数は、通常は最初の取得アイテム数に近い数にしますが、アプリの使用状況に基づいて調整する必要がある場合があります。 ユーザーが頻繁にリストを使用してエントリを検索する場合、アプリがデータの取得を高速化し、多くのアイテムを一度に読み込むことができるようにする必要があります。
  • 新しいアイテムの取得をトリガーするスクロールしきい値は、スクロールがリストの最後に達するまでの距離(ピクセル単位)であり、2,000ピクセルに設定する必要があります。 アプリケーションの使いやすさを改善するためにこのしきい値を調整する必要がある場合は、リストウィジェットにinfinite-scroll-thresholdアトリビュートを追加してInteger値(ピクセル単位)を設定します。

以下の図は様々な状況で使用する値の例を示しています。まずこれらを最初のガイドラインとして使用し、テストした後、個別のケースに応じて調整します。

オンデマンドでのデータ取得中に視覚的なフィードバックを提供する
表示すべきリストアイテムがほかにもあり、実際に何らかの処理が行われていることを、明確にユーザーに示す必要があります。アニメーション付き画像を使用すると、このメッセージがユーザーに十分に伝わります。しかし、パフォーマンスの目標として、一般的なアプリケーションの使用状況において、ユーザーがリストの最後で読み込みができなくなることがないようにする必要があるということに留意します。

画像のファイルサイズを最適化する

特に旧型のデバイスの使用時や低速な接続環境のシナリオでは、モバイルアプリで大きなイメージファイルを使用すると、ダウンロード時間の延長やダウンロード妨害につながり、パフォーマンスの低下を引き起こす可能性があります。また、これらはストレージ領域を消費し、高解像度モデルのモバイルデバイスの画面に対しても大きすぎる可能性があります。

推奨事項

目標とするユーザーエクスペリエンスを考慮して、(バイトでの)イメージサイズを削減し、面積(高さ/幅)を調節します。Googleの画像の最適化に関する推奨事項に従います。また、画像の取得を後の段階に遅らせることも検討してください。ベストプラクティス「画面コンテンツの描画の優先順位を指定する」をご覧ください。

JavaScript

OutSystemsは、高速かつ最適化されたJavaScriptコードによるモバイルアプリを生成します。独自のJavaScriptコードを追加するかどうかは慎重に検討する必要があります。これを適切に行うことができるようにするには、以下のガイドラインに従います。

カスタムJavaScriptではなく、OutSystemsのローコードを使用する
OutSystems UIOutSystems Forgeでは、モバイルアプリの実装でよく使用されるコンポーネントが提供されています。シナリオに必要なコンポーネントをほとんど見つけることができ、必要に応じてカスタマイズできます。
JavaScriptは本当に必要なときに使用し、ベストプラクティスに従う
OutSystemsのローコードはよりパフォーマンスに優れています。しかし、独自のJavaScriptを使用する場合はこのセクションのベストプラクティスを読み、これらに従うことが重要でありことに留意します。
内部APIではなく、OutSystemsの公開JavaScript APIを使用する
内部APIはサポートされず、アップグレード時に変更されてJavaScriptコードが使用できなくなる可能性があります。

業界のJavaScriptに関するベストプラクティスに従う

JavaScriptを作成する場合は、必ず実装しているコードの内容とアプリへの影響を把握するようにします。

推奨事項

W3SchoolsやこれらのJavaScriptのコーディング標準およびベストプラクティスの説明にあるような、JavaScript開発に関するベストプラクティスに従います。

たとえば、パフォーマンスに優れたJavaScriptセレクタを使用してDOMから要素を取得したり、要素の幾何学的情報の再計算(レイアウトまたはリフロー)をブラウザでトリガーするプロパティおよびメソッドを避けたりします。

Follow the Industry JavaScript Best Practices

外部JavaScriptライブラリの使用を避ける

外部JavaScriptライブラリは、モバイルデバイス上で起動するには複雑すぎる可能性があります。

推奨事項

OutSystems UIまたはOutSystems ForgeでOutSystemsコンポーネントを探して、これらを外部JavaScriptライブラリの代わりに使用します。

しかし、明らかにJavaScriptライブラリを使用する必要に迫られている場合、JavaScriptノード内ではなく、Script要素内で使用します。

Avoid Using External JavaScript Libraries

Script要素内でJavaScriptコードを使用すると、以下のことが可能になります。

  • JavaScriptライブラリをアプリによりクリーンな状態で実装できます。
  • JavaScriptライブラリごとに単一のソースを持つようになり、同じJavaScriptコードを複数回解析することを回避できます。

JavaScriptコードをクライアントアクションでリファクタリングする

同じJavaScriptコードを複数のJavaScriptノードで繰り返すと、メンテナンスの手間が増え、アプリのエラーが発生しやすくなります。

推奨事項

JavaScriptノード内で繰り返されるJavaScriptコードは、クライアントアクション内でカプセル化します。そのJavaScriptを実行する必要があるたびに、このクライアントアクションを呼び出します。こうすることでJavaScriptコードが1箇所になり、アプリのメンテナンスの手間が少なくなります。

たとえば、console.log()console.error()alert()などのトラブルシューティングに関するJavaScript関数をクライアントアクションでカプセル化します。

Refactor JavaScript Code into Client Actions

DOMの操作を避ける

OutSystemsのモバイルアプリはReactを使用しており、JavaScriptでDOMを操作すると予期しない動作や望ましくない動作が発生する場合があります。

推奨事項

DOMを操作するJavaScriptは使用しないようにします。これは高度なユースケースの場合のみです。

既知のモバイルパターンを実装する場合は、OutSystems UIまたはOutSystems Forgeで検索してください。

Avoid Manipulating the DOM

グローバルオブジェクトの使用を避ける

OutSystemsでは、モバイルアプリのランタイム実行を最適化するためにシングルページアプリケーションを使用しています。このため、ナビゲーションの間にウィンドウオブジェクトがクリアされず、グローバルオブジェクトが破棄されないため、長時間実行するとメモリ使用量が増大します。

推奨事項

グローバル変数、キャッシュオブジェクト、リスナーなど、ウィンドウオブジェクトにアタッチされたオブジェクトの使用を避けます。代わりに以下の手順を実行します。

  • localStorageおよびsessionStorageオブジェクトなどのブラウザ機能を使用します。

  • JavaScript変数の宣言時に「var」キーワードを使用してスコープを限定します。

    Avoid Using Global Objects

OutSystemsのローコードを使用してウィジェットのスタイルを変更する

JavaScriptを使用してCSSクラスを追加/削除し、ウィジェットのスタイルを変更すると、コードの見やすさと整合性の低下や、描画中のちらつきの発生などの問題の原因になる場合があります。

推奨事項

ウィジェットのStyle Classesプロパティを使用して、ウィジェットに適用されるCSSクラスを変更します。このプロパティで実行時に評価される式を使用し、スタイルを動的に変更できます。

Change Widgets Style using OutSystems Low-code

アニメーションにJavaScriptではなくCSSを使用する

通常、JavaScriptアニメーションはデバイスのCPU(中央処理装置)上で実行され、モバイルアプリのパフォーマンスに直接影響を及ぼします。

推奨事項

OutSystemsのローコードとスタイルクラスを使用して、デバイスのGPU(グラフィックスプロセッシングユニット)上でアニメーションを実行し、CPUに負荷がかからないようにします。たとえば、「Making Magic with WebSockets and CSS3(WebソケットとCSS3を使用してマジックを作成する)」では、カードのアニメーションにCSSを使用しています。

Use CSS for Animations instead of JavaScript

モバイルアプリの要素にアニメーションを適切に設定する方法については、「Smooth as Butter: Achieving 60 FPS Animations with CSS3」および「60 FPSアニメーションをフリップする、うまくフリップする」をご覧ください。

しかし、本当にJavaScriptを使用する必要がある場合はwindow.requestAnimationFrame()メソッドを使用し、GPUでアニメーションを実行します。

トラブルシューティング

モバイルアプリのバグを把握することは難しいタスクとなる場合もありますが、トラブルシューティングプロセスを円滑に進めるためのテクニックがいくつかあります。また、以下に示す開発のガイドラインに従うと、モバイルアプリにおける問題の再現と修正がさらにしやすくなります。

ネイティブプラグインのフォールバックを定義する

デスクトップブラウザでアプリのトラブルシューティングを行っているときは、ネイティブプラグインを使用できません。このため、実際のモバイルデバイスで検出された問題のトラブルシューティングができない場合があります。

推奨事項

プラグインがなくなった時期や機能しなくなった時期を把握するために、適切なフォールバックをアプリに含めます。これにより、確実にデスクトップブラウザでアプリをテストできるようになります。これを行うには、特定のプラグインが利用できない場合にエラー(または、その代わりのテスト用のモックデータ)を返すクライアントアクションに、プラグインの呼び出しをラップします。

以下の例では、ContactsネイティブプラグインのAddToContactsアクションが、プラグインが利用可能かどうかを最初に検証するAddToContacts_Safeという名前のクライアントアクションにラップされています。

Define Fallbacks for Your Native Plugins

これらのフォールバックの配置することで、特定のプラグインをサポートしないデバイスで実行されているアプリの問題の回避にも役立ちます。

シンプルなクライアント側のロギングシステムを作成する

クライアント側の問題はトラブルシューティングが難しい場合があり、特に、本番の1人のユーザーのデバイスで問題が発生していると思われる場合は困難です。問題を再現できないと、問題の特定と修正が非常に難しくなります。

推奨事項

OutSystemsには、モバイルアプリの情報をログに記録する方法があります。また、クライアント側のロギングシステムを作成し、ローカルストレージにログエントリを保存することもできます。これにより、ユーザーはエラー発生時にこれらのログをアップロードできます。これを利用して、特定のユーザーのデバイスで発生した問題の原因を分析できます。