カウルのアプリをFlutterでリプレイスしました
SHARES
この記事はnote.comからの転載です。
https://note.com/yamarkz/n/nd9716541d8ad
はじめに
こんにちは!プロダクトチームの山口です!
タイトルにあるように、弊社ハウスマートが提供する売買マンション提案アプリ "カウル" がiOS/Android共にFlutterでフルリプレイスしました! 下記サイトよりダウンロードしてみてください。
本記事では、Flutterを採用したカウルの技術的背景の話を紹介していきます。Flutterに少しでも興味がある方、もしくは将来的にFlutterの採用を検討している方の参考になれれば嬉しいです。 技術周辺の話が中心になりますが、コーディングのtipsなどはなく、振り返りの開発後記の様な内容なので、1つの読み物として読んでみてください。
目次
技術的な意思決定とFlutter
先に述べた通り、カウルのアプリは先日iOS/Android共にFlutterをベースとしたアプリケーションに生まれ変わりました! ここでは、なぜFlutterを利用したのか? なぜリプレイスするという意思決定に至ったのか? について、その経緯をご紹介したいと思います。
今回、カウルのアプリケーションを刷新するにあたって、 **「Flutterを使ってリプレイスする」 ** という意思決定に至った根拠は3つありました。
上から順にみていきます。
スタートアップ特有の技術負債
↑昔は月額課金モデルでのPMF検証を行なっていた
カウルのサービスインは2015年のことで、かれこれ4年弱の時間が経過しています。その間、サービス自体は何度かピボットを経て今の形に着地しているのですが、過去のピボットの影響もあってか、プロダクト上にはいわゆる技術負債と呼ばれるものが少なからず存在していました 。 具体的には、使われていない機能が混在していたり。多数の人の手が加えられたことで一貫性に乏しく、継ぎ接ぎの様なUI構造になってしまっている。などです。 これらはスタートアップという環境(事業のピボット、時間的な制約、人の入れ替えなど)を前提に考慮する限り、許容できる範囲ではあったのですが、今後の機能追加と改修の目処を考えると、どうしてもそのスピードを妨げる要因になることは明確で、何処かのタイミングで改善する目処をつけたいと考えていました。
生産性の向上という狙い 負債の改善でスピードを得たいというのが先の話ですが、これは言い換えると生産性高く成果を出し、成長を加速させたい ということです。 カウルのサービスはiOSとAndroidで提供しているのですが、どちらとも同じUI、同じ機能で価値を提供しています。 となると、普段の開発ではiOSに実装した機能をそのまま変わらずAndroidに実装するという形になります(当たり前の話ですが...)。 チームとしては、同じ機能を各プラットフォームに提供するために、類似コードを実装するというのは時間コスト的に見て勿体無いなということを感じていました。この不毛にも感じるものを解消するための候補に上がったのが、クロスプラットフォームです。検討が始まった頃に丁度Flutterの1系がリリースされ、既に日本でもいくつかプロダクションで採用され始めてきており、またその前評判も悪くなかったため、Flutterが候補に挙がりました。 ちなみに、この時ReactNativeやSwift / Kotlinでまるっと作り変えるという話も候補に挙がっています。
投資に見合ったリターンとリスク リプレイスするという話が出たとはいえ、ハウスマートはまだまだ成長を必要とするスタートアップ企業です。やりたいから!良さそうだから!といったハートドリブンな意思決定で進められるはずもなく、投資に見合うリターン(期待値)があるのか?という検討を行いました。 ちなみに、僕は時にはハートドリブンな意思決定をするのも好きです。 検討の結論としては、"投下する時間の範囲においてはリターンに見合う " という結論に至りました。 その理由としては、この厳密な検討を行なった6月頃の時点で、将来的な機能追加や他サービスとの連携が高い確度で導入候補として挙がっており、それらをリプレイス後に実装した場合と、リプレイスしない場合とで比較すると、最終的な時間コスト的にはその採算が取れるだろうという見立てがついたからです。
ただし、時間的な制約が設けられ、おおよそ2ヶ月以内(8週前後)であれば良いということになりました。ここでの意思決定をとある言葉で表現すると、後の3巡を買いに行く といった感じでしょうか。一度既存の開発をストップし、2ヶ月足踏みしたとしても最終的なリターンが大きい方を取りに行く意思決定をしました。
また、サービスの開発運用のリスクとしてFlutterの技術的優位性が低下すること で扱える人が減り、プロダクトのメンテナンス性が下がるリスクも考慮しましたが、後に紹介する技術検証の際に、ネイティブ開発者であればキャッチアップにさほど苦労しないということと、Flutterの開発を主導しているGoogleの本気度がわかったため問題ないという結論に至りました。
ここまでの話を整理すると、
その結果、
Flutterを使ってリプレイスするという意思決定に至った。
という流れです。
決して"やってみたいから、流行り始めているから"といった安直な考えで決めた訳ではなく、明確な背景と事実、前提条件、狙いと期待があった上での技術的な意思決定でした 。
検証とキャッチアップ、9週でのリリース
技術検証 いきなり、えいやッで始めるのは何かしら事故った際に、後戻りで時間的な機会損失を産むことにもなりかねないため、事前に技術検証を挟んでいます。ハウスマートでは副業を推奨しており、エキスパートなエンジニアの方に副業としてFlutterの実用可能性検証をお願いしていました。
↑検証完了時の謝辞
ここで検証していたのは、CI/CDの部分とAdjustやKeenなどのアプリに組み込むサードパーティツールの導入可用性の部分です。 これらは検証の結果、Flutterでも十分利用可能だという結論に至りました。
**1週のキャッチアップ ** ここからが実際の開発の話になるのですが、本開発に進む前に1週間キャッチアップを行なっています。キャッチアップで取り組んだこととしては、アーキテクチャの検証、API処理の雛形作成、Flutter基本哲学の理解、主要な機能検証、事前検証内容の把握などです。 1週間という短い期間の中でも、腰を据えて必要な知識とその理解を深められたことで、後の開発のスタートをスムーズに進めることができました。 この辺りの話はこちらの記事で紹介しています。
↑実際に検証で作成されたFlutter App
9週の開発
↑プロジェクト進行の全体感
全体の開発自体は9週で終えることができました。その内訳としては準備に1週、実装に4週、リファクタリングを含む修正に2週、リリース対応とテストに2週といった感じです。 当初の見立てでは8週でやりきる予定だったのですが、途中修正の幅が大きくなったのでプランニングで修正し、1週伸ばしてのリリースとなりました。
進める中でのよかった話として、初期の段階で大枠の構成を固めてしまうことと、懸念点を早めに解消すること を意識して進められたのがよかったです。 新規開発という不確定要素が多い中で複数人で進める場合、メンバーの認識に差異があると、その確認作業で時間を消費してしまうことがあります。この時間消費は非常に勿体無いので、なるべく関わる人を最小にして、阿吽の呼吸で開発するのが鉄則だったりするのですが、それにプラスしてスコープを切ること とスタンスを取ること も重要です。 今回のFlutter化では、やる/やらを初めの内に決め切る(スコープを切る)のと、どの構成でどこに何を実装するかの大枠だけを先に定義(スタンスを取る)し、初動の開発で方向性がブレないように進めることを意識してました。結果として、迷いも少なくスムーズに進められたなと思っています。 また、Flutterはまだ新興技術で不確定な要素も多かったので、「懸念点を調査して対応方針を決めておく」ということを行なっていたのですが、そういった将来の実装に影響を及ぼしそうな要点はなるべく先に解決しておくと影響範囲が局所化されるので良いなと思いました。
この辺りの話は既に先人の方々が "俺が考える最強の新規開発" といった内容で類似のノウハウを共有していたりすると思うのですが、実際に身を以て体験しないと自分は正直わからんと思っていたので、今回でその実情を経験できてよかったです。
Flutterの技術小話
ここまででどういった背景や狙いがあったのか、どの様に進めて来たのかという話をしてきました。次に技術小話 として、開発の過程で決めたことや採用したこと、取り組んだことの技術的な話をいくつかピックアップして紹介します。
アーキテクチャ
アプリ全体のアーキテクチャにはBLoC Patternを採用しました。 BLoC Patternを採用した理由は、ドキュメントや解説記事が豊富でキャッチアップが容易だと感じたからです。詳細な内容は下記のリンクに譲りますが、結果採用して良かったと思っています。 世間的にはBLoC Patternはキャッチアップのコストが大きいなどと言われていますが、先の理由の通り何の事は無く、カウルのアプリは見通しの良いシンプルな構成になり、非常にスピーディーな開発が行えました。 ちなみに、実コード上では最終的に26個のBLoCクラスが作られました。
パッケージ
パッケージは標準のものを中心にいくつか利用しました。 Flutterはメジャーバージョンが1系でありながら、主要なパッケージは揃っているなという印象です。ただ、どうしても足らない部分がいくつかあったり。また、従来には存在するがFlutterにはまだないといった機能も存在しました。そういった課題は影響範囲が小さくなることを意識して、自分たちで既存パッケージに手を加えたり、自前でパッケージを作成して対応することで解決しました。以下、いくつか主要な解決話を紹介します。
WebView カウルはフルネイティブではなく、一部WebViewを利用したハイブリット型でサービスを提供しています。主要なページ(物件詳細)がWebViewを利用していることもあり、FlutterでのWebViewの機能周りは検証段階から注視していました。プロダクションの実装では公式のWebViewパッケージを採用しているのですが、残念ながらこちらにはiOSと一部AndroidにあるWebページのスワイプによるバック機能が未対応となっていました。 機能未対応で進める方向も考えましたが、WebViewは物件情報閲覧というサービスとしての主要な機能を提供する画面でもあり、さらにiOSユーザーにとってはヒストリーバックは非常に馴染みのある操作体験でもあったため、その体験を実現すべく自分たちでパッケージに手を加えて拡張し、この機能を追加しました。
**ログ収集 ** カウルのアプリでは多くのユーザーログデータの収集が行われており、集まったデータを改善施策に活かしています。アプリ内に仕込んだログのトラッカーとそのトラックデータをいい感じに各種SDKに流すためのパッケージとして自作のパッケージが作られました。 このlog_collectorというパッケージはCookpad社がOSSとして公開しているpureeと呼ばれるライブラリにインスパイヤされており、Flutterで動くようにDart言語に置き換えられ、さらにストリームでハンドリングできる様にしたものです。
**Clickable Text ** FlutterのTextViewでの機能がいくつか不足しており、操作体験を損ねてしまっている状況にありました。具体的には、テキストの部分選択ができないといったところです。最悪なくても良い機能ではありますが、カウルではユーザーがメッセージでの案内をコピー&ペーストして検索するといった体験が発生すると考えると必要だよね。という結論に至り、機能拡張するパッケージが作られました。 この辺りの話は以下の記事リンクで三宅さんが紹介しています。
開発スタンス、なるべくシンプルに 最後に開発スタンスについてなのですが、今回はなるべくシンプル(単純)にすることを意識していました。特殊なことはせず、なるべく公式で言われていることを愚直に教科書的に作るといった感じです。
なぜそうしたかというと、今後の変更可用性の範囲を大きく保つためです。FlutterやDartは現在活発に開発が進められているソフトウェアで、今後変更が多く加わってくるのは自明であり、それらに対応しやすくしておきたかったです。(最近もdevでextensionが追加されてます) また、単純であれば新規メンバーのキャッチアップも容易になり、変更も加えやすくなります。この辺りの話は以下のスライドを参考にしてました。
以上が、技術小話でした。
リリースまで進めて
途中iOS13やAndroid 10の環境変化があったり、Flutter固有の問題に遭遇したりと予想通り一筋縄では行かなかったのですが、その都度打開案を探って妥当な解を見つけて、リリースまで進めることができました。 他のFlutterを採用している方も言っていますが、今のところ9割方iOS/Androidのコードを共通化することができており、自分たちの希望していた状況は実現できました😄 また、メインの開発を進めながら並行してブログの執筆やパッケージの開発、公式プラグインへの改善PRなど、プラスαの活動も行えて非常に充実した開発でした。
最後に
Flutterでアプリをリリースするに至るまでの話を紹介してきました。 日本でも最近いくつかFlutter製のアプリがリリースされてきており、Flutterがメジャーになりつつあるなと感じています。このリプレイスを契機に今後もさらにユーザーに価値を提供していくべく、開発に取り組んでいきたいと思っています! そして今回、一緒に開発を進めた三宅さん(@ryo_ryoo_ryooo)には個人的に多大なサポートをいただいており、三宅さんがいなければにっちもさっちも行かなかったと思います。ありがとうございました