Claude CodeやGitHub Copilotなどのコーディングエージェント(自然言語の指示からコードを自動生成するAIツール)を使って、スマートウォッチや組み込み機器向けのアプリを書いている、あるいはこれから書こうとしているエンジニアに向けた内容です。今回は「モダンなUIアーキテクチャの提案が、リソース制約の厳しい環境では思わぬCPU負荷を招く」という落とし穴を整理します。
最近のAIコーディングエージェントは、Reactのフック(コンポーネントに状態管理などの機能を後付けする仕組み)のような設計パターンを、ほぼ反射的に提案してきます。学習データの大半がWebやモバイルの潤沢なリソース環境のコードだからです。この傾向が、Garmin ConnectIQのような組み込み系プラットフォームでは裏目に出ることがあります。
何が起きるか:AI提案の設計パターンがフレームレートを壊す
Garmin向けアプリ開発言語のMonkey C(Garminが提供する独自のオブジェクト指向言語)で、Reactのフックに似た独自ライブラリを構築し、単方向データフロー(状態が一方向にしか流れないUI設計)とコンポーネント分離を導入する試みが報告されています。
狙いはテストしやすさの向上でした。しかしフック的な仕組みを描画ループ(画面更新のたびに繰り返し呼ばれる処理)の内部で直接呼び出したところ、CPU負荷が過大になったとされています。
GarminのWatchApp(単体で動作するスマートウォッチアプリ)は、メモリ割り当てがキロバイト単位、CPUクロックも公式仕様は非公開ながら数百メガヘルツ程度と見積もられる環境です。この制約こそが、Garminの強みである数週間持続するバッテリー寿命を支えています。
裏を返せば、モバイルアプリやWebフロントエンドの感覚で「関数コンポーネントを細かく分けて、フックで状態を管理する」設計を持ち込むと、1フレームごとのオーバーヘッドが数百ミリ秒単位の処理時間の中で無視できない割合を占めてしまいます。
なぜ起きるか:AIの提案とハードウェア制約のミスマッチ
原因を段階的に分解すると、3つの層が重なっています。
1つ目は学習データの偏りです。AIコーディングエージェントが参照する膨大なコード例は、React・Vue・Swift UIなどメモリもCPUも潤沢な環境向けがほとんどです。フックパターンやコンポーネント分離は、そうした環境では「良い設計」として何千回も強化学習されています。
2つ目は、AIが「動くコード」は生成できても「動作コストの見積もり」までは提示しない点です。描画ループ内で毎フレーム関数を呼び出す設計は、構文的には正しく動きます。しかし1フレームあたり何ミリ秒かかるかは、実機かエミュレータで計測しない限りAIの回答には現れません。
3つ目は、Monkey Cのような言語仕様の特殊性です。Connect IQ SDKにはガベージコレクションの挙動やメモリ上限に関する制約があり、汎用言語のベストプラクティスがそのまま通用しません。AIエージェントはMonkey Cの学習データ自体が少ないため、汎用パターンをそのまま適用してくる傾向が強くなります。
自分のプロジェクトが該当するか確認する方法
以下のいずれかに当てはまる場合は、AIが提案する設計をそのまま採用する前に一度立ち止まる価値があります。
- Connect IQ SDK(Garmin公式の開発キット)でWatchAppやWatch Faceを開発している
- マイコン・組み込みRTOS・IoTデバイスなど、メモリがMB未満・CPUが1GHz未満の環境をターゲットにしている
- AIエージェントに「Reactライクな状態管理を実装して」「フックパターンで書き直して」のように指示している
- 生成されたコードに
onUpdateやonLayoutなどの描画コールバック内で、複数の関数呼び出しやオブジェクト生成が含まれている
確認コマンドとしては、Connect IQ SDKに含まれるシミュレータのプロファイラを使う方法があります。
# Connect IQ SDK Manager でシミュレータを起動後、
# monkeydo コマンドでアプリをビルド・実行する
monkeyc -d 実機の型番 -f monkey.jungle -o bin/app.prg
monkeydo bin/app.prg 実機の型番シミュレータ上でonUpdateの呼び出し頻度とCPU使用率を確認し、AIが提案した抽象化レイヤーを導入する前後で比較するのが確実です。
対策の手順
対策として有効だったのは、フックの利便性は残しつつ呼び出しコストを下げる2つのパターンです。
Props Packing Pattern(プロップス梱包パターン) は、コンポーネント間で渡すデータをオブジェクトではなく配列にまとめる方法です。Monkey CはDictionary(連想配列)よりArray(配列)の生成・参照コストが低いため、頻繁に生成される描画用データを配列で受け渡すことでメモリ確保の回数を減らせます。
Container/Presenterパターン は、状態管理を担うContainerと、描画だけを担うPresenterを分離する設計です。Reactの世界でも使われる古典的なパターンですが、Presenter側を「フック呼び出し無しの純粋な描画関数」にすることで、描画ループ内の余分な処理を最小化できます。
この2つを組み合わせた結果、1フレームあたり0.8ミリ秒程度のオーバーヘッドに抑えられたとされています。トレードオフとして得られたのは、エミュレータなしでヘッドレスにUI統合テストとベンチマークを実行できる開発体験です。
実際にAIエージェントへ設計を依頼する際は、次のような指示の出し方が有効です。
Monkey C (Garmin Connect IQ) 向けにUIコンポーネントを設計してください。
制約: メモリはキロバイト単位、CPUは数百MHz相当です。
onUpdate内でのオブジェクト生成やDictionary操作は避け、
配列ベースのデータ受け渡し(Props Packing Pattern)を優先してください。
状態管理と描画処理はContainer/Presenterパターンで分離してください。このように制約条件とパターン名を明示的にプロンプトへ含めることで、汎用的なフック実装をそのまま提案されるリスクを減らせます。
まとめ
AIコーディングエージェントは、モダンなUIアーキテクチャの提案自体は的確でも、ターゲット環境のリソース制約までは考慮してくれません。
まず自分のプロジェクトがGarmin Connect IQやマイコン系の組み込み環境に該当するか確認し、該当する場合はシミュレータのプロファイラで描画ループのコストを実測してください。
そのうえでAIへの指示に「メモリ・CPUの制約」と「Props Packing Pattern」「Container/Presenterパターン」のような具体的な設計語彙を含めることで、実運用に耐えるコードへ近づけられます。
新しいライブラリやパターンを導入する前に、一度エミュレータでの計測を挟む習慣が、後々の手戻りを防ぐ一番の近道です。