🏇

フロントエンド(Next.js)現場に入って数ヶ月で技術的負債の改善に取り組んだ話

2024/11/01に公開

Fivotに参画してから約半年が経過しました。
参画当初から数ヶ月間、さまざまな課題に取り組み、方針も固まってきたため、
これまでの取り組みを整理し共有します。

背景

参画時点では、Flutter WebからNext.jsへの移行が完了したばかりの段階でした。
もともと別のプロダクトでFlutterアプリを活用していましたが、Flutter Webでの開発はメンテナンスが難しく、Next.js(v13)への移行が決断されました。

エンジニア2人体制で担当しましたが期間が短かったこと、フロントエンドが専門でなかったこともあり、コードの品質は課題が多い状態でした。
参画当初、早期の新規開発も求められていましたが、技術的負債の解消も並行して進めなければいけないと考え、改善活動に取り組みました。

技術的負債解消の取り組み

オンボーディング改善

環境構築に必要な情報をREADMEに記載し、ドキュメントを充実させました。
また、開発に使用していたVSCodeにおいて、settings.jsonやextensions.jsonを作成し、セットアップの手間を軽減し、全員が同一の開発環境で作業できるようにしました。
また、コーディング規約やディレクトリ構成などのドキュメントも作成し、READMEから参照できるようにしています。

Code Spell Checkerの導入

当初、コード内にはtypoが非常に多く見られました。これは、コードレビューが十分に行われていなかったり、品質への意識が低かったことを反映していると感じました。
そのため、VSCodeの拡張機能であるCode Spell Checkerを導入し、typoの検出と修正を自動化しました。
この取り組みによって、現在はtypoがほぼ撲滅されています。

コンポーネントファイル命名規則の変更

当初、全てのコンポーネントファイルがindex.tsという名前で作成されていました。
このため、ファイルの検索やVSCodeで複数ファイルを開いている場合などで何のファイルなのか特定がしにくい課題を感じていました。
そこで、Button.tsxのように、ファイル名からその役割を一目で把握できるように命名規則を見直しました。

ディレクトリ構成の変更

以下のような整理をしました。

  • 共通UIコンポーネントの分類
    typograpyやinputsのようなサブディレクトリを作成し、共通で使用するUIコンポーネントを用途ごとに整理しました。
  • 機能ごとのコロケーション
    各機能に関連するコンポーネントやhooksなどをfeaturesディレクトリに集約しました。
    また、ディレクトリに階層(親子関係)を設け、依存関係が分かりやすいようにしました。

UIコンポーネントの作成とFigmaとの同期

UIコンポーネントの共通化があまり行えておらず、車輪の再発明があちこちで行われてました。
同じタイミングで参画したデザイナーの方と連携し、まずFigmaでコンポーネントへの切り出しを行い、命名等も合わせた形でプロダクトにも反映させました。
また、spaceやfont-sizeなどのtokenを作成し、プロダクト側でも同様のtokenを適用しています。

padding: $spacing_lg;

コンポーネントの作成方針も見直しており、詳細は以下を参照ください。
https://zenn.dev/zoma/articles/c14793d24330ab

Container/Presentationalパターンの導入

参画当初、多くのコンポーネントが肥大化しており、役割が混在していました。また、テストのためにsubmitなどのpropsが不自然に渡されているケースも見受けられました。これらの問題を解消するため、Container/Presentationalパターンをコンポーネント作成の標準としました。
以下の記事も参照ください。
https://zenn.dev/zoma/articles/67b51cd6f1f6df

また、複数箇所で活用するFetchやMutationはhooks化しています。

コンポーネントライブラリの変更

当初、UIライブラリとしてAnt Designを使用していましたが、以下の点に課題を感じました。

  • スタイルのカスタマイズが困難
  • ドキュメントの不十分さ
  • Formの可読性、使用感が悪い

当時Ant Designへの依存度が高く、移行コストが懸念されましたが、変更するなら「早い段階での決断がベスト」と判断。新規画面の開発から段階的にMantineを導入しました。

Mantineの選定理由としては以下になります。

  • 機能が豊富であること
  • スタイルのカスタマイズが容易なこと
  • 活用経験、知見があり、開発者体験が良かったこと

実際にMantineを使用してみて、UIの作成がスムーズになり、開発生産性も向上しました。半年が経過した現在、ほとんどの画面がMantineに置き換わり、当時の判断が正しかったことを実感しています。

スタイル手法の変更

EmotionからCSS Modulesに変更しました。
RSCを見据えてEmotionは使い続けるのはリスクが高いと判断しました。
選択肢は豊富にあったものの、Mantineで推奨されていて導入コストが低いCSS Modulesを採用することにしました。

Fetch/Mutation周りの改善

プロジェクトではGraphQL/Apollo Clientを活用していますが、以下の改善を行いました。

  • Suspenseの活用
  • エラーハンドリングのグローバル化
  • キャッシュの活用

これらを導入するに辺り、いくつかの課題に直面し、別途記事として詳細をまとめる予定です。

Biomeの導入

当初からESLint/Prettierが使用されていましたが、デフォルト設定のまま追加の設定がほとんど行われていない状況でした。そこで、Biomeを導入することにしました。
Biomeに関して現時点では、いくつかの機能が不足していると感じる部分もありますが、速度の速さと設定の容易さは大きなメリットと感じています。
将来性もあるため、Biomeへの移行はポジティブな決断だったと考えています。

テスト

StorybookでのテストとChromaticを導入しました。
詳細は別途記事にする予定です。

その他、技術的改善

挙げきれませんが、以下のような改善を行いました。

  • svgrを導入してsvgをReactコンポーネントに変換した
  • a11yを意識したタグ活用(元々divばかりでした・・)
  • export defaultは原則使用しない
  • Renovateを導入し、定期的にライブラリ更新を実施
  • テストデータ、mockの共通化

こちらも参照ください。
https://zenn.dev/zoma/articles/c14793d24330ab

UI/UX/仕様

コーディングで大切にしている点としてシンプルにすることがあります。
これは、UIや画面挙動でも同様に考えてます。
当初、無駄な機能や挙動が多くあり、エラー内容が分からないなどUXの問題も多くありました。
デザイナーやPdM任せにせず、エンジニア発信でUI/UXや仕様面の改善を行なっていきました。

レビュー/プルリク

参画当時プルリクがかなり大きく、プロジェクト単位(数画面)で1つのプルリクが作られる運用になっていました。
結果として、以下のような弊害が発生していました。

  • レビューの質の低下
    • 大規模なPRでは、変更点の多さから手戻りの影響を懸念し、適切な指摘がしにくい
    • 量が多すぎるため、時間の確保が難しく、モチベーションも低下する
  • デグレが発生する可能性が高まる
  • 障害時のロールバックが困難
  • 共通で活用できるコンポーネント等の共有が遅れる

そこで、次のように方針を変えました。

  • 小さな単位で細かくプルリクを出すようにする
  • できる限りmainに早期マージを行う
    • 新規画面や機能の実装において、ルーティングの設定を除いた部分は、完成次第mainに随時マージする運用に変更
    • 共通コンポーネントや汎用的なロジックの共有が円滑になり、ロールバックの影響も小さくできた

また、レビューの遅延で開発者の手を止めないように、レビュー速度向上の取り組みも行いました。

  • 原則、自身の作業よりレビュー(他者に影響あるタスク)を優先する共通認識を持つ
  • 意見が割れそう、また理解が困難な箇所は、相談・説明してからレビューに出す
  • 理想はフロントエンド全員がレビューすることだが、approveを1人からもらえればマージできるものとした
    • レビュー依頼時、依頼を受けた際に担当が誰かをすぐに決定する
    • 優先度、緊急度をSlack送信時のスタンプの数でカジュアルに伝える

今後やりたいこと

色々とありますが、一番はApp Router / Next.js v15の検証です。
GraphQLを活用していて、App Routerを活用することの旨みと辛みがどの程度なのか
まだ見えてないこともあり、次の大型プロジェクトの前に検証する予定です。

まとめ

振り返ってみると、相当な数の変更や新規導入を行ってきたことに気付きます。弊社のプロダクトは、顧客向けだけでも30〜40画面がある規模感で、小規模とはいえないものです。そのため、ここまでの変革には、特に元々いたメンバーにとって大きな負担と勇気が伴ったと思います。

しかし、そのコストは確実に回収できると感じています。コードの保守性が向上し、UI/UXのシンプルさも実現されたことで、開発スピードが上がり、品質も大きく改善しました。また、共通リソースの管理やレビューの効率化によって、チーム全体がスムーズに協力し合える環境が整いました。

技術的負債の解消と最適化を進めることができたのは、変化を受け入れ、前向きに取り組むチームメンバーの協力があってこそです。この改善の積み重ねが、今後のプロダクトの拡張や新たな技術の導入に対する土台となり、プロジェクト全体の成長を後押ししてくれると確信しています。これからも改善を続け、より多くの価値を生み出していきたいと考えています。

Fivot Tech Blog

Discussion