沖縄フロントエンドカンファレンス2022で登壇した発表資料です。 https://frontend-conf.okinawa.jp
PickGoというサービスに採用されているフロントエンドフレームワークが時代に合わなくなってきた状況でどのように移行を行なっているかという現在進行系の話をさせていただきました。
レガシーフレームワークからの移行CBcloud 株式会社新垣雄志(あらかき ゆうじ)
View Slide
自己紹介● 新垣 雄志(あらかき ゆうじ)● Twitter: @arakaji● 職歴○ 琉球インタラクティブ株式会社○ 株式会社Payke○ CBcloud株式会社 ← NOW● 現職での役割○ PickGoというサービスのリードエンジニア
COMPANYPROFILEC B c l o u d 株 式 会 社
会社概要 基本情報 © 2016-2019, CBcloud Co., Ltd 2 会社名 英文社名 CBcloud株式会社 CBcloud Co., Ltd. 所在地 東京都千代田区神田練塀町300 住友不動産秋葉原駅前ビル16階 代表 松本 隆一 設立 2013年10月 社員数 160名(業務委託・アルバイト/派遣除く)(2022年10月24日時点) 主要株主 Tokyo Office
会社概要 沿革© 2016-2019, CBcloud Co., Ltd 3 2013年設立 運送会社時代 「PickGo」の原点 「軽town」リリース 本社を神田に移転 3.6億円資金調達(シリーズA) 60億円資金調達(シリーズC) 計80億円調達 沖縄オフィス立ち上げ 大阪オフィス 立ち上げ 初のテレビCM放送 愛知、福岡オフィス 立ち上げ 急成長フェーズを見込む 従業員数(人)
業界情報 物流業界の課題 ラストワンマイル/近距離領域における主な課題 © 2016-2019, CBcloud Co., Ltd 6 1次請運送会社(元請け)を頂点とした階構造となっており、 2次・3次・4次運送会社(下請け)は、一般的に低賃金や過重労働時間などの問題を抱えている 2次請運送会社 2次請運送会社 2次請運送会社 3次請運送会社 4次請運送会社 3次請運送会社 1次請運送会社 多重下請け構造 紙の地図に、その日の運行ルートを手書きするなどアナログな現場作業による不便さが顕在化している アナログ・非効率な業務
業界情報 業界の課題を解決するために 業界の課題を解決するために、以下プロダクトを展開 © 2016-2019, CBcloud Co., Ltd 7 業界課題 多重下請け構造 アナログ 非効率な業務 提供プロダクト 概要/説明頁 荷物を送りたいユーザーと、届けてくれるユーザーを直接つなげるプラットフォーム これまでのアナログな業務を自動化・効率化し、一つのプラットフォームで全ての管理が可能 宅配サービスの配送効率と品質をあげ、簡単に宅配事業を効率化
事業概要 配送プラットフォーム PickGo 荷物を送りたいユーザーと、届けてくれるユーザーを直接つなげるプラットフォーム © 2016-2019, CBcloud Co., Ltd 13
今日話すこと● PickGoというプロダクト立ち上げ時に選択した技術的意思決定が現在の状況に合わなくなった● とあるフロントエンドのフレームワークがその状況に陥ったため、そこからどのように移行していくことに挑戦しているかという話をします。○ どう意思決定したか?○ どのような手順で進めているか?○ ぶつかった課題はどのようなものがあるか?● 話さないこと○ 各フレームワークの技術的な詳細● ちょっとマネジメントよりの話になるかもしれません。
プロダクト立ち上げ当初の技術● PickGoというサービスは2016年に「軽town」という名前でサービスローンチ● 当時の技術スタック○ バックエンドScala○ 荷主が使う配送依頼画面はウェブアプリケーション○ ドライバーがつかうのモバイルアプリ○ ウェブアプリケーションは SPA○ モバイルアプリなネイティブ (Swift, Kotlin)で実装された一部の画面を除き、大半は WebViewでSPAの画面を表示● 今回移行を進めているのはこの時採用したSPAのフレームワーク
会場限定 🤫
その名はAngular.js● 2012年6月にバージョン1.0.0がリリースされたSPAフレームワーク● SPAという概念がで始めた時代に、それ実現するフレームワークとして非常に多くのプロダクトで採用された● ちなみにVue.jsが2014年、Reactは2013年にOSSとして発表された会場限定 🤫
なぜこれが技術負債となるのか?● 2016年9月にアーキテクチャが一新された次期バージョンがリリースされる○ 実装時の推奨言語が変わる○ フレームワークの名称も変更される○ フレームワークの仕様が大幅に変更され、既存バージョンとの互換性はない● 中長期的に見てこのフレームワークでプロダクトを作り続けるのは困難○ バージョンアップ = ほぼ作り直しのため困難○ 現バージョンのままでいることのセキュリティリスク○ エンジニアの採用・維持への悪影響○ 古いフレームワーク故の開発生産性の低さ
当時のお気持ちを察する● 2016年のサービスリリースとフレームワークの次期バージョンの公開はほぼ同時期○ こればかりは不幸○ できるとするとフレームワーク選定時やプロダクト開発中もフレームワークの開発動向を継続的にウォッチしていれば防げたかもしれないが、プロダクト立ち上げ集中している時期にそれができないのは全然わかる● サービス立ち上げ後まだこのサービス自体がどれだけ続くかもわからないのに、ほぼ描き直しが必要になるようなアップグレードやフレームワーク移行の選択はとれなかった。● その後も事業を伸ばすことにフォーカスした開発が継続する
2020年、脱却に向けた活動をスタート- PMFも成功、資金調達に成功、エンジニアの採用も進み、ついに某フレームワークからの脱却に一歩踏み出す- ドライバー向けモバイルアプリで開くWebView、荷主画面のウェブアプリをそれぞれNuxt.jsに移行することを決定- まずドライバー向けモバイルアプリの新機能の画面をNuxt.jsで実装することからTryすることになった
2020年スタートって遅くない?
移行開始が遅れた背景● CBcloudでは複数のプロダクトを展開○ PickGo, PickGo ショッピング、Smaryu トラック、Smaryu ポスト, etc..○ 1~1.5年に一つは新しいプロダクトを爆誕させている○ その分エンジニアの人数がその立ち上げに割いていた● PickGoの技術的負債はフロントエンドだけじゃなく、バックエンドにも○ 当初Scalaで開発していたが、開発生産性やエンジニア採用の難易度を理由に途中からバックエンドに Railsを採用■ 新機能のAPIはRails, 既存APIはバグ修正や仕様変更があるたびに徐々に Railsに移行■ ScalaとRailsの変更稼働状態が続く○ Rails側も大変■ 移行時にAPI仕様を理解してRails wayで書くではなく、 Scalaのコードをポートする形で実装● トランザクションスクリプト的なコード、 ARのバリデーションとか使ってない■ テストがない■ そう、テストがない○ バックエンドの課題解決にも工数が取られなかなかフロントの課題に向き合う余力がなかった
補足: バックエンドの課題の現在の状況- 2022年8月時点でテストコードがほぼゼロの状態から現在はテストカバレッジが74%ほどに- テストコードの充実により、開発速度と安定性は劇的に改善された- ScalaのAPIの移行もある時期に一気に進めて残ったAPIは1割以下になっている- 外部連携が関わるところがテストが難しく現在止まっているが、実装自体は終わっている
パートナーアプリ側の移行PJTがスタート- 新機能の画面をNuxt/TSで開発- 完全に別サイト・別ドメインでリリース。アプリ側で画面によって開くWebViewを切り替えることで一部のNuxt/TS化を実現した。- その後、荷主画面側の機能開発をきっかけに荷主画面もNuxt移行を進めることを決断- このタイミングでフロントエンドエンジニアはドライバー側の開発からは離脱して、荷主側に入ることになる。- パートナーアプリ側の移行PJTはこのあと停滞期間に入る
移行先の技術スタックをNuxt -> Flutterへ変更する- アプリ側の新機能開発要件で、どうしてもネイティブで実装しないといけない要件が出てきた- そのときはKotlin, Swiftで別々に実装- 両方のOSをメンテし続けるの厳しい- 別プロダクトでFlutterを採用していたので、PickGoでもFlutterが使えないか技術検証- いけそう- 両方OS対応をする負荷も減らせるため移行先をNuxtをWebViewで開くではなく、Flutterで実装するという風に方針展開
Flutter化プロジェクト- まず既存の少ないネイティブ画面を完全にFlutterに移植することからスタート- 完了したらベータリリースにユーザー協力してもらいながらバグを潰していく- 本リリースへ- その後はボトムメニューをFlutter毎にFlutterで実装=>QA=>ベータリリース=>本リリースを繰り返す- 移行中も新機能開発が必要な場合はFlutterで実装する- 新機能開発と移行PJTを並行しながら、2022年8月には移行完了- 2021年1月スタートなので 1年8ヶ月ほどかかった
移行後の恩恵- いままでモバイル、フロントエンド、バックエンドのメンバーが連携しながら開発を進める必要があったが、モバイル・バックエンドだけで開発が完結するようになった- Flutterで開発したいというモバイルアプリのエンジニアの採用ができた- 某フレームワークで開発したい人、いない
荷主画面の移行PJT- 荷主側Webアプリの「依頼画面統合」というプロジェクトに重ねる形でNuxt移行をスタート- 2020年10月頃
依頼画面統合PJTとは- PickGoというサービスでは、500kg以下の荷物を軽貨物というフリーランスのドライバーさんに、それ以上の荷物は2t、4t、10tのトラックを保有する運送会社へ依頼することができる- ただし運送会社への依頼はSmaryuトラックという別サービスで実装されていたためUIが別になっていた- それを一つの画面からどちらにも依頼ができるようにするというのがこのPJT
依頼画面統合PJTの状況- 当初は1人月のフロントエンドエンジニアでできるのではーという甘い見積もりからスタートしたが思いのほか複雑ということで、2人/3ヶ月くらいに変更- しかし着地としてはフロントエンドエンジニア3人/11ヶ月くらいかかった。- バックエンドエンジニアは他にいる
難航した原因- フロントエンドにドメインロジックが強く組み込まれていた- 新機能開発と移行を同時に行ってしまった- プロジェクトリードやメンバーがコロコロ代わり引き継ぎコストが非常に高くなった
フロントエンドにロジックが強く組み込まれていた- 配送依頼画面はサービスの根幹を担う機能- サービス立ち上げから現在までの試行錯誤や価値提供のためのロジックがたくさん存在する- この仕様を読み解き、取捨選択して移行する難易度が非常に高かった- 本来バックエンドが担うべきビジネスロジックがフロントエンドに漏れ出していた- バックエンドの負債とも強い関係- ScalaのAPIを改修すればいいができないので、別 APIをRailsに作ってフロントエンドでマージ /計算する- Railsの既存APIを改修すればいいがテストなく複雑なコードを触るのが怖いので、別 APIを作ってフロントエンドでマージ・計算する- バックエンドにロジックを組むべきだが他が壊れるのが怖いのでフロントエンドでロジックを組む- 結果、フロントエンドのコードが肥大化していくことに- 技術的負債が重なると更なる負債を生み出すという結果を観測することになってしまった。
新機能開発と技術移行を同時に行った- Nuxtへの移行と依頼画面統合という大幅な仕様変更を一緒に行ってしまった- 統合するだけでなく、このタイミングでということで他にも組み込まれた修正が多数- 既存の実装を完全に把握できていない状態での移行、加えての仕様変更により、実装や計画の複雑さ、関係する部署とのコミュニケーションの複雑さが増してしまった。- 統合や仕様変更をするにしても、一度既存仕様のまま移行し、その後に統合、そして仕様変更するという形にした方が結果としては早く終わった可能性が高い
プロジェクトリードが変わって引き継ぎコストが高い- プロジェクト開始の時点で社歴が長くて仕様理解が高い人は別プロダクトに入っていたり、退職したりでシステム理解が乏しいメンバーでの開発スタートになってしまった- それに加えて、プロジェクトマネジメントやテックリードが別プロジェクトへのアサインために変わったり退職してしまったりで3ヶ月ごとくらいのイメージでリードが変わってしまう状況になってしまった- 引き継ぎコストや仕様理解がその都度は発生し、最終的なQAの段階での仕様確認もこれが正しいという状況を判断するのが毎度毎度時間がかかる状況に
2021年8月にローンチ- かなり過酷なプロジェクトとなったが無事ローンチ- この時も特定の荷主様向けのみ事前リリースして利用してもらい、バグ修正などを対応していた上でリリース。- それでも事前リリースした荷主は使わないパターンでバグが出るなどは多少ありつつも、このバグ対応に開発リソースを一時的に集中して短期で安定化することができた
現在の移行PJT状況- 配送依頼画面をNuxt/TSに移行できることで、その後の新機能開発はだいぶ安心感を持って開発することができた- しかし、その他の画面の移行する余力を得るまで一時的に移行PJTを停止して他の課題を解決することに集中- その後しばらくして、移行PJT再開- 社内のエンジニアだけ進めることが難しいため、社外の開発会社と協力して現在進行系で移行中- すでに50%の画面は移行済みで、来年 3月には全画面が移行完了する見込み
現在の移行PJTの工夫ポイント- バックエンドのScala->Rails移行を先行して進めバックエンド由来の複雑さを軽減- 機能追加はせずに、既存仕様での移行に専念- フューチャーフラグを使い、ユーザー公開しなくてもmainブランチにマージできるような仕組みを導入
スタッフ用管理画面の移行PJT- サービス運営する上で社内のスタッフが広く使っている管理画面- こちらも荷主画面を拡張する形で作られているのでレガシーフレームワークで実装されている
スタッフ管理機能の不足による課題- サービス運営上多数の機能が必要だが、全然たりていない- そのため開発者に依頼してSQLを叩いて行うオペレーションがたくさんあった- それにより負のサイクルが回っている状況- 管理機能が足りない- 開発者に依頼がくる- その依頼対応のために新機能のための時間作れない- 管理機能がたりない- これに加えて負債となっているフレームワーク上に新しい画面を追加して負債を増やしたくないという思いが重なる
新管理画面開発PJTと爆誕- 既存の管理画面は一旦そのまま- 開発にくる依頼を新管理画面でできるようにするという目的でNuxt/TSで新しい管理画面を作る- これにより正のサイクルを作る- 管理機能を作る- 開発者のオペレーション負担が減る- 開発する時間が増える- 管理機能を作る
最初はNext.jsでプロトタイプを作る- 社内の別プロダクトもすべてNuxt.js- だが技術検証の意味もこめて一度Next.jsで作ってみた- 3ヶ月で10以上の機能を作ってテスト運用- その上で再度技術選択を考える
最終的にはNuxt.jsで作りなおす- Nuxt.jsの3が近くなっている状況なので、管理画面で新しいバージョンのNuxtを使うことで他プロジェクトに知見を共有できる方がいいだろうと判断- さらに3ヶ月程度かけてNuxt.jsで作り直して本稼働開始- その後も機能追加を継続、かつ新しい管理機能もこちらに実装することで管理機能を作ることの抵抗感を大きく減らすことができた。- いまもオペレーションを支えていて、開発チームの工数削減や他部署のメンバーが開発チーム待ちになるリードタイムを減らしている
新管理画面の今後の方針- 開発者の工数を下げるという目的は一定達成- 次はスタッフの非効率なオペレーションを効率化する機能開発や、既存の管理機能の移行を目指す
まとめ- ビジネスを前に進めるために以前行った決定の上に僕らは立っている- そこを否定しない- とはいえ、これからの数年を今いる人の意思決定が支えるので、現在進行形でレガシーフレームワークの課題に向き合っている- 技術的な課題も多いが、マネジメントの課題の方が多くここをしっかり向き合って改善していくにはある程度長い目線で向き合う覚悟と気合いがいる- だからMPをかなり消費する- ただ、モダンな技術を新規で採用するスキルよりも既存の技術を新しい技術に置き換えていくスキルの方がエンジニアとしての市場価値もおそらく高い- ここに積極的に向き合えると、逆に難しい課題を解く楽しみを味わえて楽しい