こんにちは、技術部の@k0uhashi👻です。最近の休日の過ごし方はVRChatを朝から次の日の朝までやることです。一瞬で月曜日が来るのでオススメです。業務では主にトクバイiOSアプリの開発をしています。
トクバイAndroid/iOSアプリはおトクな体験をより身近にし、もっと買い物をかしこく、たのしくできるようにアップデートを日々重ねています。 みなさんは、サービス開発を進めるにあたってどんな施策をやっていますか?それってどうやって考えてますか?さらにはどうやって進めていますか?アプリの体験を良くするための施策を考える中で、アプリ内で提供するコンテンツを増やしたり、UIを変えてA/BテストしてよりよいUIに変えるーーー。といった目で見てわかりやすい変化をつけることに目を向けがちですが、それ以外にも体験を良くする方法ってたくさんあるはずです。例えば、次のようなものとか。
- 読み込み待ち時間を短縮
- ネットワークパフォーマンス改善
- ぬるぬる動くUIにする
- UIパフォーマンス改善
- 初回起動時間の短縮
- 初回起動処理のパフォーマンス改善
- etc...
しかし、これらの改善は完全に技術的な要件で、エンジニア以外に改善を提案するのって難しいと思います。 そこで、トクバイのアプリチームではエンジニアから改善を提案し2ヶ月程掛けてアプリを改善していきました。今回はその改善する中でどのように進めたか?どんな結果が出たか?をお話していこうと思います。
エンジニア主導で改善を提案
エンジニアから改善を提案する!といっても何からやればいいかわからない上に、本当にユーザ体験がよくなるかどうかもわかりません。(これ以外にも当てはまりますが。)
- 不安ポイント
- 本当にユーザー体験が良くなるのか?
- 何からやれば良い?
このポイントを元にモバイルエンジニアで集まりアイデア出しを行い、次のような方針で進めることにしました。
- 本当にユーザ体験がよくなるのか?👇
- 必要最小限で、費用対効果が高そうなところを期間を限定してやっていく
- 必要最小限
- モバイルエンジニアだけでできる
- 費用対効果が高そうなところ
- よく見られている画面・機能
- 改善の余地が大きそうな画面
- 必要最小限
- 必要最小限で、費用対効果が高そうなところを期間を限定してやっていく
- 何からやれば良い?👇
- パフォーマンス計測でボトルネックを見つけて費用対効果が高そうなところをやる
方針が決まったところで、ここからはじゃあどんな改善をやっていくか?をアイデア出ししていきます。 いくつかアイデアは出ましたが、現時点ではモバイルエンジニアだけで完結できるUIパフォーマンス改善が一番よさそうという結論に至り、進めることになりました。
どのくらいの工数をかけるか?
進めるとはいったものの、いつやるか?どのくらい工数をかけるか?どこまでやるか? 一般的な自社サービス系の開発チームではロードマップが敷かれていて、それに沿って色々な機能を追加したり改修を進めていて、1スプリントまるまるパフォーマンス改善に使えるのってあまりないかと思います。そのことも踏まえて次のように決めました。
- 工数
- 前提: トクバイのモバイルアプリ開発チームではスクラム開発を採用していて、1スプリント2週間のサイクルで開発している
- 2週間のうち約2日を工数として充てる
- 期間
- 2ヶ月
ここらへんは決めの問題もあるかと思います。他の施策をやりつつ改善がうまい具合に進められるラインがこれくらいかなーというエンジニアの感覚を大事にしました。
どんなスケジュールで改善していく?
段階を分けたほうが進めやすいため、今回は次のとおりに進めました。
- Step1
- 指標の決定
- 対象画面の決定
- パフォーマンス計測方法の確立
- Step2
- 計測とボトルネックの発見
- issueを立てる
- 他社事例から改善案を出し合う
- 計測とボトルネックの発見
- Step3
- インパクトのありそうなものからissueを進め、検証する
- ある程度効果が見込めそうならmasterブランチへmergeする
- Step4
- 最高な体験をユーザへ届ける!
指標の決定
ログを仕込んで計測するのも良いですが、今回は必要最小限でスタートしたいため既存のツールを使って指標を決めます。
iOSアプリの改善の場合
トクバイiOSアプリの改善を例に取り上げると、今回はiOSアプリのパフォーマンス数値を簡単に一覧表示できるFirebase Performance
を使用しました。
- Firebase Performance
- レンダリング
- 遅いレンダリング
- フリーズしたレンダリング
- レンダリング
上記の2つの数値を指標にし、ここを下げていくことを目標に設定しました。
対象画面の決定
- アプリのメイン機能となる画面(もしくはその導線)
- 閲覧数の多い画面
Firebase Performanceを使う場合
遅いレンダリング
、フリーズしたレンダリング
の割合が大きい画面
トクバイアプリではトップページとお店の情報を見ることができる画面が項目に適していたため、この2つを対象に改善していくことにしました。
パフォーマンス計測方法の確立
パフォーマンス計測方法も必要最小限で進められるように既存のツールを使いましょう!
iOSアプリのパフォーマンス計測
iOSアプリのパフォーマンス計測には、XcodeのツールセットにあるInstruments
を使用し、次のプロファイラーを使って計測していきます。
- Instruments
- Time Profiler
システムのCPU上で実行されているプロセスの時間ベースのサンプリング
ができる- CPU負荷の時系列グラフ
- 各スレッドでどのくらい負荷がかかっているか?(時間)
- Core Animation
- アプリケーションのFPSを表示してくれる
- Time Profiler
Tips
Instruments
には他にも循環参照を発見できるLeaks
やバッテリー消耗量を確認できるEnergy Log
といった強力なツールも用意されています
計測とボトルネックの発見
ボトルネックを探すのは簡単です。Instrument
のTime Profiler
を開き、Record
ボタンからアプリのパフォーマンスを計測開始できます。開始したら計測したい画面をぐりぐり動かし、ある程度のところで一時停止します。
この状態だと、System Library
のログが入って少し見辛くなってしまうので、下部のCall Tree
を開きTop function
, Hide System Libraries
のチェックを✅にすると見やすくなります。
あとは下部のリストの最上部を選択し、キーボード入力で➔↓➔↓➔↓➔↓➔↓➔↓➔… 一番最下層までたどり着きましたか?そいつがネックです!👮♀️🚨
issueをたてて、つぶす。
ネック部分を見つけたら、順次issueをたてていきます。
作成したissueはGitHub Projects
を使ってタスク管理し、あとはやりたい人がアサイン付けて地道に潰していきます。
実際に修正した問題
トクバイiOSアプリの一部の画面では、👆のようなスクロールinスクロール(名称不明)なUIを使っています。 このUIを作る時、みなさんはどんな手段を使って実装しますか?
- UICollectionView + UICollectionViewCell in UIScrollView + 複数のUIView
- UICollectionView + UICollectionViewCell in UIScrollView + UIStackView
- UICollectionView + UICollectionViewCell in UICollectionView
- ...等
UIKitには様々なパーツが用意されていて、上記のように様々な手段で作れます。
トクバイiOSアプリでは、このUIを1.
の手段で実装していました。UIScrollView
に対して横方向にaddSubView
,addSubView
,addSubView
... という感じですね。
iOSでどんな形で表現されるかというと、次のようになります。
- 階層イメージ
- UICollectionView
- UICollectionViewCell
- UIScrollView
- UIView
- UIView
- ..
- UIScrollView
- UICollectionViewCell
はい、ここがネックでした。お察しの方も多いと思いますがあえて書かせてください。
仮にここが10枚、15枚、極端ですが100枚あった場合、100回UIViewを生成しaddSubView
します。
むっちゃ重いです。生成したView、使い回せたらいいですね。ということでView(セル)を使い回すことのできるUICollectionViewを使うように修正します。
- 階層イメージ
- UICollectionView
- UICollectionViewCell
- UICollectionView
- UICollectionCell
- UICollectionCell
- ..
- UICollectionView
- UICollectionViewCell
UICollectionViewを使うことによって、どんなにデータがあったとしてもUIの生成時間は表示されている分だけで済むので大幅な速度改善が見込めます!(再利用するときの処理時間はもちろんかかりますが、生成時間に比べるとかなり短くなります。)
実際に、データが7個の場合で速度を測ってみると、約1.7倍ほどパフォーマンスが上がりました 🎉
2ヶ月間改善を進めてみて
地道に改善を重ねた結果・・・
Firebase Performance レンダリング フリーズしたフレームの値 (その画面の読み込みに0.7秒以上かかった人がが0.1%以上いる人の割合) ≒ 画面が一時的にフリーズする人
View名 | 修正前 | 修正後 |
---|---|---|
NavigationController | 9.12% | 7.76% |
MainPageViewController(最下層のViewController) | 10.70% | 8.91% |
TabBarController | 9.71% | 8.18% |
TopViewController | 6.43% | 5.45% |
ShopTopViewController(お店の画面) | 2.32% | 1.72% |
※上記画面一覧は
アプリのメイン機能(&導線)画面
、閲覧数の多い画面
、フリーズしたレンダリングの数値が大きい画面
に該当する画面
画面が一時的にフリーズする人が全体的に約2%
減った!🎉
全体で見れば影響範囲は少ない&元々動作が軽いアプリなので大きく減らすことはできませんでしたが、この約2%
のユーザーには確実に良い体験を届けることができました。
数値的には小さな改善ですが、3,4世代前の機種であるiPhoneSE
やiPhone6
から見てみると圧倒的な差があるのが見てわかります。
修正前 平均20FPS | 修正後 平均50FPS |
---|---|
機種にもよりますが、古い端末ではFPSの平均がなんと約250%も向上してました!やったーー🎉
まとめ
- 技術的な改善の提案はエンジニア以外にするのは難しい
- 技術的な改善はまずは 必要最小限で、費用対効果が高そうなところを期間を限定してやっていく
- 指標とパフォーマンス計測は
既存のツール
を使う - ネックを見つけたらどんどんissueを立て、タスク管理していく
- 最高な体験をユーザへ届ける!
以下、チラシの裏に書いたメモ
冒頭でも述べましたが、アプリの体験をよくする方法っていっぱいあると思います。その中で、施策を考えるのはディレクターの役目、UIはデザイナーの役目、実装はエンジニアの役目、という風に考えるのではなく、一緒に一つのものを作るチームですからそんな垣根を越えて良い具合に連携して、役割ごとの強みを上手く交差させて、良いプロダクトを作れると最高ですね