Timee Product Team Blog

タイミー開発者ブログ

RailsフロントエンドをNext.js(SPA)に移行した〜バックエンド視点での振り返り〜

好きな水風呂の温度は16℃でお馴染み edy69x です。

Timee Advent Calendar 2023 の16日目を担当します。

本記事では今年完遂したUIリニューアル(SPA化)を通してタイミーで実施した工夫や学びを普段バックエンドの開発を担当する私の視点からお伝えします。

先日のイベントでの登壇内容を補完した内容となっています。気になる方は下記資料もご覧ください。

speakerdeck.com

イベントの方はプロジェクト終盤での断捨離やリファクタリングなどがテーマになっていたので本記事ではプロジェクト進行過程全般での知見をシェアしていきます。

プロジェクト概要

まずプロジェクトの概要です。大雑把に言うとフロントエンドの技術基盤を移行しながらUIリニューアルを実施しました。

それだけだと「何のことだ?」となるので前提からご説明します。

タイミーでは単発のアルバイト求人の掲載を行う事業者用のWeb管理画面を提供しています。

リニューアル前はRailsエンジニアがテンプレートエンジンのSlimを活用し、フロントエンド開発も担っていました。Railsで作られたサーバは動的に生成したHTMLをレンダリングする責務も持っていました。いわゆる Server Side Rendering(SSR) です。タイミー創業当初から変わらない技術スタックで構成されていて価値も生み出し続けていました。

しかし、サービス拡大にともない、古くから存在する Model や Controller への継ぎ足しの実装などが生まれ、Railsアプリケーションのバックエンドとフロントエンドの密結合なロジックが増えたり Fat Controller に頭を悩ませられるシーンが発生し始めました。

一方のフロントエンドでは保守性や情報設計(Information Architecture)を始めとして品質向上を狙ったり、jQueryに代わるモダンWebフロント技術の導入、またフロントエンド専任のエンジニアの採用拡大も狙っていました。

上記の理由などからUIリニューアル及びフロントエンドの技術基盤を刷新するプロジェクトがスタートしました。

フロントエンドの技術は下記の構成で、Railsのリポジトリとは別で切り出しました。

  • 言語: TypeScript
  • ライブラリ: React
  • フレームワーク: Next.js
  • APIドキュメント: OpenAPI (Swagger)

Webページ構成やレンダリング手法もこのタイミングから Server Side Rendering(SSR) から Single Page Application(SPA) に変更しました。

いざ始まったUIリニューアル

UIリニューアルを進める上で不確実性を大いに孕んでいたので管理画面全体を一気にビッグバンリリース的に旧バージョンから新バージョンに切り替える方針は見送りました。

方針としてはハレーションを抑えるためにアクセス数の少ない画面から徐々にリプレイスしていき、顧客が最も利用する事業のコア機能を終盤にリプレイスする計画を立てました。

同時にDatadogやGoogleAnalyticsなどの監視・分析ツールを用いて、アクセス数の解析、利用デバイス比率の特定をしたり、売上規模の上位を占める事業者を選定し、移行に際して障壁となるポイントが無いかを探っていきました。

従来デザイン使い続けたい問題

進行する中で発見されたのが「従来のデザインを使い続けたい」というユーザーニーズです。

背景には、既存UI/UXに対してのメンタルモデルが形成されているので変化を忌避してしまったり、画面構成やボタン単位で指定オペレーションを厳密に組んでいるケースなどがありました。

強行突破する方法もあると思いますが、打ち手として新デザインのリリース後も従来の旧UIに切り替えられる仕組みを導入しました。デバイス変更やセッション切れ等で、従来デザインを選択したユーザーが新デザインに切り戻されることを回避したり、データ分析観点で活用するために従来デザインを選択した状態はDBに永続化しました。

プロジェクト終了時には削除する前提だったので明確さやアクセスのし易さを優先しました。フロントエンドは使用状況をAPI経由で取得する方針を採用しています。

[従来のデザインに切り替える] ボタンを配置

この仕組みのお陰でリリース後に利用者に多少影響があっても完全にロールバックすることなく、利用者ごとの判断に委ねることが出来ました。新デザインを許容できる利用者には新デザインを提供し、どうしても従来のバージョンを利用したい方には一定期間の従来バージョン利用を許容する運用をしました。

事前告知による期待値調整も勿論大事だと思うのですが、石橋を叩きすぎずにリリース後の ”動くソフトウェア” を通しての実際のユーザーのフィードバックから次の意思決定に繋げられるアプローチを経験できたのは大きな財産になりました。

画面移行の約80~90%程度が終わる頃には新デザインがマジョリティになったので、上記機能はほぼ役目を終え勇退しました。

影響範囲を限定する話での余談ですが、カナリアリリースの仕組みがあると影響を抑えられた障害などもあったので今思い返すと導入しておけると良かったです(プロジェクト中には追加出来なかったので今後導入していきたい)。

ユースケースロジックを切り出すFormObjectを活用

プロジェクトも佳境に差し掛かった中で、とあるエンドポイントに対応するAPIを実装する工程が最も難を極めました。タイミーのコアドメインに関わる機能を司っている Controller のリプレイスです。元々が Fat Controller だったケースでして既存の仕様理解や根本的なリファクタリングが求められたのを覚えています。

リクエストを受けてからHTMLを返却する一連の処理の中に、データベースへの書き込みや外部APIへの通信、ビジネスロジックに関係する処理など様々な責務を Controller が抱えていました。テスタビリティも低く、RSpecで書いていた controller spec では仕様は網羅されていませんでした。

その際に Controller の責務を一部切り出す方法として FormObject を採用しました。ユースケースに対応したロジックを FormObject クラスに閉じ込め、Controllerはクラスのパブリックメソッドの呼び出しとリクエストの受付、及び適切なレスポンスの返却に特化する様な作りにしました。

FormObject には単に移行するだけではなく「テストピラミッド」も意識し、テストケースの割合が結合テスト < ユニットテスト になるように必要に応じて責務の見直しも行いました。

テストピラミッド

結果的に Fat Controller は消え去り、元々はAPIリクエストの受付からレスポンスまでの過程を通して結合テストでカバーしていたテストケースをユニットテストで再現できるようになりました。Controller は RSpec の request spec にて受け付けるリクエストとレスポンスを明示し、副作用のうち代表的なケースをテストすることで不要に FormObject 側のユニットテストと重複することも回避しました。

Controller の上部に君臨し続けていたTODOコメントを削除できたときは非常に感慨深かったことを今でも覚えています。

古来からタイミーを見守ってきた長老の様なTODOコメント

プロジェクトの中断

これは少しオフトピック的な話ですがプロジェクト進行のメタ的な話として触れておきます。

一般的にプロジェクトのみならず仕事を進める中で優先度が高い別Issueが割り込まれることはありますよね。今回のUIリニューアルプロジェクトでも起きました。

プロジェクトの性質的には「技術改善」をテーマとし基本的に従来機能を踏襲しながらUIリニューアルを進行する前提でした。そのため、割り込み的な機能開発に対してスイッチングコストが発生したり、リニューアルとの優先順位付けが必要になったりと苦労した覚えがあります。移行期間全体が約3年あったうち合計1年ほどはチーム構成やミッションが根本から変化し、別テーマの開発を担当する時期もありました。

結果として生存期間が短い前提で作られた機構が想定より長く存在し続けることになりました。例えば先に述べたデザイン切り替えの仕組みや、Rails, Next.js それぞれのリポジトリが互いに依存する様な暫定的なロジックなどです。

当時の自分はイレギュラーに対してある種「当たり前」くらいで考えていたのですが、水面下ではコードベース上に認知負荷を高める要因が生まれていました。新規参画メンバーから質問が来ることもありましたが、当時は影響を理解したり、言語化することは出来ていませんでした。

今思い返すと内部品質低下に繋がることから、プロジェクト完遂までのリードタイムを短縮したり、テーマが変化する前に最低限の内部品質改善をするように働きかける余地はあったなと感じます。

プロジェクトが順調に進んだり完了することだけが学びではなく、むしろ想定外の中に自分の枠を超えた学びのきっかけがあると気付かされた瞬間でした。

プロジェクト完遂

過程では様々な事があり、ここでは語り切れないのですが3年の歳月を経てプロジェクトは完遂しました。RailsリポジトリからはHTMLレンダリングにまつわるコードやCSSライブラリなど5万行を超えるコードが削除されました。特に1つのPull Requestで1万行を超えるコード削除をした時は非常に爽快でした。

Webpackerやyarnなどにも別れを告げ、外部顧客向けの機能についてはRailsリポジトリはWebAPIの開発に特化する様な存在になっています。GraphQL化を進める様なチャレンジも生まれました。

WebFrontも1名でプロジェクトがスタートしましたが今では技術コミュニティが生まれたり、技術顧問の方が付いていたりと2020年当時と比べてだいぶ拡大しています。いい話ですね。

おわりに

プロジェクトが終われど、フロントエンドにとってはスタートラインに立ったとも言えますし、バックエンド側も保守性が多少増したとは言え、会社の成長を支える面でいうとまだまだ改善余地があります。

会社に興味がある方がいたら、タイミーワーカーで運営が成り立っているTHE 赤提灯という居酒屋が新橋オフィス近くにあるので是非飲みに行きましょう。

一応採用ページも貼っておきます。

product-recruit.timee.co.jp

忘れていましたが、声を大にして改めて言っておきたい。

「タイミーはSPA化やり遂げたぞ!!!!」