こんにちは。ヤフーでAndroid版 Yahoo! MAPを担当しているエンジニアの福野です。
皆様はYahoo! MAPアプリをどのように活用していますか? ヤフーのマップアプリは単に地図を見られるというだけでなくテーママップ、ナビ、雨雲レーダーなど多種多様な機能を備えていますから、人それぞれさまざまな使い方ができます。旅行の行き先を探す、ルートを調べる、クチコミを投稿する…そしてもしかしたら、災害が起きたときにも使われるかもしません。
先の大震災では広い範囲で公共交通機関が止まり、多くの人が自宅まで徒歩の帰宅を余儀なくされました。さらに携帯電話事業者のインターネット通信網もつながりにくいケースがありました。またこのような状況になっても、Yahoo! MAPアプリは使えるのでしょうか?
今回、Android版にオフラインマップのダウンロード機能を実装しました。この記事ではヤフー社内の開発模様を含めてその道のりを紹介させてください。
災害時に何が起こるのか
他の多くのアプリと同じように、Yahoo! MAPもインターネットから地図を取得して表示しています。つまりアプリの機能のほとんどを利用するためにはWi-Fiかデータ通信への接続が必要です。
一般にデータ通信は音声通話と比べて災害時でもつながりやすいことが知られていますが、平成28年に総務省が発行した大規模災害時の非常用通信手段の在り方に関する研究会報告書(外部サイト)には首都直下地震のような大災害が発生した場合に回線の被災状況次第でインターネット接続も難しくなるという想定があります。そうなればアプリの利用も難しくなってしまうでしょう。
あまり考えたくないことですがここは災害の多い日本ですから、止まっている公共交通機関の代わりに慣れない道を徒歩で帰宅しなければならないような事態はまた起こるかもしません。このような事態に備えてヤフーではYahoo! MAPアプリ内に「防災モード」という機能を新設し、災害に備えたさまざまな機能を順次提供していくことになりました。オフラインマップのダウンロード機能はそのうちの第一弾です。
新機能にチャレンジ!
私にとって今回の防災モード実装は企画デザイン担当から実現したい機能の説明を受けるところから始まりました。その後何度かの話し合いを経て、第一弾ではオフラインマップを一度ダウンロードすれば期限切れまでの間はオフラインでも最低限の地図が閲覧できる状態を目指すと決まります。
ところで私は昨年入社したばかりの新人なので昔のことはよく知らないのですが、先程ちょっとヤフって調べたところによればAndroid版 Yahoo! MAPは2010年初回リリースされたそうです。その頃のAndroid最新バージョンは2.3、APIレベルは9。当時はFragmentがなくて画面遷移は全部Activityで実装していたって、あまりにも大昔のようで想像がつきません。
それから12年の間Yahoo! MAPにはさまざまな新機能が実装されてきましたが、「既存のどの画面にもほとんど関わらない」という点で今回の防災モードという新機能は非常に特異でした。
とりあえず技術検証
全くの新機能ですから、そもそも実現可能かわかりません。
そこで上記画像のような最低限の機能とUIをもったテストアプリを作成し動作を検証することから始めてみます。結果は良い感じで、開発用端末を機内モードにしてもダウンロードしたオフラインマップを閲覧することができました。求められた機能を実現できそうです。
また当初オフラインマップでは地図の拡大・縮小・移動などの地図面操作はできないことが想定されていましたが、テストアプリを見る限り地図面操作も案外手間なく実装できそうでした。地図面操作もできるようにしてはどうか? と企画デザイン担当に提案してみたところ快い返事。このような検証を通じて、これから実装すべき機能の形が具体的になっていきます。
既存実装に寄せるか、新世界に踏み出すか
ここまでの作業は全てリモートワークで行われていましたが、珍しいことにここで偶然各地のチームメンバーが出社し現実に顔を合わせる機会がありました。
ちょうど防災モードの実装方針についてコンセンサスを得たかったので、先輩エンジニアをホワイトボードの前に呼びつけ図を書いて設計を説明します。ほとんど出社をしたことがない私にとって新鮮な経験でしたが、とても効果的でもありました。Zoomの画面共有と実際その場にあるホワイトボードでは伝わり方が違うようで、流れるようなスムーズさで話し合いが進みます。
そしてこの話し合いの中で先輩エンジニアから、せっかく完全な新機能なのだからアーキテクチャも従来の方針に囚われないほうが良いんじゃないかと提案されました。
Androidアプリのアーキテクチャとして現在標準的に使われているのは上記画像のようなMVVM(+DataBinding)アーキテクチャですが…
歴史が長いYahoo! MAPアプリでは古いMVPアーキテクチャのコードも各所に残っています。
新規実装であっても従来のコンポーネントを使いまわそうとすればどうしてもMVPに引っ張られてしまうのですが、以下の2つの観点から思い切った判断をしても良いんじゃないか?とのこと。
- 一部肥大化しすぎている既存実装があるので、無理に活用せず見切りをつけてしまいたい
- 今後アプリのリファクタリングを進めていくにあたって、リファレンスになり得るコードが欲しい
私個人としても新しいアーキテクチャを使いたい思いは強く、うっすら内心では考えていたことでした。ぜひその方針で行きたいと返事をします。
既存コードから距離を置く
そういうわけで防災モードではMVVMを採用することとし、さらにはその実現のため思い切って防災モード画面のActivityを既存のものから分けることにしました。
画面遷移のためにいちいちActivityを起動する必要がない現代のAndroidでは、Activityは単一のものとするSingle Activity Architectureが好まれる傾向にあります。分けることは時代に逆行するようですが、それでも分けてしまうことで既存のActivityと密結合していて使わざるを得なくなっていたViewやPresenterに別れを告げ新しい実装を無理なく始めることができました。
このような方法について賛否があるとは思いますが、Activityが分かれることで各機能にわかりやすい「区切り」を作る事ができます。巨大なアプリにおいては無理にActivityを単一にしようとせず、ある程度複数のActivityがある状態を許容することも未だ選択肢として残っているのではないでしょうか。
レビュー負荷を抑えるために
その後の実装は滞りなく進めることができましたが、アプリの品質を守るためにはコードレビューが必要です。ここで問題が発生しました。
- どうしても新規実装が多くなるので、レビューすべきコードの量が増える
- 既存実装に関する知識があまり活用できないので、レビュー自体の負荷が増える
これについては防災モードへの導線となるボタンやダイアログの実装を最後に回すことで、プルリクエスト(以下PR)をできるだけ細かくするようにして対処しました。実装が中途半端な状態で細かくマージされても、その機能自体にアクセスできないので問題にならないという考えです。PRを細かく分けたからといって全体を通してレビューすべきコード量が多いことには変わりないのですが、1回のレビューに取られる時間が少ないことは着手のしやすさにつながります。
ただし機能への導線がないままだとレビュアーにとっても動作確認ができません。そこでレビューを受けるPRとは別のブランチに仮の導線を実装しておいて動作確認にはそちらを使ってもらうように進めました。
良かったこと、悪かったこと
一般にMVVMアーキテクチャには以下のような利点があると言われます。
- 依存関係が減りテストしやすい
- 関心が分離されコードの可読性が上がる
今回思い切ってMVVMを採用しましたが本当にその通りで、実装量が増えたことを補って余りある効果があったと思います。既存コードより大幅に高いカバレッジ率を実現できたことから将来の変更容易性を担保できたと思いますし、可読性についても良い評判が立ちました。防災モードに後続する新規実装や、既存実装の改修でも今回の私の実装を参考にしてMVVMの採用が始まっているようです。
しかしコードレビューでレビュアーに負担をかけたことが反省点として残りました。PRの分割を心がけはしましたが、意味ある単位で分割しないと逆にレビューが難しいだろうと思えば際限なく細かくすることもできず、結局それなりに大きいPRが発行されてしまいました。分割方法について今後改善していきたいです。
おわりに
今回の防災モード第一弾実装では数多くの思い切った取り組みをしました。膨大な既存実装という資産を前にしてそのような道に進むのは勇気が必要でしたが、振り返ってみれば間違いなく良い選択をしたと思います。
Yahoo! MAPアプリの防災モードをぜひご活用ください。お読み頂きありがとうございました。
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました
- 福野 将人
- Yahoo! MAP エンジニア
- Android版 Yahoo! MAPとそのバックエンドを作るかたわら、おおよそ2週間に1度のペースで電子レンジと電気ケトルを並列実行し自宅のブレーカーを落としています。