AI時代だからこそ「Bloc」を採用する価値があるのかもしれない #登壇レポート
2026年5月11日、クラスメソッド主催の connpass のイベント「AI時代のFlutter開発スペシャル by クラスメソッド」に登壇しました。
発表テーマは 「AI時代だからこそ『Bloc』を採用する価値があるのかもしれない」 です。
本記事はその登壇内容をまとめたレポートです。
登壇資料
概要
AI エージェントが実装の主戦力になった今、状態管理・アーキテクチャの選び方も変わるのではないか。
そんな仮説から、書き方の制約が強い Flutter Bloc を AI 時代の選択肢として捉え直す、という内容です。
「Bloc は冗長」とよく言われます。
しかしその冗長さの裏返しである 構造の強制力(ガードレール) が、AI に実装を任せる前提では逆に効いてくる、というのが本登壇の主張です。
先に要点をまとめます。
| 観点 | 主張 |
|---|---|
| BLOC | Flutter Bloc は書き方のガードレールになる。Event / State / Bloc + レイヤー分離で実装の自由度を構造的に絞る |
| AI | AI が書いても同じ形に収まる。誤用が物理的に起きず、雛形は一発で決まり、レビューもパターンマッチで済む |
| SKILL | 冗長さは AI と SKILL が吸収する。ボイラープレートは AI、学習コストは SKILL に埋め込めるため、冗長さは AI 時代の差にならない |
なお、本記事では Cubit、Bloc と Riverpod の優劣比較、各 API の網羅的なリファレンスは扱いません。
登壇内容ダイジェスト
スライドに沿って要点だけ振り返ります。
詳細は上の資料を参照してください。
AI時代の開発について
いまの開発を AI / SKILL / TEAM の 3 視点で整理しました。
- AI — AI エージェントが実装の主戦力になっている
- SKILL — ルール・ワークフローを整備すれば出力のブレが減る
- TEAM — それをチームで共有すれば誰が書いても近い品質になる
ここから次の仮説を立てました。
AI に任せるなら、ガードレールがある方がいい。
自由度が高い設計はブレやすく、構造の制約が効くほど出力は安定する。
書き方の制約が強い Flutter Bloc なら、AI 時代の開発に合うのではないか?
BLoCパターンとは
BLoC は Business Logic Component。
UI からビジネスロジックを切り離し再利用可能なコンポーネントとして扱うデザインパターンで、DartConf 2018(Flutter / AngularDart – Code sharing, better together)で提唱されました。
入出力は Stream / Sink、依存は注入可能でプラットフォーム非依存、という原則を守れば実装は自由です。
分離の価値は テスト・再利用・変更耐性 に集約されます。
Flutter Bloc
パッケージ flutter_bloc を使った実装では、状態変更を Bloc が一手に引き受け ます。

UI は Event を送出するだけ、Bloc が状態変更の唯一点、Data は外部リソース。
実装は Event / State / Bloc の 3 つを定義するだけです(Event は過去形・sealed class、State は loading / success / failure、Bloc は on<Event> にハンドラ登録)。
テストは bloc_test で Arrange-Act-Assert の型にそのまま乗ります。
Flutter Bloc が AI開発で効く理由
ここが本登壇の中心です。
Flutter Bloc は 実装のガードレール になり、AI にとっても扱いやすい。
具体例を 3 つ挙げました。
具体例1 — 一方向フローで誤用が物理的に起きない。
状態の書き換えは Bloc 内の emit() だけ。
UI から state を直接書き換える操作はコンパイルが通りません。
context.read<HogeBloc>().add(HogeFugaPressed()); // これは OK
context.read<HogeBloc>().state = const HogeState(...); // ← compile error
フローから外れた実装は構造を見るだけでわかるので、AI レビューがパターンマッチになります。
具体例2 — 雛形が一発で決まる。
Event 名を 1 つ渡すだけで、Event クラス・Bloc ハンドラ・State 遷移・blocTest が決まった場所に決まった形で生成され、AI の出力が安定します。
具体例3 — テストの組み方が決まる。
レイヤー分離がテスト手法にそのまま対応します。
| レイヤー | テスト手法 | モック対象 |
|---|---|---|
| Data | test() |
API クライアント / DB |
| Bloc | blocTest() |
Repository |
| UI | testWidgets() |
Bloc(MockBloc) |
「隣のレイヤーだけモックすればいい」が自明になり、AI が生成しても安定します。
アプローチ — 構造を SKILL / agent でチームに展開する
この構造は Claude Code の SKILL / agent でチームに展開できます。
サンプルリポジトリ(github.com/abe-tk/github-issues-app-with-bloc)では、次のものを用意しています。
skills/— flutter_bloc の作法・レイヤー分離・bloc_test・plan / impl-and-reviewagents/— architecture / plan / standards / test reviewerrules/— Flutter 共通ルール
冗長さ・学習コストは AI と SKILL が吸収し、レビュワーエージェントが一方向フローからの逸脱を即座に指摘する。
構造が明確であるほど SKILL 化しやすい のがポイントです。
登壇では触れなかった補足
時間の都合でスライドに載せなかった知見を、要点だけ補足します。
命名規則と UI 側の主要 Widget
命名も公式が定めています(Event は BlocSubject + Noun + Verb(過去形)、State は名詞)。
命名すら迷わない こと自体がガードレールで、AI 生成でも命名がブレません。
UI 側で使う主要 Widget は次の通りです。
| Widget | 役割 |
|---|---|
BlocProvider / MultiBlocProvider |
Bloc の生成と DI(自動 close) |
BlocBuilder |
状態変化で UI 再構築(buildWhen で制御可) |
BlocSelector |
状態の一部だけ選択して再構築 |
BlocListener / MultiBlocListener |
副作用処理(ナビゲーション、SnackBar 等) |
BlocConsumer |
Builder + Listener の組み合わせ |
RepositoryProvider |
Repository の DI |
なぜ Cubit ではなく Bloc に絞ったのか
公式は Cubit から始めて必要に応じて Bloc へ移行することを推奨しており、prefer_cubit という lint ルールまで用意されています。
本登壇は「冗長さの裏返しであるガードレール」が主題なので、入力が型として残りトレーサビリティが高く制約の強い Bloc 側を、あえて取り上げました。
パッケージエコシステムと成熟度
flutter_bloc 単体ではなく、周辺パッケージまで公式が整備しています。
| パッケージ | 役割 |
|---|---|
bloc / flutter_bloc |
コア / Flutter 用 Widget 群 |
bloc_test |
テストユーティリティ |
bloc_concurrency |
イベント並行制御(debounce / throttle 等) |
hydrated_bloc |
状態の永続化・復元 |
replay_bloc |
Undo / Redo |
bloc_lint |
公式 lint |
公式 lint まである ことは「正しさをフレームワーク側で守る」という主張の裏付けです。
pub.dev での人気も高く(Riverpod / Provider と並ぶ主要選択肢の一つ)、コミュニティや採用事例も豊富です。エコシステムの成熟度としても、安心して採用してよいレベルだと感じています。
アーキテクチャの実践知見
スライドの「UI ⇄ Bloc ⇄ Data」だけでは見えない、運用で効く原則です。
- DI はウィジェットツリーで行う —
main.dartが composition root。Page が Repository を Bloc に渡す「配線」は厳密には Presentation → Data ですが、公式チュートリアル通りで許容されるトレードオフです。 - UseCase 層は基本不要 — Bloc 自体がビジネスロジック層。横断・共有ロジックや、経験則として「ハンドラ 30 行超」あたりが抽出を考える目安です(公式の規定ではなく実践上の感覚)。この目安は AI に渡すルールにもそのまま使えます。
- Bloc 間通信は Repository の Stream で — 公式は "No bloc should know about any other bloc"。直接依存させず Repository の変更通知を購読して同期します。
Navigator.push で開いた画面は別ルートになり元画面の Bloc を参照できない、というハマりも上記 Stream 方式で解決しました。
この種の定石を SKILL に書いておけば AI も同じ判断をします。
テストの実践知見
verifyは Command にだけ使う — Query の呼び出し回数検証は実装詳細依存になりリファクタに弱い。- 生成コードはテストしない —
freezed/json_serializableの生成物は対象外。「どこをテストしないか」を SKILL で明示するのが AI 時代に効きます。 BlocObserverで全 Bloc を横断監視 — 一方向フローと相性がよく、AI 生成コードのレビュー・デバッグの土台になります。
制約 vs 柔軟性 — Riverpod との思想の違い
優劣ではなく思想の違いとして整理します。
Riverpod は BuildContext 非依存・実行時エラーを構造的に防ぎやすい・AutoDispose といった点で Bloc の弱点を埋めますが、両者は 正しさをどこで担保するか が根本的に違います。
| Bloc | Riverpod | |
|---|---|---|
| ガードレール | フレームワークが強制 | チームの規約で担保 |
| 自由度 | 低い(良くも悪くも) | 高い(良くも悪くも) |
| 向く組織 | 大規模・メンバー流動的 | 小規模・規約を守れるチーム |
AI が書き手に加わると "メンバーが流動的な大規模チーム" に近づく ——だからこそ強制力のある Bloc の価値が相対的に上がる、というのが本登壇の核です。
質疑応答 —「制約がきつくて、逆に困ることはないのか?」
登壇後にいただいた質問です。
その場では緊張でふわっと答えてしまったので、改めて整理します。
まず言葉の補正です。
Bloc は「制約(やりたいことができない)」ではなく「ガードレール(やってはいけないことができない)」の方が実感に近いです。
「他パッケージならこう書けるのに」と感じる場面の多くは、振り返ると アンチパターンを書こうとしていたケース でした。
典型は Bloc 間の直接参照で、できないのは "No bloc should know about any other bloc" のため。
Repository の Stream 経由が遠回りに見えても、それが疎結合を保つ正解であり、ガードレールが効いている証拠です。
機能面でできなくなることは基本的にありません。
レイヤードアーキテクチャに則り、UI イベントから状態更新も DI もできるので「Bloc だから実装できない」はまず起きません。
強いて言えば Riverpod 比で InheritedWidget 由来のスコープ制約があり、ツリー非依存の Riverpod に慣れた人は戸惑うかもしれませんが、慣れの問題だと考えています。
一番伝えたかったこと
Bloc の「冗長さ」は、これまでデメリットとして語られてきました。
しかし AI が実装を担い、SKILL でチームに品質を展開する時代では、冗長さは AI と SKILL が吸収してしまう。
残るのは「構造が出力を安定させる」という強みの方です。
だからこそ、AI 時代に改めて Bloc を選ぶ価値があるのかもしれません。
おわりに
「Bloc は冗長だから採用しづらい」という評価は根強いですが、AI 前提で考え直すと評価軸そのものが変わる、という話をしたつもりです。
登壇の機会をいただきありがとうございました。
サンプルリポジトリは公開しているので、SKILL / agent の構成と合わせて触っていただけると嬉しいです。
お知らせ
クラスメソッド リテールアプリ共創部では、一緒に働くメンバーを募集しています。
Flutter / モバイルアプリ開発に興味のある方はぜひご覧ください。











