より良い開発体験に ~Atomic Designによるコンポーネント設計~

[React Advent Calendar 2019](https://qiita.com/advent-calendar/2019/react)の6日目担当[@takashima_katsu](https://twitter.com/takashima_katsu)です。

## はじめに
約4ヶ月ほど前より、Reactで書かれたプロジェクトに参画しています。
このプロジェクトは私が参画する半年ぐらい前から開発されており、基本的にはサーバーサイドをメインとしているエンジニアが1人でフロント部分も担当していました。
コンポーネント設計や粒度がバラバラだったりしたため、「既にあるモノを再度作ってしまった。」「既にあるが大きなコンポーネントの一部として、密結合になっているので再利用できない。」
といったことが多発していました。

この記事では、そんなプロジェクトに途中から参画した私が、
「もう少しこうだったら、良いかもなー」と思い、
改善させる予定の概要を記載します。

## 改善したいこと
まずは改善点の整理です。

私が参画した時の状態で

- Hooksが使われていない
- コンポーネントリストがない
- コンポーネントの粒度が大きい

このトリプルコンボによるDX(開発体験)の悪さです。

### Hooksが使われていない
今のReactでHooksを使わない理由はないです。

Hooksは使われていませんでしたが、`React16.8以上`のものを使用していたので使おうと思ったら使える状態でした。
Reduxや、最近ではreact-routerなどの周辺モジュールでもHooksを入れていきました。

#### Hooksの魅力
私が感じたHooksの魅力はシンプルさです。

Reactの良さにシンプルというのがありますが、Hooksの登場によりこのシンプルさはさらに高まったとかんじています。
単純にコード量も減りましたが、ライフサイクル依存がなくなった事も大きいです。
これによる、コンポーネント設計のシンプルさやカスタムフックによるビューに依存しないロジックのモジュール化があります。
(オブジェクト指向から関数型言語の考え方を取り入れた事にも起因していると考えています)

ReactやHooksをよく知らないといった方は、見た目部分とロジックがそれぞれ柔軟に使い回しやすくなったと思ってください。
大きな開発をしていけばしていくほど、見た目部分でもロジックでも「同じような実装を別でもやったな」ということが多発してくると思います。
その問題解決をシンプルにできるようになっています。

##### スモール・イズ・ビューティフル
これは、[UNIXという考え方](https://www.amazon.co.jp/UNIX%E3%81%A8%E3%81%84%E3%81%86%E8%80%83%E3%81%88%E6%96%B9%E2%80%95%E3%81%9D%E3%81%AE%E8%A8%AD%E8%A8%88%E6%80%9D%E6%83%B3%E3%81%A8%E5%93%B2%E5%AD%A6-Mike-Gancarz/dp/4274064069/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=unix&qid=1575641608&sr=8-2)に書いてあったのですが、『小さくシンプルに作って保とう』という考え方があります。

これは、ソフトウェア開発全般に言えることです。
密結合でモノリシックなものではなく、疎結合でマイクロサービスなものが好まれているのもここだと思っています。
フロント側でそれを体現する道具のひとつとして、Hooksもあるのかと考えています。

### コンポーネントリストがない
開発が進むにつれ、コンポーネントは増えていきます。適切な粒度でコンポーネントを作っていったとしても、後から参画した人が把握するのは大変ですし、既に開発している人たちでさえ完璧に把握しおくのは難しいです。
それに、コンポーネントリストを作ることは、コンポーネントの粒度を考える時の助けにもなってくれます。

[Storybook](https://storybook.js.org/)を導入しました。
コンポーネントリストとしてだけではなく、まだ使用したことがないのですが`Snapshotテスト`なども行えることも利点です。
(全然使いこなせれていないので頑張りたい...)

### コンポーネントの粒度が大きい
詳しくは後述しますが、**Atomic Design**というデザインフレームワークを採用して、それに沿ってコンポーネントの粒度を考えていきます。
私の参画した時の既にあるものの多くが、Atomic Designで言うところの`Templates` `Organisms`層レベルの粒度だったため、ここを意識するだけでもDXの向上は大きかったです。

前者2つは「Hooksを使って、Storybookも導入しましたー」しか書くことがないので、これよりはコンポーネント設計についてを書いていきます。
(ここは、未だに正解がわからなく試行錯誤しているので、みなさんがどのようなコンポーネント設計やディレクトリ構成にしているのかをコメントにでも教えていただけると嬉しいです。)

## Atomic Designを意識したコンポーネント設計
コンポーネントの粒度を決めるに当たって、基準を設けとようと考えました。
ただ再利用性を考えて作っていくだけでは、各エンジニアによってばらばらになると思ったので、ここは明文化しておく必要があると考えたからです。

調べていると、多くの人が**[Atomic Design](http://atomicdesign.bradfrost.com/)**に則って設計していることを知りました。
「Atomic Designとは何なのか？」についてはこの記事では書いていきません。
2013年に発表されたものなので、既に多くの記事があるのと、私が調べていく中で見たのは、国内記事でも大半が2~3年前の物だったことから、私が知ったのが遅いだけでフロントエンジニアやデザイナー界隈では既に多く語られ、当たり前の知識だと想定しているからです。

Atomic Designといっても厳格なものは取り入れていません。
あくまでもデザインフレームワークですので、チームによってやりやすいように合わせていくのが良いと考えています。

私の場合は、Molecules層のもの全てをAtomsで定義しているわけではありませんし、Templatesの概念はなくしています。~~登場人物が多いのが面倒なので~~

### レイアウトは自身で持たない
レイアウトは上位層で決めるようにしています。
(Atoms層のレイアウトはMolecules層で、Molecules層のレイアウトはOrganisms層で...)

レイアウトの例としては、width, marginやflexなどです。
レイアウトは各コンポーネント自身で決めておくと、再利用性が低くなってしまいます。

### 最適化を焦らない
Atomic Designを知った最初の頃に、私はある大病にかかってしまいました。
『なんでもコンポーネントにしたい病』です。

最初の頃は、厳格なAtomic Designのルールを守って最適化しようと思い、なんでもかんでもコンポーネント化しまくろうとしていました。
その中で、たくさんの再利用することのないコンポーネントを作ってしまったり、汎用性を持たせようとしすぎてコード量が多くなって行ったりしました。

再利用性を高く、見通しの良いコンポーネント設計にするために導入したAtomic Designなのに、再利用することのないものが溢れていき、ディレクトリ全体で見たときに見通しの悪いものになってしまいました。

### Rule of three
その治療薬として『Rule of three』です。
『なんでもコンポーネントにしたい病』にかかっていた私自身にこのルールを設けました。

意識したのは、3回以上登場するものだけをコンポーネント化することです。
最適化を目指すあまり、空回りしていた私には特効薬でした。

### ディレクトリ構成
ディレクトリ構成はこんなかんじです。
<img width="198" alt="スクリーンショット 2019-12-06 21.17.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231184/c3e2aa26-57c2-dd2d-87dd-0e1a8fa07f1e.png">

Next.jsでもこのまま使っています。

## これから
これを言うと怖い人から怒られそうなんですが、テストを書けていません。
テストを書きたい**"気持ちはある"**ので色々見ているのですが、一言でテストといっても色々とありすぎませんか？

正直テストの必要性もあまりわかっていなかったのですが、最近仕様変更によってそれに関連している別のところが動かなくなっていたのを見つけました。
また、私自身はリリース前の新規開発しかしたことがないのですが、今後サービスをしっかりと運用しながら育てていくことを考えると必要だなーと心変わりしてきました。

よーし、がんばるぞー！