現代のアプリケーションは、複雑なサービスの集合体です。
故障する可能性や、期待どおりに動作しない可能性を持つサービスが、相互に連携し合って構成されています。
Flutterとその開発言語であるDartは、イベント駆動型、並行処理、そしてパフォーマンスの高いアプリケーション開発のために設計されています。
それらを使用する開発者にとって、適切なデバッグツールを使いことなすことは必要不可欠です。
デフォルトのFlutterツールには、他言語よりも優れたデバッグとプロファイリングのツールスイートが含まれており、多くの開発者をサポートしています。この堅牢な基盤によって、人気のあるIDE向けのプラグインや外部モニタリングプロバイダが、Flutterアプリケーションに対する深い洞察を得ることができます。
この記事では、いくつかのオプションを紹介し、それらがFlutterのデバッグとプロファイリングにどのように役立つかを説明します。
Flutterデバッグの例
Flutterデバッグに必要なトップツールとヒントを網羅するために、例を交えながらお伝えしていきます。
この情報収集の目的は、複数のタスク、課題、およびToDoのソースを統合し、それらをソートおよびフィルタリング可能なリストで一緒に表示するアプリケーションを作成することです。
では、TrelloとGitHubの課題からアイテムを取得し、リストで表示するアプリケーションを例として挙げて進めていきます。
このアプリケーションは2つのAPIからデータを取得し、JSONレスポンスを解析し、データ構造を統合し、それらをスクロール可能なリストで表示する必要があります。
このアプリケーションの進捗状況はGitHubで確認できます。
ログ記録のオプション
一般的な開発者であれば「console.log()」といったログを出力するコードを書く所から解析を始めるでしょう。
これが最適な方法ではないことはわかっていますが、簡易なデバッグであればこれで充分です。
FlutterとDartには、これを行うための3つの方法があります。
print()、stdoutそしてstderrを使用してメッセージをコンソールに記録できます。
詳細な情報を受け取るためにdart:developerのlog()関数を使用できます。
log()関数を使用すると、タイムスタンプ、エラーレベル、スタックトレースなどの複数のオプションパラメータが追加された状態で出力されます。
Flutterでフラグをデバッグする方法は
FlutterはUIに焦点を当てたアプローチを取り、アプリケーションインターフェースはしばしば数十のカスケードウィジェットから構成されるため、アプリケーションのUIに対する視覚的なフィードバックはとても重要です。
Flutterにはクラスに追加できるいくつかのデバッグフラグがあります。ただし、FlutterのDevToolsにはこれらのフラグを複製(および改善)する機能があるため、それらを使用する目的がない限り、出来るだけ使用しない方が良いでしょう。
Flutterのドキュメントには、これらのフラグの概要が記載されており、レンダリングパッケージのプロパティリストには完全なリファレンスがあります。
DevToolsパッケージ
Flutterの最も強力な機能の1つは、DevToolsパッケージです。これはデバッグやパフォーマンス分析機能を提供するツール集です。Android Studio、IntelliJ、またはVS Codeのプラグインと組み合わせて使用するのが最適ですが、ブラウザ内またはコマンドラインからも使用できます。
組み込みツールとして、多彩な機能を提供しており、以下が含まれます。
- UIのレイアウトと状態を検査
- UIパフォーマンスの問題を診断
- CPUプロファイリング(プロファイルモードのみ)
- ネットワークプロファイリング(プロファイルモードのみ)
- ソースレベルのデバッグ
- トレースをサポートするタイムラインビュー
- メモリの問題をデバッグ
- 実行中のアプリに関する一般的なログと診断情報を表示
- コードとアプリのサイズを分析
アプリケーションをデバッグモードまたはプロファイルモードで実行すると、DevToolsは自動的に開始し、エディター内で表示されるか、コマンドラインから実行した場合はブラウザで表示されます。DevToolsはデフォルトで多くの情報を表示しますが、エディタープラグインを使用してブレークポイントを設定することで、その機能を最大限に活用することができます。
DevToolsを使用して、ブラウザからUSBケーブルで接続した物理デバイスまで、どこからでも実行中のFlutterアプリケーションをデバッグすることができます。
Flutterアプリケーションをデバッグするためのエディタープラグインには
Android Studio、IntelliJ、およびVS Codeのプラグインは、DevToolsをIDEにバンドルしており、アプリケーションが実行中でも上記でリストに挙げた機能をリアルタイムで活用できます。
ブレークポイントを設定すると、DevToolsはアプリケーションをブレークポイントで一時停止し、アプリケーションが宣言する変数を含む現在のアプリケーションの状態を表示します。その後、DevToolsのUIを使用してアプリケーションの状態を検査し、実行を続行できます。
Sentry Flutterプラグイン
Flutterはアプリケーションを構築する際に包括的なデバッグツールを提供しています。
本番環境でのエラー追跡とモニタリングが重要であり、Sentryはそのサポートを提供しています。
これには手動で追加された例外のキャッチングや、本番環境のパフォーマンス監視が含まれ、Sentryはこれらに加え、メタデータやスクリーンショットなどの情報を提供します。
実際の問題をデバッグする
これらの様々なツールは、アプリケーションのデバッグをどのようにサポートするのでしょうか?
以下は、私が遭遇したエラーの具体例と、それらを解決するのに役立ったツールの一部をご紹介します。
もちろん、他にも多くのエラーに悩まされましたがそれらのほとんどは人為的なものでした 😅
開発にはVisual Studio Codeを使用していますが、開発中にブラウザでアプリケーションをテストしたため、エディターとブラウザの両方で同じDevToolsが利用可能でした。
私が遭遇した問題と課題は、以下の通りです。
- 外部サービスの誤ったAPIエンドポイントの呼び出し
- 正しいエンドポイントを使用しつつも、誤った引数を指定した呼び出し
- 正しいエンドポイントを正しい引数で呼び出したが、不適切なペイロードが返却された
- 互換性の問題や障害を引き起こすような古い依存関係を使用している
- 期限切れのトークンを使用している
- APIコールからのペイロードの検査
アプリケーションのなかでも最も重大な問題の1つは、異なるAPIコールが異なる形式のペイロードを返したということでした。
REST APIは想像よりも標準的ではないことがあるとわかりました。
幸いなことに、監視されている変数をホバーして現在の値を確認することで、この問題を確認できました。
別の例では、2つのJSON文字列を結合してオブジェクトを作成する必要があり、変数の値を探ることで、どのような文字列操作が必要かを確認できました。
この操作には、1つの文字列の末尾から角かっこを削除し、もう1つの文字列の先頭から角かっこを削除し、2つの文字列をカンマで連結することが含まれます。
ログステートメントを使用することで同じ目的を果たすことができますが、変数を監視する方が整然としています。
現在、アプリケーションには複雑なUIはありませんが、最終的には多くのプロパティを持つ多くのウィジェットで構成された長いネストされたウィジェットのリストになります。
ウィジェットツリーインスペクターは、そのウィジェットツリーがどのように組み合わさっているかを理解するために不可欠です。
多くのAPIを呼び出す際の主な問題は認証することです。
キーやトークンの生成・保存が必要になり、そしてこれらは期限切れになることがあります。そうすると、本番環境でのアプリケーション不具合に繋がる可能性も生まれます。
組み込みのFlutter DevToolsは問題の原因をデバッグするのに役立つかもしれませんが、本番環境での問題にはアラートを表示しません。Sentryのような外部のパフォーマンスモニタリングツールは、それができます。
APIへの呼び出し元など、適切な箇所に計測用コードを追加することで、生成されたエラーが意味を持つようになります。
.envファイル内のトークンの値を変更することで、誤った認証情報をシミュレートできます。これにより、Sentryで問題が生成され、チームメンバーにアラートが送信されます。
また、Sentryデバッグ情報を文字列の形式で送信することもできます。例えば、以下のように使用します。
“`dart
await Sentry.captureMessage(‘何かがうまくいかなかった’);
“`
同様に、Sentryは本番環境でのパフォーマンス監視に役立ちます。
ルーティングとウィジェットのパフォーマンスを観察するために、メインアプリケーションウィジェットに次のようにnavigatorObservers : [SentryNavigatorObserver()]が追加できます。
このアプリケーションは多くのHTTP APIを呼び出します。その中で応答が遅いものがあると、アプリケーションのパフォーマンスが低下します。
Sentryは、デフォルトの代わりにSentryHttpClientクラスを使用してHTTPリクエストを監視できます。例えば、次のようにします。
これにより、時間とともにSentryにパフォーマンスレポートが生成され、通常のパフォーマンスとそうでないもののレポートが得られます。
パフォーマンスページは失敗率も表示するため、API呼び出しのエラーを検出する代替方法として役立ちます。
他にも便利な機能として、エラー発生時のUI状態のスクリーンショットを追加できます。これは、FlutterのようなUI重視の言語に特に役立ちます。これを行うには、アプリケーションをSentryScreenshotWidgetでラップし、アプリケーションを子要素にするだけで実現可能です。
そして、Sentryの`SentryFlutter.init`メソッドに`options.attachScreenshot = true;`を追加します。
最後に、DevToolsウィジェットインスペクタツリービューを反映させるために、ビュー階層をJSON文字列としてSentryに送信し、Sentryが問題にレンダリングすることもできます。これを行うには、`options.attachViewHierarchy = true;`をSentryの`SentryFlutter.init`メソッドに追加します。
次のステップ
ここまで色々なことをお伝えしてきましたが、アプリケーションはまだまだ不完全です。
Jiraの統合や、さまざまなサービスを処理するためのミドルウェア、適切なUI、ブラウザ外でのアプリケーションの正常な動作など、重要なサービスを追加する必要があります。
しかし、私が使用したプログラミング言語の中で、DartとFlutterは最も統合されたツールを提供していました。
その提供する機能の全容を理解するまで時間がかかるかもしれません。
しかし、それはあなたにとって大きな価値になる可能性を秘めています。
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。