見出し画像

アプリの新機能はどう開発される?

日々新機能が登場するREALITY、今回は「総合ランキング」という機能の開発について、どんな流れで実現に至ったのか?をPM、iOS/Android/Serverエンジニアのみんなで紹介したいと思います。

総合ランキング機能とは

2021-06-08_総合ランキング01

「あのギフトを1番もらった配信者は誰か?」
いつでも知ることができる機能です。
また「自分が一体何をどのくらいもらったのか?」
という自身のランキングのまとめを見ることもできます。

企画の背景

PM(※Product Manager、企画や開発進行の職種)のむくどりんです。
REALITYでは、実に1000種を超えるギフト(視聴者が配信者に送り応援できるアイテム)があります。
ここまで多くの種類があると、ユーザーも様々な楽しみ方をしてくれます。

ユーザーの数だけ、好きなギフトがある。
そこでまずはキャンペーンとして #ギフトレース  というもらったギフトの数を発表する施策を何度か試しました。

画像3

画像4

画像2

何度か検証した所、多くのユーザーが楽しんでくれている。
ただ、自分が何をいくつもらったか?
今何位なのか?をリアルタイムには分からない。

そこで、今回の総合ランキング機能の開発に至りました。

仕様の策定とデザインの検討

企画が決まったら、KPIの策定や、Figma(UIの作成ツール)を使ってデザインの想定と機能仕様、ログの仕様などを作成して、デザイナーやエンジニアと議論します。

画像5

あとは素敵なデザイナーとエンジニアがいい感じにしてくれます!(嘘です。ちゃんと議論したり進行して進めます。)

各プラットフォームの開発

開発は各プラットフォームごとに担当者が設計と開発を行っていきます。
今回はiOS, Android, Serverの担当者の苦労話をまとめてみました。

iOS開発

iOS担当のかむいです。
機能仕様を設計や実装に落とし込むと思わぬ落とし穴があったりするのですが、iOSでは主に以下の問題に出くわしました。

・ミニプレイヤーと自身のランキング情報のデザイン競合
・順位の単位

iOSではミニプレイヤーを表示しながらリスト系の画面を表示すると、リストの最下部がミニプレイヤー(配信画面を最小化して画面下に表示する機能)と被らないように微調整を行っています。

しかし当初この機能の自身のランキング情報はイベント画面と同じく画面下部に固定で表示する形で考えており、その結果ミニプレイヤーと自身のランキング情報が2つ合わせて画面下部に固定することになってしまいました。
そのためデザイナーと協議し、自身のランキング情報は画面の上に置く形となりました。イベント画面も現在は総合ランキングと同じデザインに修正されています。

スクリーンショット 2021-07-01 11.37.53

 もう一つ、実は今回から順位の単位が登場しました。これまで順位の概念があった応援ランキングでも順位に単位はついておらず、無いことでローカライズ(多言語対応)のことを考えずに済むという利点がありました。

しかし今回単位が登場することで、ローカライズのことを考える必要が出てきました。日本語だと単位は「位」ですが、英語圏の単位は単語の一番右をみて、序数の言葉の最後の二文字を取るという特徴があります。

1=  Fir[st]
2= Seco[nd]
3= Thi[rd]
4= Four[th]
5= Fif[th]
以降 Six[th] Seven[th] Eigh[th] Nine[th] Ten[th]

上のルールは10の桁に入っても考え方は同じなのですが、11と12だけ特殊という更にややこしい問題があります。

11 = Eleven[th]
12 = Twelf[th]

これらをアプリ側で自前で制御するのは骨が折れそうに思いますが、きちんとプラットフォーム側でサポートされています。iOSではNumberFormatter.Style.ordinalです。順位の数値とNSNumberFormatterのインスタンスにLocale情報とを合わせることで、英語圏の単位の設定もこちらで制御する必要なく値を返してくれます。

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.ordinal
numberFormatter.locale = locale
return numberFormatter.string(from: NSNumber(value: self)) ?? ""
PM むくどりん のコメント
序数について開発初期にかむいさんから相談を受け、悩んだポイントでしたね。
縦に1,2,3,4と並ぶページはともかく
「自分が一体何をどのくらいもらったのか?」という自身のランキングのまとめページでは「3位→8位→12位」と数字が飛んで並ぶため、序数がつかないと結構わかりづらく、時間をかけてでもお願いしますと頼んだポイントででした。
 (#1 #3 #12 にすれば良いのでは? Rank XXX とするのはどうか?など色々悩みました)
※↓が議論の中で一瞬検討に上がったUI

画像8

Android開発

AndroidエンジニアのSです。
OS共通の苦労話はかむいさんが書いてくれたので、
ここではAndroid特有のトピックをいくつか紹介します。

序数の話
iOSとおなじく順位の単位には一苦労がありました。
iOSではOSレベルでサポートされていますが、以前はAndroidではサポートがありませんでした。
独自に序数をつける実装をするか(大変!)の議論をしましたが、
ここでAndroidでもMessageFormatというAPIが追加されていたことが判明します。
このAPIはAPI level 24を要求されるため、それより古いOSバージョンをサポートしているアプリでは別途独自に序数を返す実装をしなければなりません。
しかしREALITYのmin SDKレベルは24!(高い!)
このAPIを利用することで序数の問題を解決できました。
REALITYのmin SDKレベルの高さの恩恵を最も受けた瞬間でした。

ページングライブラリの話
総合ランキングは1画面で表示するデータが多く、サーバーからデータを少しずつ取得する設計となりました。
この「サーバーからデータを少しずつ取得する」ということをページングと呼びますが、アプリ側でこの機能を実現してくれるPagingというライブラリが存在します。
設計段階でページングのライブラリを選定する際、REALITYのAndroidチームでは、alphaやbetaのライブラリは使用しない方針なので、当時stableではなかったPaging3は使わずPaging2を利用する設計にしました。
しかし、総合ランキングは比較的大きな機能だったので実装期間も長くなったこともあり、実装中にPaging3のアップデートされstableになりました。
Paging3で実装したほうが負債を残さずに済むのは間違いなかったのですが、すでに半分作り終えた状況だったため後ろ髪を引かれながらPaging2で作り切るという選択をしました。現在Paging3にリファクタリング中です。
(Paging3はPaging2に比べて登場するクラスが減り、使いやすくなったなぁという印象を持っています。)

サーバー開発

サーバエンジニアの阿部です。エンジニアブログ書くのは初なんですが、なぜかブログには既に名前が登場済みでした。不思議だなあ🤔

総合ランキングに限らず、REALITY の各種ランキングは主に Redis Sorted Sets を利用して実装されています。スコアをセットするだけで内部的にソートした状態で保持してくれるため、順位を更新するバッチ処理などを回すことなくほぼリアルタイムに順位を取得・更新することができます。便利!

総合ランキングには色々な画面がありますが、基本的には同じデータに対して画面によって処理を変えることで様々な角度からランキングをお届けしています。地域や期間別、ユーザ別など色々なパターンで情報を取ってくる必要がありますが、Redis Sorted Sets は複数のランキングにわたって情報を一括で取ってくることができません。

画像7

この画面どうしよう…(頭を抱える)

総合ランキングでは多くの種類のランキングがあるため、全ランキングにひとつずつ問い合わせをしていくのは厳しいです。どう実現するかチームメンバーとも相談し、今回は Redis と MySQL を併用する方向で実装しました。

視聴者が配信者にギフトを送った際、それによるスコアの変化を Redis に送信して最新の順位を取得し、その情報を MySQL にも投入します。ユーザごとの順位を表示する画面では、MySQL からそのユーザに紐づくレコードだけ取得して順位の高い順にソートしてやれば OK です。やったか!?

……これだけで終われば話は簡単なんですが、スコア獲得時に更新するこの方法だと他の人のスコア獲得による順位の変化に MySQL 側が追従できないため、定期的に Redis から順位を一括で取得して MySQL を更新するバッチ処理を回す必要が出てきます。そして総合ランキングは種類が膨大な上に地域別でランキングデータを持っており、さらにランキング期間も日・週・月と複数あるので、更新がなかなか終わらない!

リリース直後はこの更新処理にかなり時間がかかっていたのですが、改善を続けた結果今では割と速く更新できるようになりました。今後も展開地域や公開中のギフトが増えるほど更新対象のランキングも増えるため、より効率的に処理を行えるよう引き続きチューニングを行っています。展開地域やギフトが一気に増えるようなことがあったりするとランキングの更新が大変そうですね!

リリースとユーザーの反応

開発が完了したら、本当にバグはないか?PMが想定していなかったものがないか?などを確認して、リリースに進みます。(正直に告白すると色々抜け漏れていて、リリース後も修正を相談したりしていました。)

REALITYの機能開発は、基本的にPMと各Platformのエンジニアが1名ずつの3~4名で進めます。リリース後にはメンバーで集まり振り返り。

機能の成果はどうだったのか?を定量や定性でPMが共有、みんなでプロジェクトの進め方などに改善点がないか?を議論し、社員全体に共有して終わります。

一緒に新機能をつくりませんか?

私たちは皆様の新しい価値観、喜びを提供していく仲間を募集しております。興味を持って頂けた方は下記をご参照ください!