読者です 読者をやめる 読者になる 読者になる

#iosdc 2016 前夜祭 A-3 フルSwiftでバイクフリマアプリRIDEを作って得た学び

twitter.com

ファッションフリマアプリFRILを運営する株式会社Fablicは、この春に新サービス「RIDE」をリリースしました。 RIDEは一部ライブラリを除けばアプリ部分はすべてSwift 2.2で書かれたプロジェクトになっています。またWeb界隈で話題のフレームワークReduxのSwift実装であるReSwiftを用いた新しい設計を採り入れています。 このRIDEを実例として、本トークではSwift時代における開発手法についてお話します。 プロジェクトの構成やアプリの設計思想といったコードの話題はもちろん、CIやテストの進め方などチームで効率的に開発を進めるための工夫についてもお話する予定です。

iosdc.jp

speakerdeck.com

フルSwiftでバイクフリマアプリRIDEを作って得た学び

f:id:niwatako:20160819184435j:plain

僕は緊張でビール我慢しているんですが会場からプシュっていう音が聞こえて落ち着きました。

f:id:niwatako:20160819184548j:plain

f:id:niwatako:20160819184602j:plain

RIDEを軽く紹介させて頂いて、ほぼSwiftで作っているので構成の話と、Reduxアーキテクチャを採用したので実際のコードを見ながらどのようになっているかお話します。

f:id:niwatako:20160819184638j:plain

f:id:niwatako:20160819184644j:plain

ファッション向けフリマアプリ、フリルの次に、バイク専門フリマアプリを出しました。

もともとSNSで売買をしていた方がいたのですが、直接みて取引するケースが多く、距離検索で会いにいける範囲で検索して取引をします。

f:id:niwatako:20160819184709j:plain

技術的な話

f:id:niwatako:20160819184749j:plain

f:id:niwatako:20160819184755j:plain

今からObjective-Cだけで書こうと言う方はおられないのではないか。いい加減Swiftで作らないといけないよねというモチベーションでした。昨年プロジェクトが始まって完全にSwiftで書いて良いという機運も高まっていて、なるべくSwiftに寄せる考えで開始。

f:id:niwatako:20160819184846j:plain

f:id:niwatako:20160819184858j:plain

サーバー側はAndroid版があった。

プロジェクトの特徴は可能な限りSwiftを利用しているのと、アーキテクチャにReduxを採用している。

最近のイケテルプロジェクトの進め方という所でちょっとお話させていただきたいのですが

f:id:niwatako:20160819184937j:plain

本番と開発でターゲットを買え別のBundleIDを使っている。

リリース版と開発版を別々にインストールしてそれぞれ試せる環境にしている。社内にはエンタープライズ版を配布してテストしてもらっている。

開発ツールは、正直すごいことはしていない。

f:id:niwatako:20160819185045j:plain

開発していたメンバー全員がSwiftで開発したことがなかったのでLintを入れて書き方を統一した。

CircleCIはFastlaneのコマンドを用意しておいて同じテストを度のメンバーでも走るように用意していた。

開発フローも特別なことはしていない

f:id:niwatako:20160819185133j:plain

Github Flowに近いと思う。

この辺りはSwiftというわけではなくて皆さんやられている内容かと思う。

ここからは特徴的かと思っている。ターゲットがアプリと別にフレームワーク用のターゲとにも分かれている。

f:id:niwatako:20160819185216j:plain

アプリ側の都合をモデル側に混入したくない。

f:id:niwatako:20160819185300j:plain

もしモデルに合わせてUI似あわせて切り替えるみたいなことをしたければ、API側のモデルをExtensionで拡張してUIに紐付けるということをしていた。

f:id:niwatako:20160819185350j:plain

バイクというデータはstructとそれが持つ定数プロパティのみで作っている。

初期化はJSONから帰ってきて変換した時だけ。

変数プロパティが書き換わることがないのは最初は不便にも感じられるかもしれないが今は便利だと思っている。

お知らせの種類に3種類あり、APIモデルに種類は定義している。しかしどのタブに表示するかはアプリ側の都合であって、モデルの定義はAPIだけで、それをどのタブのIndexに割り当てるかはアプリ側に定義しました。

f:id:niwatako:20160819185507j:plain

このようにしてアプリ側の都合を分離することが出来る。TV OS用に別UIで作るときに混ざることもない。

BaseViewControllerみたいなものを作らないように、またUIViewController全部を拡張しなくて良いように、プロトコルを作った。

f:id:niwatako:20160819185644j:plain

f:id:niwatako:20160819185732j:plain

個人的にはパターンマッチングが好きで複数の値のパターンで条件分岐するときに非常に便利だと思っている。

protocol で必要最低限の機能の実装・共通化が出来るのが良い。

Swiftにして困ったことは。。。

f:id:niwatako:20160819185832j:plain

型推論に時間がかかっているようだが機会のために人間が型を指定するのもなぁと思っている。

Swift3対応はライブラリの対応を待たなくては行けないなどはコスト。

Redux

f:id:niwatako:20160819185951j:plain

f:id:niwatako:20160819185956j:plain

画面間の同期、Segueでプロパティをセットするの、画面遷移の構成が変わった時に辛くないですか、とか。NotificationやKVOで失敗してクラッシュしたり誰がどこから度のタイミングで変更するのか把握するのが大変。サービスが大きくなるほど困ってくる。

そこでRedux。

ご存知の方、、、ちらほら。

Javascriptの世界で生まれたものですね。

f:id:niwatako:20160819190121j:plain

f:id:niwatako:20160819190127j:plain

データが1方向にぐるぐる回る。

f:id:niwatako:20160819190222j:plain

SwiftでRedux実装にどんなものがあるかというとReSwiftというのが有ります。実践でどの程度動いているかはわかりませんが弊社は使いました。

f:id:niwatako:20160819190327j:plain

デモ:さまざまなアクションがバンバン発行されています。

f:id:niwatako:20160819190359j:plain

値型で定義するのが良い。

f:id:niwatako:20160819190418j:plain

f:id:niwatako:20160819190433j:plain

f:id:niwatako:20160819190457j:plain

Actionの定義

f:id:niwatako:20160819190534j:plain

非同期処理も始まりと終わりをActionで表現する

f:id:niwatako:20160819190549j:plain

ReducerはActionを受け取って、Actionに応じて状態を更新する。

f:id:niwatako:20160819190608j:plain

f:id:niwatako:20160819190631j:plain

f:id:niwatako:20160819190653j:plain

f:id:niwatako:20160819190720j:plain

いいねの同期問題

f:id:niwatako:20160819190724j:plain

f:id:niwatako:20160819190736j:plain

画面構成

f:id:niwatako:20160819190748j:plain

赤く囲った画面が同期の必要な画面。Segueで受け渡すには無理がある。

f:id:niwatako:20160819190803j:plain

f:id:niwatako:20160819190816j:plain

Reducerは自分に関係するActionだけ拾ってStateを各自更新すれば良い

f:id:niwatako:20160819190834j:plain

f:id:niwatako:20160819190913j:plain

非同期リクエストの依存関係がややこしい。パラメータちょっと帰るために似たようなリクエストとコールバックを実装するのがちょっとやだ。

これが商品の状態遷移図。

f:id:niwatako:20160819190956j:plain

それを、商品の状態は必ず一個に定まると考えてこのように定義します。

f:id:niwatako:20160819191009j:plain

f:id:niwatako:20160819191041j:plain

f:id:niwatako:20160819191048j:plain

f:id:niwatako:20160819191054j:plain

Switch文としては大きいが、どれか一つに行き着けばそこでやるべきことは決まる。見方を覚えればそんなに辛くない。

f:id:niwatako:20160819191126j:plain

インジケーターの管理も出来ます。

f:id:niwatako:20160819191143j:plain

f:id:niwatako:20160819191217j:plain

このViewは状態に寄ってどう変わるかがnewState()だけ見れば良くて置いやすくなる。

チームで状態更新の作法が統一されることで、チーム全体でPullRequestのレビューもしやすくなるのではと思うぐらいには作法が統一される。

考え方は単純なのでReduxの開発が止まっても大丈夫そう。ライブラリが止まってもこのまま行けると思っている。

f:id:niwatako:20160819191408j:plain

値を持つ人間と変更する人間、責任範囲が明確に分かれて困ることはなかった。

モデリング:状態をEnumで表現するみたいな方法を思いつくまで悩んだりした。

UI更新の差分検知を自分で書かなきゃいけないのは辛いかも。

よく言われる質問は結構決まっている。こんな感じ。

f:id:niwatako:20160819191514j:plain

まとめ

Swiftを使ってみて

f:id:niwatako:20160819191604j:plain

Reduxを使ってみて

f:id:niwatako:20160819191616j:plain

エンジニア募集中です、Reduxの話を聞きにくるだけでもウェルカムです!

f:id:niwatako:20160819191635j:plain

感想

twitter.com

twitter.com

twitter.com

twitter.com

twitter.com

まとめ

togetter.com