効率的な運用を実現するWEARコンテンツのモジュール化

ogp

こんにちは、WEARバックエンドエンジニアの三浦です。WEARのバックエンドの開発、保守運用に携わっています。個人ではおよそ2年ぶりのテックブログ執筆となります。
さて、今回はWEAR上のコンテンツを運用チームが自由にカスタマイズできるようモジュール化した話をご紹介します。

目次

モジュール概要

まず最初にWEARのモジュール化はどのようなものか説明します。
今回導入したモジュール化は、WEARのアプリ上の一部コンテンツをUIモジュールとして扱えるようにすることです。1つ目の画像に表示されているシアーシャツ雨の日コーデといったテーマ別のコンテンツ1つ1つがモジュールとなっており、テーマに合わせて絞られたコーディネート画像が表示されます。モジュール右上のすべてを見るを押下するとそのテーマに沿ったコーディネートの一覧画面へ遷移します。それが2つ目の画像になります。モジュールは運用チームが管理ツールから自由に作成できます。

WEARアプリ画面

導入背景

以前ビジネスサイドから、WEARのTOPページのコンテンツを定期的に変更してユーザーに様々な切り口でコーディネートを提案し、効果検証にも活用したいという要望があがりました。しかし、当時は新しいコンテンツを導入する際には、毎回デザイン検討、開発、QAチームによるテストと一連のプロセスを踏む必要があり、かなりの工数がかかりました。そのため、気軽に変更することが難しい状況でした。
そこでTOPページの一部のコンテンツをモジュール化し、大規模な開発をせず自由にコンテンツを変更できる環境を整えようということで今回の施策が動き始めました。

モジュールの設計

要件と課題

ビジネスサイドからの要件は以下のとおりです。この要件をベースに設計を考えていきます。

  • 初回リリース時点ではコーディネートに関するモジュールを作成できること
  • 将来的に動画やフリマ出品アイテムといったコーディネート以外のコンテンツもモジュール化できる汎用的な作りになっていること
  • モジュールは複数表示でき、個別に掲載期間も指定できること
  • モジュールの作成自体は管理ツールから運用チームが自由に作成できること

要件を満たすための設計を検討していく上でいくつかの課題も浮かび上がってきました。

リプレイスとの競合

WEARでは別チームが同時並行でリプレイスを行っており、コーディネートの検索基盤も旧版(Amazon CloudSearch)と新版(Elasticsearch)が同時稼働している状態です。モジュールのすべてを見るのリンクから遷移するコーディネート一覧画面は、開発工数を抑えるため既存の画面をそのまま使用します。こちらは旧版の検索基盤で検索が行われています。一方、TOP画面のモジュールで表示されるコーディネートには、ユーザーが最初に目にする部分であることから、柔軟にロジックを調節できる新版の検索基盤を使用します。

リプレイス前後の検索基盤でインデクシングされている項目に差異があり、リプレイス後の方が検索の絞り込み条件が増えています。ただし、TOP画面と一覧画面で検索結果が変わってしまっては困るので、その差異を考慮しながら検索条件を組み立てる必要があります。

負荷対策

モジュールはTOP画面で表示され、かつモジュールの数に比例してAPIのリクエスト数も増えるので、検索基盤に大きな負荷を掛けてしまう恐れがあります。

これらの要件や課題を踏まえて管理ツール、APIそれぞれの設計をしていきます。

管理ツール

運用チームは、まず管理ツール上のコーディネート検索画面からモジュールに使用したい条件で検索し、検索結果を確認します。ここでの検索には新版の検索基盤を使用しているため、TOP画面のモジュールで表示されるコーディネートになります。検索条件に使用できる条件は、リプレイス前後のパラメータの差分を確認して旧版の検索基盤でも検索可能な条件のみに限定しました。問題なければ同画面に用意しているモジュール作成ボタンからモジュール作成へ進みます。

以下は、上記のフローをシーケンス図にしたものです。

管理ツールシーケンス図

モジュール作成画面では主に以下の値を設定できます。

  • タイトル
  • 掲載開始日時
  • 掲載終了日時
  • 表示優先度:複数のモジュールを表示した際の優先順位
  • コンテンツ種別:コーディネート、動画、etc...
  • 検索パラメータ:モジュールに表示するデータの検索条件
  • ディープリンク:絞り込み条件付きの一覧画面のアプリディープリンク

検索パラメータとディープリンクに関しては、シーケンス図の1.コーディネート検索画面:検索で指定した条件を基にバックエンド側で登録します。画面で指定した条件と各検索基盤で使用するキー名のマッピングをモデル内で保持し、検索パラメータとディープリンクを組み立てていきます。ディープリンクのパラメータに関する資料があまり残っておらず、どのようなキー名が使われているかをアプリ上で実際に試しながら実装したため時間がかかりました。マッピングの実装部分は若干複雑になってしまいましたが、運用チームがリプレイスの環境差分やパラメータ名などシステムの仕様を意識せず、直感的にGUI上で登録できるようになりました。

また、同時に掲載できるモジュールの数には制限を設けることにしました。無制限に作成するとシステム負荷が上がるため、運用チームから作成したいモジュール数をヒアリングし、最大4つに制限しました。

API

モジュールの一覧APIと詳細APIの2つに分けて作成しました。一覧APIで現在日時が掲載期間内のモジュールのIDを全て取得し、詳細APIではそれぞれのモジュールの内容を1件ずつ取得します。

以下は、上記のフローをシーケンス図にしたものです。

アプリ表示シーケンス図

モジュールの内容は全ユーザーに対して同じであるため、負荷対策として詳細APIの内容を一定時間キャッシュする仕組みを導入しました。具体的にはRailsの低レベルキャッシュを使用して、#{controller_path}/#{モジュールのID}をキーにレスポンスのJSONをキャッシュします。キャッシュ有効期間は、検索基盤のインデクシングが更新されるタイミングに合わせて設定しました。同じモジュールの内容を再利用することで、頻繁な検索基盤へのアクセスを回避し、検索基盤への負荷を軽減しました。

coordinate_module = CoordinateModule.find(params[:id])
coordinate_module_json = Rails.cache.fetch("#{controller_path}/#{params[:id]}", expires_in: xx.minutes) do
                          render_to_string json: CoordinateModuleSerializer.serialize(coordinate_module: coordinate_module, coordinates: coordinates_searched_by(coordinate_module))
                         end 

render json: coordinate_module_json

詳細APIのレスポンスは、管理ツールで設定したモジュールの内容+モジュールと一緒に表示するデータの配列のJSONになっています。配列部分はコンテンツ種別で設定した内容によってコーディネートの配列や動画の配列といったように変わってきます。クライアント側はコンテンツ種別を見てどんなデータが返ってくるかを判別します。
これによりコンテンツによって大きくレスポンス形式を変えることなく汎用的に利用できるようになりました。

まとめ

モジュール化を行なったことで、エンジニアを介さず運用チーム側で定期的にTOP画面のコンテンツを更新できるようになりました。また、システム面で汎用的に作成したので他のページでもこの機能を応用できました。現在はフリマページのおすすめの出品アイテムも一部モジュール化されています。

モジュールを複数個出し始めてから、ユーザーのコーディネートの一覧ページへの回遊率が上昇しました。年齢別やTPOに合わせたテーマが人気のようです。

今後は、検証をした結果を活かして、コンテンツの精度の向上やパーソナライズなどもしていきたいです。

さいごに

WEARでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

カテゴリー