こんにちは。LIFULL でネイティブアプリのスペシャリストをしている菊地です。
今回は LIFULL HOME'S アプリにおけるプッシュ通知の役割やアーキテクチャの変遷についてご紹介させていただきます。
一般的にスマートフォンアプリにとってプッシュ通知というのはユーザーとのコミュニケーションのために重要な役割を持っています。
- SNS などでコメントやメッセージが来た際にリアルタイムに気付くための通知
- ゲームやマンガアプリなどで、時間によって回復するライフなどが回復したことを知らせる通知
- サービス内における重要な情報に気付いてもらうための通知
- EC やオークションアプリなどで気になる商品の値段が下がったり、高値がついた場合にお知らせする通知
など様々なシーン、目的で使われています。
LIFULL HOME'S アプリにおけるプッシュ通知とは
LIFULL HOME'S アプリでは、どのようなシーン、目的で使っているかというと
- 住まい探しをしているが条件はほぼ決まっており物件が出てくるのを待っているユーザーに対して、最新の情報を提供する
- 気になっている物件について掲載が終了してしまって見れなくならないように期限をお知らせすることで見逃さないようにする
- サービスからユーザーに対して重要な内容を告知する
- ある行動をした際に次のステップにつなげてもらうための通知
- 一定期間アプリを利用していないユーザーに対して、アプリに戻ってきてもらうための通知
などがあります。
その中でも今回は1 の新着物件通知と 2 の掲載期限通知と呼ばれる「ユーザーに対して有益な情報を提供」するための通知をご紹介します。
新着物件通知
目的
- ユーザーが自分の探している条件で毎回アプリを立ち上げて探す手間を省く
- 探している条件で新しい物件が出てきたタイミングでユーザーのアプリの起動を促す
Android アプリ
配信時間:朝、昼、夜の3つの時間帯で指定可能
配信条件:アプリ内で保存した検索条件がある場合はその中から新着物件を。保存した検索条件がなければ前回検索条件から新着物件を検索して通知する
※ Android では保存した検索条件もしくは前回検索条件のどちらか一つの条件で送る仕様
iOS アプリ
配信時間:夜のみ
配信条件:保存した検索条件で「通知を受け取る」にチェックを入れたものの新着物件を検索して通知する
※ iOS では複数の保存した検索条件をまとめて送る仕様
掲載期限通知
目的
- ユーザーがお気に入りに登録している物件の掲載がいつの間にか切れてしまい問合せを失ってしまうという機会損失を減らす
- 問合せの機会損失を減らしつつ、ユーザーがアプリを起動するきっかけを作る
配信時間:夕方
配信条件:お気に入りに登録している物件の掲載期限を確認して、期限切れ数日前の物件があれば通知する
※ Android のみ
アーキテクチャの変遷
初期
開発工数の関係で、プッシュ通知ではなくアプリ内で実装を行い、バックグラウンドで定期的に処理を走らせてローカル通知を行なっていました。
ただし、毎回バックグラウンドで処理をして API を呼び出して受け取った結果を通知するため、導入コストは低かった反面、改修する際のコストは高くなっていきました。 具体的には、A/B テストの実施のたびにリリースが必要となることや、通知を送るための条件や内容を変更するたびにリリースが必要となるといったことが挙げられます。
さらに、Android の場合は OS のアップデートにより、バックグラウンド処理に対する制限が厳しくなっていきました。何も対処をしないと
- バックグラウンドで API を呼び出している間にプロセスが終了してしまい通知が行われない
- 通知の対象とならなかったため通知されなかったのか?通知の対象となっていたが通知が行われなかったのか?の判別が困難
- 指定時刻に通知を行いたいのに、ユーザーがアプリを立ち上げた瞬間などに突然通知が行われる
という問題が出てきました。
このままではユーザー体験としておかしくなるため、改修を重ねて行きましたが、継続的に改修をしようとすればするほどサーバーサイドでロジックを持ち自由に A/B テストができる環境を求める声がチーム内で強くなってきました。
そこでプッシュ通知に移行することを検討したのですが、要件として
- 新着物件通知:ユーザー毎の検索条件に合わせた新着物件
- 掲載期限通知:ユーザー毎のお気に入り物件の掲載期限
といったユーザーごとに違う情報を用いて通知を行う必要がありました。
最初に検討した Firebase ではユーザーセグメント単位での通知は簡単に利用することができますが、ユーザー毎に違うデータを元に通知を送るということが難しいため、サーバー側でサードパーティーのプッシュ通知を送る必要が出てきました。
移行期
ローカル通知における課題などを解決するにあたり、プッシュ通知として今後どういうことを実現するか?という要件定義から行って、新たに仕様を作ることになりました。
様々な要件を定義して施策を行ったのですが、わかりやすいものとしては「配信時間帯(朝・昼・夜)の中でもユーザー毎に開封してもらいやすいタイミングに合わせて配信する」というものがあります。
新着物件及び掲載期限通知それぞれで朝・昼・夜(夕方)という配信時間帯の中でも「ユーザーのライフスタイルに合わせてスマートフォンをみる時間にはばらつきがあるため、朝・昼・夜(夕方)ごとに基準となる配信時間を設けて、そこからユーザー毎に時間をずらすことで開封率の向上を狙うということを行いました。
これを実現するためには
- 時間帯別の配信リストを作成する
- 配信時間帯毎に配信リストを処理する
- ユーザー毎に異なる条件を元に検索を行い、通知を送る
という手順を踏む必要がありました。
この時に出来る限りサーバーレスで、かつ今後も継続的に改修がしやすい構成でと考え、Cloud Functions をベースとして Cloud PubSub と組み合わせた構成に移行しました。
アーキテクチャ
メリット
- 処理毎に疎結合となっているため、テストや改修が非常にしやすい
- 今後の改修でアーキテクチャを移行することになっても一部のみ切り替えということが可能になるため、メンテナンス性が非常に高い
- サーバーレスのみで構成しているため、通知配信用のサーバーなどを用意する必要がなく運用の負担が低い
デメリット
- 配信リストの作成、時間帯別の配信処理毎に Cloud Scheduler が存在してしまうため、管理が大変になる
- ユーザー数が増加した場合や処理が複雑になった場合に、Cloud Functions の実行時間の制限に引っかかる恐れがある
- Cloud Firestore の Read / Write の頻度が高く、単位時間あたりの制限に引っかかる恐れがある
- API server に対して、Cloud Functions からのリクエスト制限をかけるのが難しいため、大量のリクエストが同時に発生する恐れがある
現在
移行期のアーキテクチャでも運用はできていたのですが、プッシュ通知をより使いやすくと改修を繰り返していくうちに想定よりも早い段階で、移行期のアーキテクチャのデメリットとしてあげていた「ユーザー数が増加した場合や処理が複雑になった場合に、Cloud Functions の実行時間の制限に引っかかる恐れがある」という懸念が現実の問題となり始めていました。
元々、Cloud Functions の実行時間の制限を回避するために、Cloud Functions -> Cloud Pub/Sub で配信対象ユーザーの抽出を段階的に行なっていましたが、一度に処理できる量の問題や処理の回数が増えてきてしまい途中で失敗するといったことが懸念としてありました。
また、該当部分のロジックは特にスケールする必要もなく Cloud Functions でなくてもよいため、より実行時間の制限が長い Cloud Run での抽出に移行することになりました。
アーキテクチャ
処理の流れとしては
- Cloud Scheduler-> Cloud Run で配信時間帯毎にユーザー抽出を行い、配信時間帯の中でさらにユーザーごとに時間を調整して Cloud Tasks にタスクを追加する
- Cloud Tasks では設定された時刻になるとタスクが実行され、Cloud Functionsを呼び出す
- Cloud Functions は Cloud Firestore にアクセスを行い、通知に必要となるデータの取得や加工を行い、FCM に通知を送る
という流れになります。
メリット
- Cloud Functions から Cloud Run にしたことで、実行時間の制限が緩和された
- Cloud Scheduler から Cloud Tasks にしたことで、管理コストが減少
- エラー発生時の再送処理などを全て Cloud Tasks に任せられるようになった
- API server へのアクセスのスロットリングを Cloud Tasks で簡単に調整できるようになった
デメリット
- Cloud Functions は Typescript、Cloud Runは golangと別の言語で作ってしまったため、開発に学習が必要になった(チームのエンジニアに学習機会を提供するという目的もあったので負債ではない)
処理の流れも、構成も移行期のものよりもだいぶスッキリしたものとなりました。 さらに懸念されていた処理量の増加についても問題なく処理ができるパフォーマンスを出せているため、当分はこの構成でユーザー毎にパーソナライズされた通知を配信していくことになると思います。
最後に
今回は LIFULL HOME'S アプリを支えるプッシュ通知について、実際に行っているプッシュ通知の例とアーキテクチャの変遷をご紹介させていただきました。 ご紹介したものはローカル通知でも実現可能ではありますが、プッシュ通知にすることで、より良い体験を継続的に提供できるようにすることができました。LIFULL HOME'S アプリではサービスの成長に合わせて施策が実行できるようにするためにアーキテクチャの刷新を継続的に行っています。 また、紹介した通知以外にもアプリでは様々な通知を行なっており、Firebase を用いたユーザーセグメントに対する通知や、ユーザーの行動をトリガーとしたリアルタイムな通知なども行なっております。
プッシュ通知は便利な反面、送り過ぎてしまうとユーザーにとって有益なものでなくなってしまう場合もあるため、今後もカスタマイズを続けていきユーザーにとって最適なタイミングで最良の情報を提供できるようにしていきたいと思います。
LIFULLではメンバーを募集しております! カジュアル面談もありますのでご興味ある方は是非ご参加ください! hrmos.co