Atomic Design はなぜ難しいか?どうやって難しさを解消するか
Atomic Design は難しい
Webフロントエンド開発をしている人で Atomic Design を用いた経験がある方に会った時は、必ず 『Atomic Designどうですか?』と聞くようにしています。
大体の方はちょっと苦笑いをしながら『やっぱり難しいですねぇ』とか『試行錯誤しながらで...』みたいなことを教えてくれます。
私もメインの開発をする際に Atomic Design という枠組みを用いています。そして、同様に色々と悩んだのですが、このあたりについて納得がいく解釈ができたと思っています。
そこで、私の思う Atomic Design の難しさや、そう思う原因、どうやってそれを解消するかという点について、https://atomicdesign.bradfrost.com/ を適宜参照しながら共有したいなと思います。
そもそも Atomic Design 何やねん。な方は上述のURLを参照するか、いくつかのエッセンスを解説した日本語の記事があるのでそちらを御覧ください。
Atomic Design を見る2つの視点
Atomic Design はそれを見る人によって大きく2つの視点があると思っていて、そこが難しさの源泉だと思っています。
Atomic Design をうまく運用するには、この2つの視点の折り合いをうまくつけなくてはいけないと思います。
この章ではその2つの視点について記載します。
Atomic Design は ソフトウェアアーキテクチャのためのもの?
『Atomic Designどうですか?』の回答として、『とりえず、Molecules は Molecules に依存させないようにして...』や『Organisms と Molecules の区別が難しいから、依存コンポーネントの個数を原則として考えて...』 みたいなことを聞いたことがあります。
私はWebフロントエンドを中心にソフトウェア開発を専門としている人間で、前述の質問をした相手もおおよそ同じ属性にカテゴライズされる方々です。
ソフトウェアの開発は多くの場面でソフトウェアモジュールの具象・抽象、依存関係、結合度、そして、要件やリソースをイイ感じに調整するための方法を考える必要があると私は思っています。
これをイイ感じにするための手段としてソフトウェアアーキテクチャがあります。
React.js などのコンポーネント志向なライブラリの出現からしばらく経って、なんとなーく『コンポーネントの割り方に規律が欲しいなー』とか『コンポーネント同士の依存関係がぐちゃぐちゃでカオスだなー』と思ったソフトウェア開発者からしたら、 Atomic Design は 『コンポーネントのレイヤードアーキテクチャ』に見えたんじゃないでしょうか?(私にはそう見えました)
(https://atomicdesign.bradfrost.com/chapter-2/ より引用)
したがって彼ら (私達) は、自然とコンポーネントの機能の抽象性や、ソフトウェア的な責務、依存の単一方向性などに注目して Atomic Design を運用しようとします。
つまり、Atoms は抽象性が最も高いソフトウェアモジュールです。抽象性が高く、責任がより限定的であるため、それ単体で成立させたくなります。
そして、Molecules は Atoms より抽象性が低く、より具体的です。Organisms は更に抽象性が低く具体的です。
Webサイトを構築するときは特定のユースケースを実現するためにいくつかのコンポーネントを組み合わせてUIパーツを組み合わせます。多くのUIパーツを組み合わせると言うことは、UIパーツとしてはより具体的になり、ソフトウェア的には多くの責任・場合によってはビジネスロジックを有することになります。
Organisms と Molecules の区別が難しいから、依存コンポーネントの個数を原則として考えて...
この発想は、ソフトウェアモジュールの具体性を依存コンポーネント数で考えていたのかなぁと思います。
この5つのレイヤにエクストラレイヤを追加して考えるという方もいました。
例えば、Utilities
みたいなレイヤを設けて、モーダルの表示とか機能的なコンポーネントをそこに配置するみたいな感じです。もっと言えば、Presentational Component と Container Component の Container Component が含まれるということなのだと思います。
これはソフトウェア開発をする上では割と自然な発想で、これまでもそのようなレイヤを作成しモジュールを配置するということが行われてきたと思います。
ソフトウェア開発者的には Atomic Design はレイヤードアーキテクチャなんだけど、なんだか色々足りなくて自分たちで工夫してより秩序を高める必要があって難しいなぁ感じている人が多いのではないかと思います。
Atomic Design は Design System のためのもの?
https://atomicdesign.bradfrost.com/ では Designing Systems という章から始まります。文書構成的に Atomic Design は Design System のために定義されたと私は理解しています。
すっごい雑に要約すると最初の章 (https://atomicdesign.bradfrost.com/chapter-1/) で以下のような感じで Design System の構築までの動機が記載されていると思います。
まず、紙を模したWebページからスタートしたWebページのデザインから、クライアントサイズ変化に対応するためにレスポンシブデザインが求められました。そうなると全体のデザインじゃなくて、UIパーツのスケールでデザインが合理的になったということがあります。
そうすると、各パーツ間でデザインの一貫性が必要になります。くわえて、たくさんできるUIパーツ共有するための共通言語が必要になります。
これらコンポーネントを整理して、管理・改善するために Design System が必要になる。
そして、これらのUIパーツを整理するための枠組みとして Atomic Design を導入し、階層化という整理方法を使おう。
という流れだと私は理解しています。
つまり、Atomic Desgin は Design System のためのものであり、Design System はコンポーネントを一貫したデザインで構築したり、再利用したり、管理したりするために必要なのだということのようです。
2つの視点で共有できる1つの観点
前述したようにプロダクトに対する見方・関わり方で Atomic Design に求めるものが違います。
結果としてコンポーネントの分割基準やレイヤへの分類が難しく感じたり、齟齬が生じたりするのだと思います。
これを解決するために、それぞれの視点に共通する観点に基づいて各レイヤ読み直せばいいと思いました。観点が共通のものなら基準の構築がより明確になるからです。
ここで、共通する観点はプロダクト (Webサイト) の知識です。
つまり、プロダクトの知識をより多く持っているものはより具体的ですし、比較的多くのビジネスロジックを有しています。プロダクトの知識を持っていないものはより抽象的で、有しているロジックはより一般的なものです。
例えば、それぞれの会社で持っているイメージ、テーマがあり、それぞれのプロダクト (コーポレートサイト、採用サイト、LP、SaaSサービス、ECサイトとか...) ではそれらが一貫して利用されると思います。
これは比較的一般的な知識です (抽象的です)。一方で、コーポレートサイトでは使うけど、SaaSサービスでは使わないUIパーツが存在すると思います。これは特定のプロダクトについてより専門的な知識を有している (具体的である) と言えます。
この認識は、ソフトウェアアーキテクチャを考える場合とデザインを考える場合で矛盾しません。
なので、この知識に沿ってレイヤを分割し、それぞれの興味を適切に各層へ配置するように考えることにします。
ぼくのかんがえたさいきょうの Atomic Design
ここまでの流れを踏まえて 『ぼくのかんがえたさいきょうの Atomic Design』を説明しようと思います。私は普段 Vue.js を使っているので、コード例を出す場合は Vue.js + composition-api の記述を使用します。
Atoms
Atoms は以下の特徴を持っていると考えます。
- 特定のプロダクト (Webサイト) についての知識を持たない
- 基本的な Web UI としての知識 (機能) しか持たない
https://atomicdesign.bradfrost.com/chapter-2/ では、
If atoms are the basic building blocks of matter, then the atoms of our interfaces serve as the foundational building blocks that comprise all our user interfaces.
とあります。これは、前述の理解との相違は特にないと思います。
また、上記の説明とともに以下の例を示しています。
(https://atomicdesign.bradfrost.com/chapter-2/ より引用)
ここで、ボタンやフォームはサービスなどに一貫して定義されたデザインに沿ったものです。そのため、どのようなプロダクトにも利用できるし、利用するべきです。そして、これらのパーツは基本的な知識しか持ちません。
例えば、ボタンは自身がクリックされるものだとは知っているのでそういう見た目をしていますし、クリックされた時にイベントを発行すると思います。(もしかしたらデザインのマイナーチェンジのためにテーマカラーの設定機能があるかもしれません)
ですが、それだけです。自分が検索ボタンとして使われるか、フォームの確定ボタンに使われるかなどは知りません。
知らないということは、何にでもなれるということです。ここに意味を加えることで確定します。
意味を加える方法は、周りに別のコンポーネントを配置することかもしれませんし、ボタンに属性値を設定することかもしれません。ただ、とにかくそれは Atoms の責任ではないです。Molecules 以上で行われます。
Molecules
Molecules は以下の特徴を持っていると考えます。
- 特定のプロダクト (Webサイト) についての知識を持たない
- いくつかのコンポーネントを組み合わせて構成されるような Web UI の知識 (機能) を持つ
- いくらかの複雑性はもつがこれ単体では成立しない
https://atomicdesign.bradfrost.com/chapter-2/ では、
In interfaces, molecules are relatively simple groups of UI elements functioning together as a unit. For example, a form label, search input, and button can join together to create a search form molecule.
とあります。ここで気になるのは、やはり、 relatively simple groups of UI elements functioning together as a unit.
というやや曖昧な表現でしょう。
ここで私は、relatively simple
を『特定のプロダクトの知識を持たない』と読み替えています。
ここでは以下の例を出しています。
(https://atomicdesign.bradfrost.com/chapter-2/ より引用)
いくつかの Atoms を組み合わせて検索フォームを構成しています。重要なポイントは、この検索フォームはなんの検索に使われるかを知らないと言うことです。
SaaS アプリケーションでユーザの検索にも使えますし、ECサイトで商品の検索にも使えます。
一方で、これだけがあっても何が検索できるかわかりません。他の要素が組み合わさって初めて何が検索できるかわかります。
この理由は、このコンポーネントたちは特定の Webサイトに対して十分な知識を有していないためです。
これはデザイン観点では特に問題ないと思いますが、ソフトウェア的には実装に工夫が必要になってきます。
例えば、説明のためにこのコンポーネントがオートコンプリート機能も持っているとしましょう。(持ってても Molecules ですよね?)
その時以下のような実装はNGです。
export default defineComponent({
setup() {
const query = ref("")
const suggestions = ref<string[]>([])
watch(
query,
(q)=> fetch(`/api/autocomplete?query=${q}`)
.then(res => suggestions.value = res.json())
)
return {
query
suggestions
}
}
})
特定のプロダクトで実装されている、オートコンプリートを取得するためのAPIの知識を有してしまっています。
これを解決するためには、例えば以下のようなアプローチがあります (他にもあると思います)。
- オートコンプリートの内容を
props
で受け取り、query
をv-model
として定義する (上位コンポーネントへ責任を移譲) - オートコンプリートを取得する関数のインターフェースのみを規定し上位コンポーネントから注入する (依存性の注入)
このように、この階層までは特定のプロダクトの知識を有さないので、社内の共通 UI ライブラリとしても利用できます。
Organisms
Organisms は以下の特徴を持っていると考えます。
- 特定のプロダクト (Webサイト) についての知識を持つ
- それ単体で Web サイト内で存在できる
https://atomicdesign.bradfrost.com/chapter-2/ では、
Organisms are relatively complex UI components composed of groups of molecules and/or atoms and/or other organisms. These organisms form distinct sections of an interface.
とあります。 These organisms form distinct sections of an interface.
は 『それ単体で Web サイト内で存在できる』という点と合致します。また、『特定のプロダクト (Webサイト) についての知識を持つ』が『それ単体で Web サイト内で存在できる』に必要であることがこれまでの流れからわかると思います。
そのまま読み進めてきただけだと Organisms are relatively complex UI
のところで、 Molecules との違いに悩むことになるのですが (これまで話したことのある人は大体ここについて悩んでました)、『特定のプロダクト (Webサイト) についての知識を持つ』という点を踏まえると、どういう意味で複雑性が高いのかということも含めて理解できるのではないかと思います。
以下のような例が提示されています。
(https://atomicdesign.bradfrost.com/chapter-2/ より引用)
Molecules で出てきた検索フォームにもラベルに 'SEARCH THE SITE' という値が設定されたりする形で プロダクト特有な知識を与えられることで、サイト内のコンテンツを検索できるようになることが明らかになり、独立して利用できるようになっています (サイトのどこに配置されていてもサイト内のコンテンツを検索できることが明らかです)。
一方で、このコンポーネントは特定のプロダクトの知識を十分に有しているため、他のプロダクトではこのヘッダーコンポーネントは利用できません。
そして、知識をもたせることができるので、プロダクト特有のWeb API をコールさせても良いこともわかります (知識を持たせて良いということと、実際にどのような実装にするかは別の話)。
このように、ソフトウェア実装の話は持ち出さずに、Atoms から Organisms までのレイヤの違いを理解することができますし、この理解から、ソフトウェア的な責任をどこに持たせるべきかを導くことができます。
Template / Page
https://atomicdesign.bradfrost.com/chapter-2/ にある通りで、ここからはメタファをやめて、役割が明確な階層になっており、それほど難しさを感じないと思うので割愛したいと思います。
実装上のポイントはあるとは思うのですが、趣旨から外れるので別の機会があれば...
おわりに
Atomic Desgin について、なんで難しいと思うかを自分なりに考えた上で、どのような観点でレイヤを分けるとそれが解消できると思うかを紹介しました。
『ぼくのかんがえたさいきょうの Atomic Design』では、これまでに述べた考えを踏まえてのレイヤの分け方を https://atomicdesign.bradfrost.com/ での説明を照らし合わせながら紹介しました。
ここまで、長々書きましたが、こういう枠組みを考える上で最も大事なことは、関係するメンバーが納得感を持ってその枠組を維持できるかどうかだと思っています。納得をしているからその枠組を維持できるし、維持できるからソフトウェアやデザインに秩序が生まれます。秩序があるからそれを保ちながら枠組を進化させることができます。
なので、『ぼくのかんがえたさいきょうの Atomic Design』を見て、『なんかちげぇんだよなぁ』と思う方がいたら、なんで違うと思うかをしっかりと言語化して自身の開発に活かせていただければいいと思いますし、それができたらこの記事に意味があったのだと思います。
Atomic Desgin に限らず Web フロントエンド界隈では多くのツールや概念が生まれてはそれの良し悪しについて議論されています。そこから何かを選択する必要があるわけですが、『何を使うか』以上に『なぜ使うか』のほうが大事なのだろうなと思っています。
以前に共有した https://zenn.dev/sterashima78/articles/607bcaa644b848 もテスタビリティを高めたいという『なぜ』から出発したものです。
みなさんも『なぜ』を大事にして『さいきょうのかいはつ』を考えてみてはいかがでしょうか。
Discussion