コンテンツにスキップ

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

このガイドは、カスタムのアーキテクチャから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.jsx

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

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

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

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

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


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

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

Section titled “ステップ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。 ページ以外のすべてを分離する

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

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

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

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

  • ディレクトリsrc/
    • ディレクトリapp/
      • ディレクトリroutes/
        • products.jsx
        • products.[id].jsx
      • App.jsx
      • index.js
    • ディレクトリpages/
      • ディレクトリproduct/
        • index.js
        • ディレクトリui/
          • ProductPage.jsx
      • ディレクトリcatalog/
    • ディレクトリshared/
      • ディレクトリactions/
      • ディレクトリapi/
      • ディレクトリcomponents/
      • ディレクトリcontainers/
      • ディレクトリconstants/
      • ディレクトリi18n/
      • ディレクトリmodules/
      • ディレクトリhelpers/
      • ディレクトリutils/
      • ディレクトリreducers/
      • ディレクトリselectors/
      • ディレクトリstyles/

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

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

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

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

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

Section titled “ステップ4。 Shared層を分解する”

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

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

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

  • ディレクトリsrc/
    • ディレクトリapp/
    • ディレクトリpages/
      • ディレクトリproduct/
        • ディレクトリactions/
        • ディレクトリreducers/
        • ディレクトリselectors/
        • ディレクトリui/
          • Component.jsx
          • Container.jsx
          • ProductPage.jsx
        • index.js
      • ディレクトリcatalog/
    • ディレクトリshared/ only objects that are reused
      • ディレクトリactions/
      • ディレクトリapi/
      • ディレクトリcomponents/
      • ディレクトリcontainers/
      • ディレクトリconstants/
      • ディレクトリi18n/
      • ディレクトリmodules/
      • ディレクトリhelpers/
      • ディレクトリutils/
      • ディレクトリreducers/
      • ディレクトリselectors/
      • ディレクトリstyles/

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

Section titled “ステップ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スライスからエンティティ/フィーチャーを形成する

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

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

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

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

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

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

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

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

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

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

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