🫵

【重要】Next.js実装時はココを押さえて品質保とう!

2023/06/11に公開

はじめに

こんばんは。
こちらはだいぶ寒くなってきて毛布が手放せなくなってきたオーストラリア在住のケニーです。

前回までの記事ではテスト(Jest、E2E)の基本についてアウトプットしました。
最近は、テストの理解を深めていく事は、
【テストの重要性のみならず、品質を一定以上に保つ事に結び付く】
と痛感し始めましたので、品質を保つ事についてアウトプットしてみようと思います。

この記事の対象

ソースコードの品質管理について、

  • 全然知らん!の方     :この際新たな知識のインプットに。
  • なんとなく理解している方 :この際復習も兼ねて。
  • 詳しいぜ!の方      :ケニーのアウトプットに間違いがないか。

目を通していただけますと嬉しいです!

TL;DR

以下を意識する事でテストの導入の敷居が低くなり、ソースコードの品質管理ができるようになる
1)できる限り機能分離する
  ⇒超重要:画面の処理とビジネスロジックの処理が一緒になっているのはNG。
2)関数は万能でつくらず、シンプルに。
 例:formatterの関数ならformatterの仕事しかさせない。
  それ以外も一緒にやるとNG。テスト導入時にも手間が一気に増える
3)識別子は超こだわる
4)letは極力使わない

では本題へ

※クリーンアーキテクチャの概念をベースに自分なりの今の考えを書いていくので、これが正解だとは限らないでしょうし、もしかしたら間違い等あるかもしれません。もしあれば優しくご指摘いただけますと嬉しいです。

余談)クリーンアーキテクチャとはRobert C. Martin(Uncle Bob)が2012年に提唱したDBやフレームワークからの独立性を確保するためのアーキテクチャ。詳細は今回は割愛します。

機能分離を意識する

機能分離がイメージしにくい場合、会社をイメージしてもらうと理解が進むかもしれません。
例えば、株式会社HOGEケニーには、以下のように機能分離をして事業を営んでいるとします。

株式会社HOGEケニー
 +-- 営業部
 |     +-- 国内チーム
 |          +--東日本担当 
 |          +--西日本担当 
 |     +-- 海外チーム
 |          +--アジア担当 
 |          +--オセアニア担当 
 +-- 開発部
 |     +-- フロントエンドチーム
 |     +-- バックエンドチーム
 |(その他略)

このように細かく役割(機能)を分離することで、誰が何をやるっていうのが明確になり、
管理側は課題を見つけたり、カイゼンやチーム編成の修正等がしやすくなります。

このイメージを、実装に落としこんでいきます。

例:本のオンラインショップでの本の一覧画面をNext.jsで実装

(詳細のコードは割愛)

上記のような画面を実装する際、どう機能分離をするのが良いのか。
(上記図は、5分で作ったものなので、クオリティはご了承ください。。)

先に結論を書きます。
ディレクトリ構成の抜粋としては、以下のイメージになります。

web
 +-- features(機能の塊)
 |     +-- books
 |          +-- index.tsx(一覧画面全体。バックエンドとの処理はここにまとめる)
 |          +-- bookContainer.tsx(本の一覧表を表示だけ)
 |          +-- bookList.tsx(本の一覧データを表示だけ)
 |          +-- logic(booksに関するビジネスロジックをここにまとめる)
 |               +-- logicA.tsx
 |               +-- logicB.tsx
 |          +-- test(logicに対するテストをここにまとめる)
 |               +-- logicA.test.ts
 |               +-- logicB.test.ts
 +-- pages
 |     +-- books(本に関するページ)
 |          +-- index.tsx(routerのみ行う。中身はすべてfeaturesからインポート)

少し解説します。

1)pages/books/index.tsxの対象ページ

pagesは、あくまでルーティングさせるだけのページにする
例)本の詳細ページへの遷移

2)features/books/index.tsxの一覧画面全体

一覧画面全体を管理し、useHogehoge系の処理はすべてここで処理する
例)本の一覧データ取得、ページネーション処理、バリデーション等

3)features/books/bookContainer.tsxの本の一覧表

・本の一覧表に絞って、側を表示させる
・検索で入力されたキーワードは、features/books/index.tsxに渡す。ここでは処理しない
・親から渡されたページネーション情報をここで表示させる

4)features/books/bookList.tsx

features/books/index.tsxから渡された本の一覧データを表示させる

5)features/books/logic

features/booksに関するビジネスロジックはすべてここにまとめる

6)features/books/test

5)logicに対してのテストをここですべて実施し、品質担保する

はい、このように機能を分離させました。
ルーティングさせる機能、画面を表示させる機能、ビジネスロジック機能、テスト機能、といった具合に明確に役割を分けています。
ここでのポイントとしては、画面の処理とロジックの処理が一緒になっていない事です。
ロジックの処理を抽出することで、テスト導入の敷居がぐっと低くなります。

画面で機能分離を表すと以下のような感じ・・?

機能分離するメリット

  • 可読性が増す
  • 品質管理がしやすい
  • メンテナンスや拡張に優れている

機能分離するデメリット

  • ファイル数が多くなる
  • (個人的に)慣れるまで大変

識別子は超こだわる

別記事で作成中なので、ここでは簡潔にアウトプットすると、
・(プロジェクトの)ルールに従って、
・略語は使わずなるべく簡潔に、
・第三者がみて中身がすぐイメージできるように、
命名する。といった感じでしょうか。

ifが続くケースはなるべく避ける

以下のようにifが続くケース見たことあると思いますが、
テストを導入する前提で実装する場合、できれば避けたい。

if (xxx) {
  if(yyy) {
    hogehoge
  } else {
    fugafuga
  }
}
return

テストを導入する際、分岐が多くなればなるほど、大変になります。。

letは極力使わない

よく言われている事ですね。
途中で値が変わるので、処理を一個ずつ追わないといけなくなる為、
想定していないバグが発生する可能性が非常に高くなります。
(テストを実装する際も大変です)

終わりに

とりあえず機能するものを実装する「スピード重視」は理解はできるものの、
リリース後の保守運用等の長い目で見ると、プロジェクトスタートした段階からとりあえず上記を意識して実装していくと、グッと品質確保に繋がると思います!

只今、絶賛スキルアップ中ですので、次回も乞うご期待ください!♪

コラボスタイル Developers

Discussion