コンポーネントは compnents 以下にフラットに全部置くのが良い

# はじめに
巷では `Vue.js` や `React` など、コンポーネント指向フレームワークにおいて、**どのようにコンポーネントのディレクトリを切り分けるか** について議論がなされているようです。

- [Atomic Design ベースの Vue コンポーネント設計](https://qiita.com/d2cd-kimura/items/4aee84da42131f40b808)
- [Atomic Designをやめてディレクトリ構造を見直した話](https://note.com/tabelog_frontend/n/n07b4077f5cf3)
- [なに？マクドナルドから学ぶ、優れたcomponentsディレクトリ構造？！](https://qiita.com/marty_ojiya/items/abe64cfaff2e0941e278)

私自身も、ここ 1.5 年ほどフロントエンドの開発を行っており、いくつかのディレクトリ構造を経験しました。
結論、**`components` 以下に全てのコンポーネントをフラットに配置する**のが一番しっくり来ています。

# フラット構造がオススメの理由
とりあえず概要だけ先に書いておきます。

- １年ほど前から全社的に導入しているが、この方法で全く困ったことがない。
- どのフォルダに入れるかを全く考えなくていい。
- 検索が容易。

# フラットなディレクトリ構造を実践してみる
こんな感じです。

```
src
├── components
│   ├── AppBackButton
│   ├── AppSubmitButton
│   ├── ArticleCard
│   ├── ArticleTextEditor
│   ├── ArticleTextColorPallet
│   ├── BaseInput
│   ├── BaseSelect
│   ├── BaseTextArea
│   ├── ProfileCard
│   ├── ProfileForm
│   ├── ProfileFormLayout
│   └── ProfileGenderSelect
└── pages
    ├── ArticleListPage
    ├── ArticleEditPage
    ├── ProfilePage
    └── ProfileEditPage
```

## ポイント： 命名規則
全てのコンポーネントは原則として **属性 + 要素** という形式で命名されています。

#### ArticleTextColorPallet

- Article = 記事投稿機能に関連する
- TextColorPallet = テキストの色選択要素


#### AppBackButton

- App = アプリケーション全体で共通の
- BackButton = 戻るボタン

このように名前を付けることで、どの機能に関連するものなのか、どのような要素なのか、が明確になります。
機能をまたがって使う場合は、`App` やプロダクト名等のプレフィックスを付けましょう。
検索するときも、機能 → 要素 と絞り込んでいけるので楽です。

## ポイント： Base コンポーネント
`Base` という名前がついているコンポーネントは、**プロジェクト全体で使われる最も基本的な要素** を指しています。
Atomic Design で言うところの **Atoms** に相当します。

もちろん `Base` 以外のプレフィクスを付けても OK です。
チームで合意が取れていれば `Core` でも `Hoge` でも何でも OK です。

## ポイント： page ディレクトリ
各ページ最上位に当たるコンポーネントは `page` 以下で管理します。

「全て」フラットじゃないのかよ！！というツッコミもあるかと思います。すいません。
別に `components/` だけでも問題はありません。`Page` という要素であることが明確だからです。
我々のチームでは、`Page` 以外で api 等のリソースを直接使ってはいけない、というルールを敷いていたので、ディレクトリを分けて、`Page` コンポーネントが特別であるということを表現しました。

# 他のやり方との比較
### Atomic Design
私自身 Atomic Design のディレクトリ構造を試したことがありますが、どのディレクトリかを考えるのは結構大変です。
Atoms は割と決めやすいですが、 **molecules と organisms は基準が曖昧になりがちです。** 時間をかけて分類しても、得られるものが少なすぎました。

### 機能ごとにディレクトリを切る方法
先程の例の、`Article` `Profile` のような機能ごとにディレクトリを切ってみたりもしていました。
このやり方は、機能ごとにコンポーネントが見やすくなるという点では優れています。
一方で、次のような状況が発生します。

```
src
└── components
    ├── article
    |   ├── Card  // 名前が同じ！
    |   ├── TextEditor
    |   └── TextColorPallet
    └── profile
        ├── Card  // 名前が同じ！
        ├── Form
        └── GenderSelect
```

この状態でファイル名で検索すると `Card` コンポーネントが複数表示されます。
もちろんディレクトリ名を見れば特定できますが、VsCode の `ctrl + p` での検索では、ディレクトリ名はやや見づらいです。
細かいことですが、コーディング中は何回も繰り返す動作なので、効果はかなり大きいです。

# その他
### 命名規則は徹底する
チーム内で命名規則を決めて、徹底することが大切です。
徹底できれば、名前だけでスコープと機能を伝えることができるようになります！

### 車輪の再開発を防げる
「こういうコンポーネントつくらないとな...」と思ったときに、ファイル検索をすると、実はもう既に存在していた！
みたいなことがちょいちょいあります。

### components ディレクトリが巨大になる問題
また、**components ディレクトリが巨大なりすぎるんじゃないの？** という疑問もあるかも知れません。
はい、なります。開くとズラーッとコンポーネントが表示されます。
でも問題となったことはありません。**コンポーネントファイルは検索して開けば良い**のです。

### 命名が長くなりすぎる問題
`ArticleTextColorPallet` とかは長いな、と感じた方もいるかも知れません。
確かに長いですが、それで問題になったことはありません。
むしろ名前が長いコンポーネントは、それだけ**狭い範囲で使われているコンポーネント**なんだ、ということが分かります。
逆に名前の短いものは、**汎用的で広い範囲で使われているコンポーネント**であることが分かります。(例外もありますが。)

# まとめ
いろんなコンポーネント管理方法が記事になっていますが、フラットに管理する、というものはあまり見ないので書いてみました。
もちろんプロジェクトの規模によってベストな方法は変わってくるとは思います。
ですが、我々の社内では小さいプロジェクトから大きいプロジェクトまでこの方法を採用していますが、困ったことは一度もありません。
迷っていたら、是非試してみてください。