Slide 1

Slide 1 text

AI時代のFlutter開発スペシャル by クラスメソッド AI時代だからこそ 「Bloc」を採用する価値があるのかもしれない クラスメソッド株式会社 リテールアプリ共創部 takuro abe

Slide 2

Slide 2 text

自己紹介 02 名前 takuro abe 所属 クラスメソッド株式会社 リテールアプリ共創部 最近の趣味 ランニング 5/10(日) 鹿沼さつきマラソン 10km 走ってきました 🏃 LINKS DevelopersIO / abe-tk X / @abe_tk6

Slide 3

Slide 3 text

目次 03 Agenda 01 AI時代の開発 02 BLoCパターン 03 Flutter Bloc 04 Flutter Bloc が AI開発で効く理由 05 まとめ

Slide 4

Slide 4 text

SECTION 01 AI時代の開発について

Slide 5

Slide 5 text

AI時代の開発について 05 AI・SKILL・TEAM AI時代の開発を、 3つの視点で整理します。 01 / AI AIエージェントが コードを書く時代 AIエージェントが、実装の主戦力になっている。 02 / SKILL SKILL・ルール・ワークフローで 品質が安定する エージェントの「振る舞い」を整備すれば、出力 のブレが大きく減る。 03 / TEAM チーム共有で 全員が同じ品質に SKILL をチームで共有すれば、誰が書いても近い 品質のコードが出てくる。

Slide 6

Slide 6 text

そこで考えたこと 06 Hypothesis AIに任せるなら、 ガードレール がある方がいい。 AI・RULES・TEAM が前提になるなら、状態管理・DI の選び方も変わるのではないか。 自由度が高い設計はブレやすく、構造の制約が効くほど出力は安定する。 HYPOTHESIS 書き方の制約が強い Flutter Bloc なら、 AI時代の開発に合うのではないか?

Slide 7

Slide 7 text

SECTION 02 BLoCパターン

Slide 8

Slide 8 text

BLoCパターン — 定義 08 Definition BLoC = Business Logic Component。 Business Logic Component UI からビジネスロジックを切り離し、再利用可能なコンポーネントとして扱うデザインパターン。 DartConf 2018 で提唱。 BLoC design guidelines — BLoC の 4 原則 ・ 入出力はすべて Stream / Sink ・ 依存は注入可能でプラットフォーム非依存 ・ BLoC 内にプラットフォーム分岐を書かない ・ 上記を守れば実装は自由 UI design guidelines — UI 側の 4 原則 ・ 「十分に複雑」なコンポーネントには 対応する BLoC を 1 つ ・ コンポーネントは入力を「そのまま」BLoC に流す ・ 出力も可能な限り「そのまま」表示する ・ 分岐は BLoC が出す真偽値で行う 出典: Flutter / AngularDart – Code sharing, better together (DartConf 2018)

Slide 9

Slide 9 text

BLoCパターン — 分離の価値 09 TEST・REUSE・CHANGE なぜビジネスロジックを 分離する のか。 01 / TEST UI なしで ロジックを検証できる BLoC 単体でユニットテストが書ける。Stream の入出力で状態遷移も追える。 02 / REUSE UI から独立、 横断で使い回せる 画面差し替えでもロジックは流用できる。プラッ トフォーム横断の再利用が元々の動機。 03 / CHANGE 責務が分かれ、 変更に強い UI / ロジック / データの責務が分かれるので、片 方の変更が他方を壊しにくい。差分レビューも局 所化する。

Slide 10

Slide 10 text

SECTION 03 Flutter Bloc

Slide 11

Slide 11 text

Flutter Bloc の構造 11 Structure — UI ⇄ Bloc ⇄ Data 状態の変更は Bloc が一手に 引き受ける。 UI 画面を描画する。 ユーザー操作を Event と して送出 する。 Bloc 状態変更の唯一点。 Event を受けて State を 発行する。 Data API・DB などの外部リソ ース。 Bloc からの呼び出しに応 える。 ※ Cubit(Event の代わりに公開メソッド呼び出しで State を更新する簡易版)には触れない。 UI Bloc Data Event State request response

Slide 12

Slide 12 text

Flutter Bloc の状態管理 — Event / State / Bloc 12 State management Event / State / Bloc。 flutter_bloc で3つを定義していくのが基本。 Event 入力 UIで何が起きたかを表す。 命名は 過去形、 sealed class で網羅。 sealed class HogeEvent {} final class HogeFugaPressed extends HogeEvent {} final class HogePiyoPressed extends HogeEvent {} State 出力 現在の状態を表す。 典型は loading / success / failure。 enum HogeStatus { initial, loading, success, failure } final class HogeState { const HogeState({ this.status = HogeStatus.initial, this.hoges = const [], this.exception, }); final HogeStatus status; final List hoges; final Exception? exception; // ※ 実運用は Equatable / freezed で == を実装 } Bloc 変換 Event を受け取って State を 発行 する。 on にハンドラを登録するだけ。 final class HogeBloc extends Bloc { HogeBloc({required this.repository}) : super(const HogeSt on((event, emit) async { // ... }); on((event, emit) async { // ... }); } final HogeRepository repository; }

Slide 13

Slide 13 text

Flutter Bloc のテスト — AAA(Arrange-Act-Assert)パターン 13 Test Bloc の単体テストは bloc_test で AAA に沿って書ける。 Arrange 準備 テスト対象と周辺を 組み立てる。 Stub・初期状態の設定。 blocTest( '...', setUp: () { when(() => repo.fetchHoges()) .thenAnswer((_) async => hoges); }, build: () => HogeBloc(repository: repo), seed: () => const HogeState(status: HogeStatus.loading), // ... ); Act 実行 検証したい操作を 1つ実行。 Event を add するだけ。 blocTest( '...', // ... act: (bloc) => bloc.add(HogeFugaPressed()), // ... ); Assert 検証 State 遷移と副作用を 検証。 順序も含めて検査できる。 blocTest( '...', // ... expect: () => [ isA() .having((s) => s.status, 'status', HogeStatus.loadi isA() .having((s) => s.status, 'status', HogeStatus.succe ], verify: (_) { // 副作用検証 (mock の呼ばれ回数など) }, );

Slide 14

Slide 14 text

SECTION 04 Flutter Bloc が AI開発で効く理由

Slide 15

Slide 15 text

ポイント 15 Point Flutter Bloc は 実装の ガードレール になる。 FRAMEWORK 構造を 強制する FOR AI AGENTS AI にも 扱いやすい

Slide 16

Slide 16 text

具体例1 — 一方向フロー → 誤用が物理的に起きない 16 Example 01 / 03 状態の書き換えは、 Bloc 内の emit() だけ。 FRAMEWORK CONSTRAINT // UI からは Event を投げることしかできない context.read().add(HogeFugaPressed()); // state setter は存在しないので、そもそもコンパイルが通らない context.read().state = const HogeState(...); // ← compile error // emit() は Bloc 内のハンドラからしか呼べない final class HogeBloc extends Bloc { HogeBloc() : super(const HogeState()) { on((event, emit) { emit(const HogeState(status: HogeStatus.loading)); }); } } EFFECT 誤用が 物理的に起きない 「UI で state を直接いじる」がそもそも書けない。 AI レビューが パターンマッチ になる フローから外れた実装は、構造を見るだけで即わかる。 チームで書いても ブレない 「正しさ」がフレームワーク側に守られている。

Slide 17

Slide 17 text

具体例2 — Event/State/Bloc の役割 → AI 雛形が一発で決まる 17 Example 02 / 03 Event 名を1つ渡すだけで、 雛形が ほぼ確定する。 PROMPT HogeFugaPressed を追加してください。 GENERATED FILES lib/feature/hoge/ ├── bloc/ │ ├── hoge_event.dart ← HogeFugaPressed を追加 │ ├── hoge_state.dart (既存利用) │ └── hoge_bloc.dart ← on └── data/ └── hoge_repository.dart (既存利用) test/feature/hoge/bloc/ └── hoge_bloc_test.dart ← blocTest 追加 OUTPUT EVENT Event クラス 過去形 / sealed class。 HogeFugaPressed がそのまま型になる。 BLOC Bloc ハンドラ on 登録 + Repository 呼び出し。 STATE State 遷移 HogeStatus enum で loading → success / failure を表現。 TEST blocTest(AAA パターン) Arrange / Act / Assert が build / act / expect にそのまま対応。

Slide 18

Slide 18 text

具体例3 — レイヤー分離 → テストの組み方が決まる 18 Example 03 / 03 レイヤー分離が テスト手法の選択に そのまま対応する。 レイヤー テスト手法 モック対象 備考 Data test() API クライアント / DB 外部 I/O をモック化、純粋な変換に集中 Bloc blocTest() Repository AAA パターンが自然に強制される UI testWidgets() Bloc(MockBloc) UI は状態を描画するだけ、と割り切れる EFFECT 何をモックすべきか 自明 レイヤーが分かれているので、隣のレイヤーだけをモッ クすればいい。 テストが 独立する UI / Bloc / Data を、それぞれ単独で検証できる。 AI でも 迷わない レイヤーごとの書き方が決まっているので、生成しても 安定する。

Slide 19

Slide 19 text

アプローチ — AI 開発で Flutter Bloc の構造を活かす 19 Approach ここまでの構造は、 SKILL / agent でチームに展開できる。 SAMPLE REPO — github.com/abe-tk/github-issues-app-with-bloc .claude/ ├─ skills/ │ ├─ bloc/ ← flutter_bloc の作法 │ ├─ layered-architecture/ ← レイヤー分離ルール │ ├─ testing/ ← bloc_test の使い方 │ ├─ plan-and-review/ ← 計画 → AI レビュー │ └─ impl-and-review/ ← 実装 → AI レビュー ├─ agents/ │ ├─ architecture-reviewer ← レイヤー違反を検知 │ ├─ plan-reviewer ← 実装計画の妥当性 │ ├─ standards-reviewer ← 命名・コーディング規約 │ └─ test-reviewer ← テスト観点 └─ rules/flutter.md ← Flutter 共通ルール ABSORBED BY AI + SKILL 冗長さ・学習コストはAIとSKILLが吸収する ボイラープレートは AI、学習コストは SKILL に埋め込める。 REVIEWER AGENTS 構造から外れた実装を自動検知 レビュワーエージェントが、一方向フローからの逸脱を即座に指摘する。 TEAM REPRODUCIBILITY 構造の明確さ = SKILL化のしやすさ 迷いポイントが少ないからこそ、ルール化・共有が機能する。

Slide 20

Slide 20 text

SECTION 05 まとめ

Slide 21

Slide 21 text

まとめ 21 BLOC・AI・SKILL AIが書く時代、 Flutter Bloc の ガードレール は武器になる。 01 / BLOC Flutter Bloc は 書き方のガードレールになる Event / State / Bloc + レイヤー分離で、実装の自 由度を構造的に絞る。 02 / AI AI が書いても 同じ形に収まる 誤用が物理的に起きず、雛形は一発で決まる。レ ビューもパターンマッチで済む。 03 / SKILL 冗長さは AI と SKILL が吸収する ボイラープレートは AI、学習コストは SKILL に埋 め込める。冗長さは AI 時代の差にならない。

Slide 22

Slide 22 text

ご清聴ありがとうございました。