Q. コンポーネント設計って誰がやるべきなの?

2021-05-18

先日とあるミーティングに参加させていただきまして。

フロントエンドディベロッパーの方よりいくつか質問をいただいたので、その内容を書き残しておこうと思います。


Q. Atomic Design ってあらゆるケースで導入したほうがいいの?

A. ケースバイケースなので、求められる仕様によって導入を考えましょう

Atomic Design は比較的シンプルなデザインに最適なデザインシステムです。

そのため 1 枚ペラのランディングページや、1 画面にたくさんの機能が盛り込まれたケースではあまり最適でありません。

Pattern Lab を基準として考えてみるのが良いと思います。

Q. Presentational Components では state を扱っていいの?

A. ui にのみ関わるものなら OK です

Dan Abramov の記事 には以下のように書かれてますね。

Rarely have their own state (when they do, it’s UI state rather than data).

独自の状態になることはめったにありません(ある場合は、データではなく UI の状態です)。 (Google 翻訳)

悩んだら全部 Container Components に寄せちゃっても良いと個人的には思います。

Q. コンポーネント設計って誰がやるべきなの?

A. Web デザイナーです

プロトタイピングツールにコンポーネントの機能 がある以上、Web デザイナーがやるべきに決まっています。

Web デザイナーが在籍しているのにフロントエンドディベロッパーがコンポーネント設計をするというのは普通に考えておかしいです、どう考えてもプロトタイプとの整合性が取れなくなります。

Web デザイナーの方にはしっかりとコンポーネント設計を理解してもらいたいです。

Q. Web デザイナーがいない場合は Atomic Design は導入しないほうがいいの?

A. ケースバイケースですが、そんなことはないです

Web デザイナーが在籍しないプロジェクトであれば、むしろ Atomic Design は導入したほうが有用なケースのほうが多いと思います。

Atomic Design 以外のコンポーネント設計(つまりデザインシステム)を知っているのであれば、それでも良いと思いますが。

自分は Atomic Design 以外知らないので、独自のやり方とかを導入するのはリスキーすぎると考えます。

Q. Redux の connect は Presentational Components で行っていいの?

A. ダメです、Container Components に限定しましょう

Presentational and Container Components の考え方に沿って開発を行うと決めた以上はきちんとルールに沿いましょう。

GraphQL や動的なデータを扱う Hooks でも同様です。

とくに Hooks についてはネストが深くなるため、フォルダーをわけるなどして動的なデータを扱うか否かひと目でわかる状態を作っておくことが重要です。

Q. Storybook って導入したほうがいいの?

A. もちろん導入したほうが良いですが、コンポーネント設計などが破綻しているケースでは導入しないほうが無難です

仮に Storybook に Api を関わらせないのであれば、理論上は Atomic Design の Templates  以下のすべてのコンポーネントに、Presentational Components のすべてのコンポーネントに導入が可能です。

個人的に Storybook には Api を関わらせたくない、つまり動的なデータを扱わせたくないです。

Storybook に Redux や動的なデータを扱う hooks が絡んでくるとめんどくさいですし、そっちにやたら時間を取られるのがイヤですね。

Q. 素の JavaScript で書いた Redux 周りに対しあとから TypeScript を反映するのってやめたほうが良いですか?

A. 個人的にはやめたほうが良いと思います

素の JavaScript で書かれた Redux 周りは基本的に型周りがボロボロです。

直すのは諦めたほうが無難かなと。


そんな感じです、いかがでしょうか。

言わずもがなですが、上に書いたことはすべて現時点での個人の見解です。

なにもかも鵜呑みにするのはやめましょう。

自分はどうなっても責任は持てませんし、あとから自分の考えが変わることもしょっちゅうあります。

それでもどなたかのお力になれれば幸いです。


追記

ちなみに、上記のコンポーネント設計は比較的レガシーです。

とくに Presentational and Container Components については、1 つの Container Component から各 Presentational Components に動的なデータを流し込むのはレガシーと言われています。

[Redux の公式サイト](Should I only connect my top component, or can I connect multiple components in my tree?) にもはっきり明記されていますね。

Should I only connect my top component, or can I connect multiple components in my tree?#

Early Redux documentation advised that you should only have a few connected components near the top of your component tree. However, time and experience has shown that such a component architecture generally requires a few components to know too much about the data requirements of all their descendants, and forces them to pass down a confusing number of props.

The current suggested best practice is to categorize your components as “presentational” or “container” components, and extract a connected container component wherever it makes sense:

Emphasizing “one container component at the top” in Redux examples was a mistake. Don't take this as a maxim. Try to keep your presentation components separate. Create container components by connecting them when it's convenient. Whenever you feel like you're duplicating code in parent components to provide data for same kinds of children, time to extract a container. Generally as soon as you feel a parent knows too much about “personal” data or actions of its children, time to extract a container.

In fact, benchmarks have shown that more connected components generally leads to better performance than fewer connected components.

In general, try to find a balance between understandable data flow and areas of responsibility with your components.

最上位のコンポーネントのみを接続する必要がありますか、それともツリー内の複数のコンポーネントを接続できますか?#

初期のReduxのドキュメントでは、コンポーネントツリーの最上部近くに接続されているコンポーネントはごくわずかである必要があるとアドバイスされていました。ただし、時間と経験から、このようなコンポーネントアーキテクチャでは、一般に、すべての子孫のデータ要件について多くのことを知るためにいくつかのコンポーネントが必要であり、紛らわしい数の小道具を渡す必要があります。

現在推奨されているベストプラクティスは、コンポーネントを「プレゼンテーション」または「コンテナ」コンポーネントとして分類し、接続されているコンテナコンポーネントを適切な場所に抽出することです。

    Reduxの例で「上部にある1つのコンテナコンポーネント」を強調するのは間違いでした。これを格言として受け取らないでください。プレゼンテーションコンポーネントを分離しておくようにしてください。都合の良いときにそれらを接続してコンテナコンポーネントを作成します。同じ種類の子にデータを提供するために親コンポーネントでコードを複製していると感じるときはいつでも、コンテナーを抽出する時間です。一般に、親が「個人」データや子供の行動についてよく知っていると感じたらすぐに、コンテナを抽出します。

実際、ベンチマークによると、接続されているコンポーネントが多いほど、接続されているコンポーネントが少ない場合よりもパフォーマンスが向上します。

一般に、理解できるデータフローとコンポーネントの責任範囲のバランスを見つけるようにしてください。

ただ一方で、この考え方は Atomic Design とは真っ向から相対するものとなっています。

そのため【Atomic Design のみを採用するケース】【Atomic Design と Presentational and Container Components を採用するケース】【Presentational and Container Components のみを採用するケース】など、採用するルールによって設計は変わってきます。

レガシーと知りつつも自分が 1 つの Container Component から流し込むケースを採択するのは、以下の理由によるものです。

  • 1 画面を複数の Container Components から構成するベストプラクティスが見つけられていないため
  • Atomic Design を採択したいため

React であれば、たとえば上位の Container Components で動的なデータを取得し、Context によって子コンポーネントに流し込むことも可能です。

また hooks で動的なデータを取得することも容易になってきましたし、近年はかなり柔軟な設計が可能となっています。

とはいえそれゆえにコンポーネントやデータフローのルールが曖昧となり、なんとなく適当な粒度で開発に至っているプロジェクトは決して少なくありません。

上記の Redux の説明にも書かれていますが、1 つの Container Component から動的なデータを子に流し込むケースが絶対的に正というわけではありません。

結局ケースバイケースとしか言いようがなく、きちんとしたルールのもとにデータフローがルールとして決められれていればそれで OK だと思います。

フロントエンド開発にフォーカスしすぎず、Web デザイナーやバックエンドディベロッパーとの連携を意識した上で設計のベストプラクティスを追い求めることも非常に重要です。

きちんとしたルールが定められないのであれば本エントリー通りレガシーでもベタな設計を行うことを強くオススメします。