Yosuke Ishikawa
メルカリで働くiOSエンジニアです。APIKitというSwiftの言語機能を活かしたネットワークライブラリの開発者でもあります。最近は川遊びに夢中になっています。
Protocol-Oriented ProgrammingはWWDC 2015で紹介された新しいプログラミングのコンセプトです。この講演では、Protocol-Oriented Programmingがなぜネットワーキングに適しているのか、また、型安全性やコードのシンプルさにどのように貢献するのか説明します。実際のアプリケーション開発で使えるような実例や、RxSwiftと組み合わせた発展的な実例についても紹介します。
Here's the demo code from my presentation at #tryswiftconf : https://t.co/1R0PH9613u
— ishkawa (@_ishkawa) March 3, 2016


ネットワーキングにおけるPOP
NSURLSessionをプロトコルでラップする
コールサイトのコードをシンプルに、レスポンスをタイプセーフに

右の形にラップします。右の図ではSessionの中に5ステップが入ります。リクエストをプロトコルにすることでレスポンスがリクエストに紐づく。

指で刺した部分がポイント
例を示します。イシュー作成とリポジトリ検索。

リクエストの方さえ指定すればレスポンスの方が自動的に決定し、型安全にレスポンスが取得できるようになる。
何故プロトコルを使うことがこの設計に適しているのでしょう。
ひとつ目の理由は、リクエストとレスポンスを紐付けられるからです。

指の2箇所で紐付けられています。

ひとつ目の指:リクエストの方の中にResponseという名前の型が存在します。プロトコル上でリクエストとレスポンスのひも付けが可能に。
ふたつ目の指:レスポンスがリクエストによって変わります
SessionのSendRequestのところで利用されます。

ResponseFromObjectが利用されているので、Resultがリクエストごとに違う方を返します。
この結果が、リクエストに応じてレスポンスの型が変わるということです。
ふたつ目の理由

デフォルト実装をフレキシブルに実装できる

GithubRequestプロトコルを提供している。GithubのベースURLはいつも同じなのでデフォルト値を設定している。デフォルト実装で準拠する型の実装ハードルも下がる。
リポジトリ検索の例。arrayにダウンキャストしてRepositoryの型にインスタンス化する。

これをリクエストごとにこれを実装するのは大変。Responseにデフォルト実装を与える

Decodable の decode を通してオブジェクトを取り出します。
プロトコルに準拠していればdecodeをよべる。型制約つきExtensionを使う。

デフォルト実装を提供できました。

ここまでで、一つ一つのリクエストの定義はこのコードのようになります。これだけ。
WebAPIのドキュメントと同じ情報量。プロトコルのフレキシブルなデフォルト実装のおかげでシンプルに出来た。
なぜプロトコルだったか振り返りましょう

- 型安全にできる
- フレキシブルなデフォルト実装
設計についてだけ述べましたが実装した物があります。

APIKitはNSURLSession、Himotokiはdecode
Topic2

ページングなどの制約をプロトコルで表す。

リポジトリ検索URL

ページングパラメータが page=1 と付いています

ページ情報を持ち、ページ指定をするメソッドを用意。typealias では PaginationResponseTypeに準拠することを宣言。

incomplete_requests true なら次のページが有る。それと結果の配列。
これをプロトコルで表します

ここまででページネーションとレスポンスを表せた。これを使ってページネーションクライアントを実装する。

3行目initで初期化段階で基準ページのリクエストを受け取る。
はじめにbaseRequestから1ページ目のリクエストを作成

普通と思うかもしれませんが、重要なのは、プロトコルで定義したインターフェースしか利用していないということ。
汎用的であらゆるページネーションタイプのクライアントになれます。
振り返り

リクエストタイプはもともとなんでも送れたら、ページネーションのプロトコルを定義した結果、ページネーション用のクライアントが出来た。より具体的な定義が可能になった。
Topic3 イベントの抽象化

メソッド呼び出しを入力としてリクエストを行い出力コールバックを実行していた。
RXではこの入出力をストリームとして扱う

ViewControllerからはリフレッシュや次のページのタイミングを送る。Paginationは次のページが有るかなどを返す。
インターフェースを見てみます。

ページネーションクライアントとの違いは、メソッド入力で呼び出しを行っていたが、今度はリフレッシュトリガーとネクストページトリガーというストリームのトリガーになって、またストリームが返ってくるようになっています。エレメントは、ちょっと複雑ですが、”リクエストのレスポンスに基づいたエレメントの型”になる。

Swiftの検索結果を表示します。読み込み中はインジケータが回ります。

ViewModelを作る

ViewModelを特殊化させるのはサーチリポジトリ

次のページを読み込む

UIをViewModelにつなげました。
ViewModelからのデータをUIにつなぎましょう
ローディングのストリームをインジケータにつなぐ

データをテーブルビューにバインド、Cellに表示。型が決まってるから型推論されますね。

バグがなければ動くはずです

👏
PagenationのVeiwModelはリクエストやUIは変わるが、一般化されたPagenationViewModelを使いまわせる。
ページネーションの実装のためにしたことは

まとめ

SendRequestはSendRequestしたあとからProtocolExtensionで型を書き換えられる可能性はないか。
あまり複雑に絡まる設計はしていなくて、意図していない上書きがあるような状況には遭遇していないです。あったら共有してほしい。
スキルがバラバラなチームなので誰が何処を触るかわからない
なるほど。それは基盤を整える人の責任でも有りますね。
今のライブコーディングはハンズオンでやってほしいレベル #tryswiftconf
— mego (@mego_) March 3, 2016
分かった気になれる、触ってみたくなる、そんな組み立てがとっても素敵なスピーチでした。楽しかった。 #tryswiftconf
— 熊谷 友宏 (@es_kumagai) March 3, 2016
viewDidLoadでのbindingだけで実装してしまえてすごい #tryswiftconf
— ほんとは超いそがし松 (@himara2) March 3, 2016
「Protocol-Oriented Programming in Networking リアクティブプログラミングをライブコーディングでお届けします! #tryswiftconf」をトゥギャりました。 https://t.co/zh8lgWWKoC
— トゥギャッター開発まとめ (@tg__dev) March 3, 2016
気に入った記事は はてなブックマーク
はてなブックマークアプリiOS開発チームから来ました! はてなブックマークにはSwift特集があります! 良い記事を見逃さないように、ご利用ください! http://b.hatena.ne.jp/hotentry/it/Swift
そして良いまとめ記事があったらはてなブックマークでブックマークしましょう! try! Swift の記事で盛り上がると嬉しいです!
