メインコンテンツにスキップ

カスタムアーキテクチャからの移行

このガイドは、カスタムのアーキテクチャからFeature-Sliced Designへの移行に役立つアプローチを説明します。

以下は、典型的なカスタムアーキテクチャのフォルダ構造です。このガイドでは、これを例として使用します。フォルダの内容が見えるように、フォルダの横にある青い矢印をクリックすることができます。

📁 src
  • 📁 actions
    • 📁 product
    • 📁 order
  • 📁 api
  • 📁 components
  • 📁 containers
  • 📁 constants
  • 📁 i18n
  • 📁 modules
  • 📁 helpers
  • 📁 routes
    • 📁 products.jsx
    • 📄 products.[id].jsx
  • 📁 utils
  • 📁 reducers
  • 📁 selectors
  • 📁 styles
  • 📄 App.jsx
  • 📄 index.js

開始前に

Feature-Sliced Designへの移行を検討する際に、チームに最も重要な質問は「本当に必要か?」です。私たちはFeature-Sliced Designが好きですが、いくつかのプロジェクトはそれなしでうまくいけることを認めています。

移行を検討すべき理由はいくつかあります。

  1. 新しいチームメンバーが生産的なレベルに達するのが難しいと不満を言う。
  2. コードの一部を変更すると、しばしば他の無関係な部分が壊れる。
  3. 巨大なコードベースのため、新しい機能を追加するのが難しい。

同僚の意に反してFSDに移行することは避けてください。たとえあなたがチームリーダーであっても、まずは同僚を説得し、移行の利点がコストを上回ることを理解させる必要があります。

また、アーキテクチャの変更は、瞬時には経営陣には見えないことを覚えておいてください。始める前に、経営陣が移行を支持していることを確認し、この移行がプロジェクトにどのように役立つかを説明してください。

ヒント

プロジェクトマネージャーをFSDの有用性に納得させるためのアイデアをいくつか紹介します。

  1. FSDへの移行は段階的に行えるため、新機能の開発を止めることはありません。
  2. 良いアーキテクチャは、新しい開発者が生産性を達成するのにかかる時間を大幅に短縮できます。
  3. FSDは文書化されたアーキテクチャであるため、チームは独自の文書を維持するために常に時間を費やす必要がありません。

もし移行を始める決断をした場合、最初に行うべきことは📁 srcのエイリアスを設定することです。これは、後で上位フォルダを参照するのに便利です。以降のテキストでは、@./srcのエイリアスとして扱います。

ステップ1。コードをページごとに分割する

ほとんどのカスタムアーキテクチャは、ロジックのサイズに関係なく、すでにページごとに分割されています。もし📁 pagesがすでに存在する場合は、このステップをスキップできます。

もし📁 routesしかない場合は、📁 pagesを作成し、できるだけ多くのコンポーネントコードを📁 routesから移動させてみてください。理想的には、小さなルートファイルと大きなページファイルがあることです。コードを移動させる際には、各ページのためのフォルダを作成し、その中にインデックスファイルを追加します。

注記

現時点では、ページ同士が互いにインポートすることは問題ありません。後でこれらの依存関係を解消するための別のステップがあります。今はページごとの明確な分割を確立することに集中します。

ルートファイル

src/routes/products.[id].js
export { ProductPage as default } from "@/pages/product"

ページのインデックスファイル

src/pages/product/index.js
export { ProductPage } from "./ProductPage.jsx"

ページコンポーネントファイル

src/pages/product/ProductPage.jsx
export function ProductPage(props) {
return <div />;
}

ステップ2。 ページ以外のすべてを分離する

📁 src/sharedフォルダを作成し、📁 pages📁 routesからインポートされないすべてをそこに移動します。📁 src/appフォルダを作成し、ページやルートをインポートするすべてをそこに移動します。

Shared層にはスライスがないことを覚えておいてください。したがって、セグメントは互いにインポートできます。

最終的には、次のようなファイル構造になるはずです。

📁 src
  • 📁 app
    • 📁 routes
      • 📄 products.jsx
      • 📄 products.[id].jsx
    • 📄 App.jsx
    • 📄 index.js
  • 📁 pages
    • 📁 product
      • 📁 ui
        • 📄 ProductPage.jsx
      • 📄 index.js
    • 📁 catalog
  • 📁 shared
    • 📁 actions
    • 📁 api
    • 📁 components
    • 📁 containers
    • 📁 constants
    • 📁 i18n
    • 📁 modules
    • 📁 helpers
    • 📁 utils
    • 📁 reducers
    • 📁 selectors
    • 📁 styles

ステップ3。 ページ間のクロスインポートを解消する

あるページが他のページから何かをインポートしているすべての箇所を見つけ、次のいずれかを行います。

  1. インポートされているコードを依存するページにコピーして、依存関係を取り除く。
  2. コードをShared層の適切なセグメントに移動する
    • UIキットの一部であれば、📁 shared/uiに移動。
    • 設定の定数であれば、📁 shared/configに移動。
    • バックエンドとのやり取りであれば、📁 shared/apiに移動。
注記

コピー自体はアーキテクチャの問題ではありません。実際、時には新しい再利用可能なモジュールに何かを抽象化するよりも、何かを複製する方が正しい場合もあります。ページの共通部分が異なってくることがあるため、その場合、依存関係が妨げにならないようにする必要があります。

ただし、DRY("don't repeat yourself" — "繰り返さない")の原則には意味があるため、ビジネスロジックをコピーしないようにしてください。そうしないと、バグを複数の箇所で修正することになることを頭に入れておく必要があります。

ステップ4。 Shared層を分解する

この段階では、Shared層に多くのものが入っているかもしれませんが、一般的にはそのような状況を避けるべきです。理由は、Shared層に依存している他の層にあるコードが存在している可能性があるため、そこに変更を加えることは予期しない結果を引き起こす可能性が高くなります。

特定のページでのみ使用されるすべてのオブジェクトを見つけ、それらをそのページのスライスに移動します。そして、これにはアクション、リデューサー、セレクターも含まれます。すべてのアクションを一緒にグループ化することには意味がありませんが、関連するアクションをその使用場所の近くに置くことには意味があります。

最終的には、次のようなファイル構造になるはずです。

📁 src
  • 📁 app (変更なし)
  • 📁 pages
    • 📁 product
      • 📁 actions
      • 📁 reducers
      • 📁 selectors
      • 📁 ui
        • 📄 Component.jsx
        • 📄 Container.jsx
        • 📄 ProductPage.jsx
      • 📄 index.js
    • 📁 catalog
  • 📁 shared (再利用されるオブジェクトのみ)
    • 📁 actions
    • 📁 api
    • 📁 components
    • 📁 containers
    • 📁 constants
    • 📁 i18n
    • 📁 modules
    • 📁 helpers
    • 📁 utils
    • 📁 reducers
    • 📁 selectors
    • 📁 styles

ステップ5。 コードを技術的な目的に基づいて整理する

FSDでは、技術的な目的に基づく分割がセグメントによって行われます。よく見られるセグメントはいくつかあります。

  • ui — インターフェースの表示に関連するすべて: UIコンポーネント、日付のフォーマット、スタイルなど。
  • api — バックエンドとのやり取り: リクエスト関数、データ型、マッパーなど。
  • model — データモデル: スキーマ、インターフェース、ストレージ、ビジネスロジック。
  • lib — 他のモジュールに必要なライブラリコード。
  • config — 設定ファイルやフィーチャーフラグ。

必要に応じて独自のセグメントを作成できます。ただし、コードをその性質によってグループ化するセグメント(例: componentsactionstypesutils)を作成しないようにしてください。代わりに、コードの目的に基づいてグループ化してください。

ページのコードをセグメントに再分配します。すでにuiセグメントがあるはずなので、今は他のセグメント(例えば、アクション、リデューサー、セレクターのためのmodelや、サンクやミューテーションのためのapi)を作成するときです。

また、Shared層を再分配して、次のフォルダを削除します。

  • 📁 components📁 containers — その内容のほとんどは📁 shared/uiになるべきです。
  • 📁 helpers📁 utils — 再利用可能なヘルパー関数が残っている場合は、目的に基づいてグループ化し、これらのグループを📁 shared/libに移動します。
  • 📁 constants — 同様に、目的に基づいてグループ化し、📁 shared/configに移動します。

任意のステップ

ステップ6。 複数のページで使用されるReduxスライスからエンティティ/フィーチャーを形成する

通常、これらの再利用可能なReduxスライスは、ビジネスに関連する何かを説明します(例えば、プロダクトやユーザーなど)。したがって、それらをエンティティ層に移動できます。1つのエンティティにつき1つのフォルダです。Reduxスライスが、ユーザーがアプリケーションで実行したいアクションに関連している場合(例えば、コメントなど)、それをフィーチャー層に移動できます。

エンティティとフィーチャーは互いに独立している必要があります。ビジネス領域に組み込まれたエンティティ間の関係がある場合は、ビジネスエンティティに関するガイドを参照して、これらの関係を整理する方法を確認してください。

これらのスライスに関連するAPI関数は、📁 shared/apiに残すことができます。

ステップ7。 モジュールをリファクタリングする

📁 modulesフォルダは通常、ビジネスロジックに使用されるため、すでにFSDのフィーチャー層に似た性質を持っています。一部のモジュールは、アプリケーションの大きな部分(例えば、アプリのヘッダーなど)を説明することもあります。この場合、それらをウィジェット層に移動できます。

ステップ8。 shared/uiにUI基盤を正しく形成する

理想的には、📁 shared/uiにはビジネスロジックが含まれていないUI要素のセットが含まれるべきです。また、非常に再利用可能である必要があります。

以前📁 components📁 containersにあったUIコンポーネントをリファクタリングして、ビジネスロジックを分離します。このビジネスロジックを上位層に移動します。あまり多くの場所で使用されていない場合は、コピーを検討することもできます。