【DI】依存の書き換えハンズオン
#ハンズオン
事前準備
Flutterの開発環境の構築
エディター : 作成者はVSCode想定
パッケージ管理ツール : fvm
エミュレータ想定 : iOS
※ Androidの場合、Firebaseの設定ファイルを追加する必要があり。
以下mainブランチのアプリが動かすことができる。
https://github.com/beeeyan/flutter_app_sample/tree/feature/di_question
※ 強制アップデートなどのサンプルも一緒くたになっているリポジトリです。
目標
DIとは何かハンズオンの中で理解を深める。
「依存を変える」が何を指しているか理解する。
DIとは
→ Dependency Injection
DIとは、プログラミングにおけるデザインパターン(設計思想)の一種で、オブジェクトを成立させるために必要となるコードを実行時に注入(Inject)してゆくという概念のことである。
https://www.weblio.jp/content/Di?edc=BINIT
DIにおいては、オブジェクトが他のオブジェクトを利用するためのコードを初めから結合させるのではなく、オブジェクトの実行時に呼び出すようにしている。
このとき、オブジェクト間の結合が「依存性(Dependency)」と呼ばれる。オブジェクト成立のための情報を外部に分離させておくことによって、開発効率やソフトウェアの開発サイクルを向上させることができるとされる。
課題
dioパッケージ( https://pub.dev/packages/dio )の依存をhttpパッケージ( https://pub.dev/packages/http )の依存に変えてください。
「dioパッケージが使えなくなって、httpパッケージに書き換えなければならない」みたいなシナリオです。
※「書き換える」ではなく「依存を変える」です。
※ 30分くらいを想定しているため「Get通信」のみが対象のイメージで作りました。
https://gyazo.com/6c7285fee5dc93f5221a831d996c0cfd
利用させてもらっているAPI
https://pokeapi.co/
API呼び出して、ポケモンの名前が表示できたらクリアです。
条件
api_client.dartを書き換えない(編集しない)でください。
新しいファイルを作成してapi_client_http.dartのような新たなクライアントを実装してください。
「依存を変える」→ 新しいクライアントを作成・依存を注入している部分を書き換えるイメージ。
httpに対するExceptionについてはchatchしなくてもOKです
※できるとより良いですが、回答では想定はしていません。
回答ではApiException・SocketException・FormatException・Exceptionをchatchしています。
beeeyan.iconがやってみた限りの情報
編集したのは「ファイルを新規作成 + 既存ファイル一つ編集のみ」でした。
帳尻を合わせるために型変換を一回やりました。
【DI】依存の書き換えハンズオン_ヒント・スモールステップ
※ ヒント全て同じページに書いているのでご注意
しばらく考えて何を言っているかわからない人は「3」をみてください。
1)パッケージの追加
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528c911c3b4c3000054283d
2)ファイル作成場所
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528c991c3b4c30000542857
3)新しいクライアントの作成方法(方針のみ)
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528c9e9c3b4c3000054285c
4)httpパッケージの使い方
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528cae2c3b4c30000542870
5)型変換した場所
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528cbcac3b4c3000054287c
6)BaseResponseDataに変換するメソッド
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528cc09c3b4c30000542886
7)ApiClientHttpクラスの全容
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528cc4bc3b4c300005428a1
8)依存注入している部分
【DI】依存の書き換えハンズオン_ヒント・スモールステップ#6528cc81c3b4c300005428cc
Flutter初学者用補足
パッケージの追加
「pubspec.yaml」というファイルの「dependencies」部分に追加したいパッケージを記載して、保存するとインストールされます。
※ Github上のファイル
https://github.com/beeeyan/flutter_app_sample/blob/main/pubspec.yaml
modelの作成
今回modelは「pokemon」というものが存在します
※ Github上のファイル
https://github.com/beeeyan/flutter_app_sample/blob/main/lib/feature/pokemon/models/pokemon.dart
※ Freeezedという自動生成のライブラリを利用していて、もし自動生成する場合は以下のコマンドを実行します。
fvm flutter pub run build_runner build --delete-conflicting-outputs
Map<String, dynamic> 型のデータをmodelに格納することができます。
プログラムに既に存在するもの
return Pokemon.fromJson(data.main);
riverpod (provider)とは?
https://riverpod.dev/ja/
リアクティブ・キャッシングとデータバインディングを実現するフレームワーク
今回の文脈では「DIの機能 +α状態管理」と説明させてもらいたい。
純粋な「DI」を実現するパッケージではないが、DIもできる(DIだけであれば「Provider」を使えば十分)としてもらいたい。
回答(ネタバレ)
プルリクとして差分で回答を書いてます。
https://github.com/beeeyan/flutter_app_sample/pull/2
最終的まとめの話(時間があれば)
https://gyazo.com/c2897a499a697f6bd7261e689e480632
出典
modelが変わった。
ビジネスロジックが変わった
データベースが変わった。
パッケージが変わった。
Clean Architecture サイバーエージェント資料
https://note.com/cyberz_cto/n/n26f535d6c575
beeeyan.iconの言葉でいうと
依存関係を整理することで、変更が発生した際に最小限の部分だけ変更するようにしたい。
→そのためにDIという考え方がある。
Dioの元々の参考(プラスアルファの話)
https://github.com/KosukeSaigusa/flutterfire-commons/tree/main/packages/routing_with_riverpod/example
該当ファイル1
該当ファイル2
今回のハンズオンをやってみた感じはdioの依存だったり、Providerの中に入れる型だったりは変えておきたいかも。
前回
「関数・メソッド」について改めて考えてみるLT#64f12314c3b4c30000e7321d