mcpField
F
flutter-debugging

flutter-debugging

github.com/vp-k開発1453 回インストール12 週間前に更新
リポジトリ

flutter-debugging について

Flutter開発者向けの体系的なデバッグスキルです。変更前に根本原因を特定して検証し、問題の再現、正常な実装との比較、仮説の検証、修正確認へと進めます。

主な機能

  1. 01修正前に根本原因を調査
  2. 02問題を安定して再現
  3. 03異常な実装と正常な実装を比較
  4. 04仮説を一つずつ検証
  5. 05解析とテストで修正を確認

活用シーン

  1. 01ウィジェットのビルドや描画エラーを診断
  2. 02状態、ナビゲーション、ネットワークの不具合を調査
  3. 03ビルド失敗やテスト失敗を追跡

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/vp-k/flutter-craft --skill flutter-debugging

インストール後、Claude Code で/flutter-debuggingを入力して読み込まれたか確認します。

詳細

システマティックな Flutter デバッグ

概要

手当たり次第の修正は時間を無駄にし、新たなバグを生みます。応急処置では根本的な問題が隠れてしまいます。

基本原則: 修正を試みる前に、必ず根本原因を特定してください。症状への対処は失敗につながります。

開始時に宣言: 「この問題を調査するため、flutter-debugging スキルを使用します。」

鉄則

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST

フェーズ 1 を完了していない場合、修正を提案してはいけません。

使用する場面

あらゆる Flutter の技術的な問題で使用します。

  • ウィジェットのビルドエラー
  • 状態管理のバグ
  • テストの失敗
  • UI の描画問題
  • ナビゲーションの問題
  • API/ネットワークエラー
  • ビルドの失敗
  • プラットフォーム固有の問題

特に次のような場合に使用してください。

  • 「ちょっとした応急処置ですぐ直せる」と思える
  • すでに複数の修正を試した
  • 前回の修正で解決しなかった
  • 時間に追われている

Flutter デバッグツール

1. コンソールログ
// Basic logging (truncates long output)
print('Debug: $value');

// No truncation (preferred)
debugPrint('Debug: $value');

// Conditional debug logging
import 'package:flutter/foundation.dart';
if (kDebugMode) {
  debugPrint('Only in debug mode: $value');
}

// Developer log with tags
import 'dart:developer';
log('API response', name: 'NetworkService', error: e);
2. Flutter DevTools
# Open DevTools
flutter run --start-paused
# Then press 'd' or use DevTools button in IDE

DevTools のパネル:

  • ウィジェットインスペクター: ウィジェットツリー、プロパティ、レイアウト
  • パフォーマンス: タイムライン、フレーム描画
  • メモリ: ヒープ使用量、リーク
  • ネットワーク: HTTP リクエスト/レスポンス
  • ログ: すべてのログを一か所に表示
3. デバッグ用ウィジェット
// Show widget boundaries
debugPaintSizeEnabled = true;

// Show baseline alignments
debugPaintBaselinesEnabled = true;

// Show repaint regions
debugRepaintRainbowEnabled = true;
4. ブレークポイント
// Programmatic breakpoint
import 'dart:developer';
debugger();

// Or use IDE breakpoints

4 つのフェーズ

フェーズ 1:根本原因の調査

どんな修正を試みる前にも、必ず次のことを行います。

1. エラーメッセージを注意深く読む
════════════════════════════════════════════════════════════
EXCEPTION CAUGHT BY WIDGETS LIBRARY
════════════════════════════════════════════════════════════
The following assertion was thrown building MyWidget:
'package:flutter/src/widgets/container.dart': Failed assertion: line 287
'child != null || decoration != null || constraints != null'
════════════════════════════════════════════════════════════

エラーを読み飛ばさないでください。 多くの場合、そこには正確な解決策が示されています。

2. 安定して再現する
# Hot reload to reproduce
r  # in terminal

# Hot restart (clears state)
R  # in terminal

# Full restart
flutter run
  • 確実に再現できますか?
  • 正確な手順は何ですか?
  • ホットリロードとホットリスタートで違いはありますか?
3. 最近の変更を確認する
# What changed recently?
git diff

# Recent commits
git log --oneline -10

# Diff with specific commit
git diff HEAD~3
4. 診断用ログを追加する
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    debugPrint('=== MyWidget.build() ===');
    debugPrint('context.mounted: ${context.mounted}');

    final state = context.watch<MyState>();
    debugPrint('state: $state');

    return Container(...);
  }
}
フェーズ 2:パターンの分析
1. 動作する例を見つける
# Search for similar working code
grep -r "similar_pattern" lib/
  • 問題のあるものと似ていて、動作しているものは何ですか?
  • ウィジェットの構造や状態管理を比較します。
2. 参照例と比較する
// Reference: Working widget
class WorkingWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<WorkingBloc, WorkingState>(
      builder: (context, state) => ...,
    );
  }
}

// Broken: My widget
class BrokenWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // What's different?
    return BlocBuilder<MyBloc, MyState>(
      builder: (context, state) => ...,
    );
  }
}
3. 違いを特定する

どんなに小さくても、すべての違いを列挙します。

  • ウィジェットの種類
  • 状態プロバイダーの位置
  • BuildContext の使用方法
  • ライフサイクルメソッド
フェーズ 3:仮説の立案と検証
1. 仮説を 1 つ立てる

次のように明確に述べます。

「[Y] であるため、問題は [X] だと思います」

例:

「ウィジェットツリー内でこのウィジェットより上に BLoC が提供されていないため、ビルドエラーが発生していると思います」

2. 最小限の変更で検証する

可能な限り最小の変更を加えます。

// Before (broken)
Widget build(BuildContext context) {
  final bloc = context.read<MyBloc>();
  return ...;
}

// After (testing hypothesis)
Widget build(BuildContext context) {
  debugPrint('Looking for MyBloc...');
  try {
    final bloc = context.read<MyBloc>();
    debugPrint('Found: $bloc');
  } catch (e) {
    debugPrint('Error: $e');
  }
  return ...;
}
3. 次に進む前に検証する
  • 解決しましたか? → フェーズ 4 へ
  • 解決しませんでしたか? → 新しい仮説を立てる
  • さらに修正を重ねないでください
フェーズ 4:実装
1. テストケースを作成する(優先度に応じて任意)

Repository/DataSource の問題(優先度 1)の場合:

test('should return user when API succeeds', () async {
  // Arrange
  when(mockApi.getUser(any)).thenAnswer((_) async => userModel);

  // Act
  final result = await repository.getUser('123');

  // Assert
  expect(result, equals(userEntity));
});
2. 修正を 1 つ実装する

一度に変更するのは 1 つだけです。

// Fix the root cause identified in Phase 3
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => getIt<MyBloc>(),
      child: BlocBuilder<MyBloc, MyState>(...),
    );
  }
}
3. 修正を検証する
# Run analysis
flutter analyze

# Run tests
flutter test

# Manual verification
flutter run
# Test the specific scenario
4. 修正で解決しない場合
  • 試した修正の数を数えます。
  • 3 未満の場合:フェーズ 1 に戻り、再分析する
  • 3 以上の場合: 作業を止めて、アーキテクチャを見直す

Flutter でよくある問題と根本原因

症状よくある根本原因
"No ancestor found"Provider/BLoC がウィジェットツリー内で対象より上にない
"setState after dispose"ウィジェットの破棄後に非同期処理が完了している
"RenderBox not laid out"制約が無制限になっている(Column の中に Column があるなど)
"Null check operator"変数が初期化されていない、または API が null を返した
"Build during build"ビルドフェーズ中に setState が呼び出されている
"Ticker not disposed"with TickerProviderStateMixin または dispose がない

危険信号 — 作業を止めて手順に従う

次のように考えていることに気づいたら:

  • 「とりあえず応急処置しよう」
  • 「try-catch で囲めばいい」
  • 「ここに null チェックを追加しよう」
  • 「Container で囲めばいい」
  • 「とりあえずホットリスタートしよう」
  • 「たぶん状態の問題だから、リセットしてみよう」

これらはすべて、作業を止めてフェーズ 1 に戻るべきサインです。

必須のサブスキル

バグを修正した後、必ず次を呼び出してください。 → flutter-craft:flutter-verification

flutter analyze、flutter test、手動テストで修正を検証してください。

クイックリファレンス

フェーズFlutter での作業成功基準
1. 根本原因エラーを読み、再現し、debugPrint を追加する何が起きているのか、なぜ起きているのかを理解する
2. パターン動作するウィジェットを見つけ、比較する違いを特定する
3. 仮説仮説を立て、最小限のテストを行う仮説が確認されるか、新しい仮説が得られる
4. 実装優先度に基づいてテストを作成し、修正して、検証するバグが解消され、解析に問題がない

系統的に進める理由

場当たり的な修正をすると、試行錯誤を繰り返すことになりがちです。失敗した推測のたびにコードが汚れ、元の症状が見えにくくなります。根本原因を最初に特定するデバッグなら、変更を最小限に抑え、修正を検証可能にし、「いろいろ試す」うちに新たなバグを持ち込むのを防げます。

コメント