ラクマのiOSエンジニアをしている鶴田です。
ラクマでは、常に新規開発のプロジェクトが走っており、毎月のように新しい機能が導入されています。
ただ、開発と並行して技術的な負債とも向き合ってきました。
最近では、そんな負債も減ってきたため、新規機能の開発へ大きく時間を割くことができています。
その中でも、最近リリースした機能とその裏側について、今回はご紹介したいと思います。
出品時間の削減
「出品時間の削減」は元々ラクマは4枚のみ出品画像を追加できる仕様となっており、1枚ずつアップロードすることが前提のAPI設計となっていて、その仕様がDBのレコードの順番にも依存していました。
そのため、並列アップロードを実現するには、サーバーサイドのAPIとDBの設計まで大きく書き直す必要がありました。なぜなら、サーバー、フロントエンド、アプリと多くのチームを巻き込んで同時に実装を修正する必要があったからです。
ここ数ヶ月は、その重い腰をようやく上げて、チーム一丸となって取り組んできました。
- どうやって削減するのか?
出品時間で一番のネックとなるものは、画像のアップロードでした。
商品が持つ他の情報(タイトル、説明、状態など)はデータとして軽量なため、そこまで問題にならなかったのですが、画像の場合はデータの容量もあり一度の出品で最大10枚までアップロードできるため、画像が多ければ多いほど出品時間が増加するからです。
そこで、現状は画像を1つずつアップロードしていたものを、並列化してアップロードすることで、高速化を実現しようと考えました。
As Is
To Be
- 技術選定に関して
今回は、主にiOSアプリ面からみた並列化実装の話をします。
並列化の実装を行う上で、技術の選択肢は2つありました。
- Combine による並列化
- Concurrency による並列化
今回は Combine の実装方法を取りました。
【理由1】
先ほども述べた通り、並列化実装は兼ねてより(2020年から)想定していましたが、まだ Objective-C が残っており、画像の API Client もその中の1つでした。当時は Concurrency がネイティブでは用意されておらず、Combine がネイティブでサポートされた直後だったこともあり、それを念頭に Combine でリファクタリングを行いました。
そのため、画像の API Client は現在 Combine で実装されており、Concurrency にする場合は書き換える必要があります。
【理由2】
簡易な Concurrency による書き換えをトライしてみましたが、1つ問題がありました。それは、並列実行の進捗状況をどのようにハンドリングするかです。
並列実行中の Concurrency で進捗状況を取る場合、呼び出し元に進捗状況を伝える方法を別途作成する必要があります。クロージャーを渡すことでそれは可能ですが、処理が汚くなってしまい Concurrency のメリットが薄れてしまうため、Concurrency で実装することは適切ではないという結論になりました。
- 実装方法に関して
実装の概要を紹介します。
基本的には前の説明と重複しますが、以下は Combine を使って並列化を実現したものです。具体的なコードを載せても伝わりづらいので、内部の挙動を図にしたものを掲載しています。
Before
After
1枚ずつ行なっていた処理を辞めて並列実行するようになり、処理を Subject で一手に引き受け、最終的な結果を返す仕組みになっています。
並列実装系は Concurrency に置き換えられていく流れだと思っていましたが、処理の途中をハンドリングする等のリアルタイム性がある場合は、Combine の方が適しているなと実感しました。(Coucurrency で良い方法あれば、ぜひご教授願いたいです...)
実装した結果
アップロードの速度は半分以上も早くなりました。
以下は(サイズの大きい)画像10枚を用意し、アップロードを比較したものです。
Before - 単一アップロード
After - 並列アップロード
これは体感でも数秒レベルに匹敵するため、UX を大きく向上できたと思います。また、下書きや編集でも同様の実装が施されています。
実際にアプリからアップロードされる画像は、上記のテストで試したサイズより小さいため、高速になったことをあまり実感しづらいかもしれませんが、ぜひ皆さんには一度試していただきたいです!
また、今回は iOS のみしか紹介していませんが、Android でも同じような実装が施されてます!
技術で挑戦していきたい人は、ぜひラクマでお待ちしています!
楽天グループ株式会社ラクマ開発課では一緒に働く仲間を募集しています