ファッションフリマアプリFRILを運営する株式会社Fablicは、この春に新サービス「RIDE」をリリースしました。 RIDEは一部ライブラリを除けばアプリ部分はすべてSwift 2.2で書かれたプロジェクトになっています。またWeb界隈で話題のフレームワークReduxのSwift実装であるReSwiftを用いた新しい設計を採り入れています。 このRIDEを実例として、本トークではSwift時代における開発手法についてお話します。 プロジェクトの構成やアプリの設計思想といったコードの話題はもちろん、CIやテストの進め方などチームで効率的に開発を進めるための工夫についてもお話する予定です。
フルSwiftでバイクフリマアプリRIDEを作って得た学び
僕は緊張でビール我慢しているんですが会場からプシュっていう音が聞こえて落ち着きました。
RIDEを軽く紹介させて頂いて、ほぼSwiftで作っているので構成の話と、Reduxアーキテクチャを採用したので実際のコードを見ながらどのようになっているかお話します。
ファッション向けフリマアプリ、フリルの次に、バイク専門フリマアプリを出しました。
もともとSNSで売買をしていた方がいたのですが、直接みて取引するケースが多く、距離検索で会いにいける範囲で検索して取引をします。
技術的な話
今からObjective-Cだけで書こうと言う方はおられないのではないか。いい加減Swiftで作らないといけないよねというモチベーションでした。昨年プロジェクトが始まって完全にSwiftで書いて良いという機運も高まっていて、なるべくSwiftに寄せる考えで開始。
サーバー側はAndroid版があった。
プロジェクトの特徴は可能な限りSwiftを利用しているのと、アーキテクチャにReduxを採用している。
最近のイケテルプロジェクトの進め方という所でちょっとお話させていただきたいのですが
本番と開発でターゲットを買え別のBundleIDを使っている。
リリース版と開発版を別々にインストールしてそれぞれ試せる環境にしている。社内にはエンタープライズ版を配布してテストしてもらっている。
開発ツールは、正直すごいことはしていない。
開発していたメンバー全員がSwiftで開発したことがなかったのでLintを入れて書き方を統一した。
CircleCIはFastlaneのコマンドを用意しておいて同じテストを度のメンバーでも走るように用意していた。
開発フローも特別なことはしていない
Github Flowに近いと思う。
この辺りはSwiftというわけではなくて皆さんやられている内容かと思う。
ここからは特徴的かと思っている。ターゲットがアプリと別にフレームワーク用のターゲとにも分かれている。
アプリ側の都合をモデル側に混入したくない。
もしモデルに合わせてUI似あわせて切り替えるみたいなことをしたければ、API側のモデルをExtensionで拡張してUIに紐付けるということをしていた。
バイクというデータはstructとそれが持つ定数プロパティのみで作っている。
初期化はJSONから帰ってきて変換した時だけ。
変数プロパティが書き換わることがないのは最初は不便にも感じられるかもしれないが今は便利だと思っている。
お知らせの種類に3種類あり、APIモデルに種類は定義している。しかしどのタブに表示するかはアプリ側の都合であって、モデルの定義はAPIだけで、それをどのタブのIndexに割り当てるかはアプリ側に定義しました。
このようにしてアプリ側の都合を分離することが出来る。TV OS用に別UIで作るときに混ざることもない。
BaseViewControllerみたいなものを作らないように、またUIViewController全部を拡張しなくて良いように、プロトコルを作った。
個人的にはパターンマッチングが好きで複数の値のパターンで条件分岐するときに非常に便利だと思っている。
protocol で必要最低限の機能の実装・共通化が出来るのが良い。
Swiftにして困ったことは。。。
型推論に時間がかかっているようだが機会のために人間が型を指定するのもなぁと思っている。
Swift3対応はライブラリの対応を待たなくては行けないなどはコスト。
Redux
画面間の同期、Segueでプロパティをセットするの、画面遷移の構成が変わった時に辛くないですか、とか。NotificationやKVOで失敗してクラッシュしたり誰がどこから度のタイミングで変更するのか把握するのが大変。サービスが大きくなるほど困ってくる。
そこでRedux。
ご存知の方、、、ちらほら。
Javascriptの世界で生まれたものですね。
データが1方向にぐるぐる回る。
SwiftでRedux実装にどんなものがあるかというとReSwiftというのが有ります。実践でどの程度動いているかはわかりませんが弊社は使いました。
デモ:さまざまなアクションがバンバン発行されています。
値型で定義するのが良い。
Actionの定義
非同期処理も始まりと終わりをActionで表現する
ReducerはActionを受け取って、Actionに応じて状態を更新する。
いいねの同期問題
画面構成
赤く囲った画面が同期の必要な画面。Segueで受け渡すには無理がある。
Reducerは自分に関係するActionだけ拾ってStateを各自更新すれば良い
非同期リクエストの依存関係がややこしい。パラメータちょっと帰るために似たようなリクエストとコールバックを実装するのがちょっとやだ。
これが商品の状態遷移図。
それを、商品の状態は必ず一個に定まると考えてこのように定義します。
Switch文としては大きいが、どれか一つに行き着けばそこでやるべきことは決まる。見方を覚えればそんなに辛くない。
インジケーターの管理も出来ます。
このViewは状態に寄ってどう変わるかがnewState()だけ見れば良くて置いやすくなる。
チームで状態更新の作法が統一されることで、チーム全体でPullRequestのレビューもしやすくなるのではと思うぐらいには作法が統一される。
考え方は単純なのでReduxの開発が止まっても大丈夫そう。ライブラリが止まってもこのまま行けると思っている。
値を持つ人間と変更する人間、責任範囲が明確に分かれて困ることはなかった。
モデリング:状態をEnumで表現するみたいな方法を思いつくまで悩んだりした。
UI更新の差分検知を自分で書かなきゃいけないのは辛いかも。
よく言われる質問は結構決まっている。こんな感じ。
まとめ
Swiftを使ってみて
Reduxを使ってみて
エンジニア募集中です、Reduxの話を聞きにくるだけでもウェルカムです!
感想
— aoyama (@makoto_aoyama) August 19, 2016twitter.com
twitter.com#iosdc #a RIDEはAPI部分を切り出してライブラリ化。APIをエクステンションで拡張する頻度はどれくらいだろう。
— naru (@naruchigi) August 19, 2016
— ダンボー田中@味噌汁への憎しみ (@ktanaka117) August 19, 2016twitter.com
twitter.comRIDEダウンロードして開きながら見てるよ #iosdc #a
— Teruto Yamasaki (@snoozelag) August 19, 2016
— にかいどう あまね (@a2kaido) August 19, 2016twitter.com