Atomic Designってむずくないすか?
なんか、良さそうなのは分かるんですよ。
UI要素を最小単位まで分解して、それを共通化して再利用性を高めて工数減らしていこうぜ!ということなのは分かるんです。
Atomic Design を分かったつもりになる
こちらはDeNAの記事で、単純に「Atomic Design」でググると最初に出てくる記事です。SEOが強め!(2018/07/30現在)
こちらの記事、確かに詳細に書かれているんです。
2016年にこんな記事を書けるなんて、当時口を開けてアホ面で仕事をしていた自分なんかからしたらもう感服するしかないです。
英語の記事しかない中で、最先端なことを書けるDeNAはやっぱりすごいな私は何してんだよって話なんです。
ただ、この記事を、こんな優良な記事を読んだとしても、実際に作り始めると、、、
- ButtonってIconも文字も入ってくるけど、これってAtomsでいいの!?もしかしてMolecules!?
- AccrodionとかPopupとかの挙動はどうなる!?Templatesかな!?Animationsとか作っちゃう!?
- え…Pagesって…いる…?
こんなことを思うと思うんです!
なので、この疑問に対して、デザイナーでもわかりやすいように噛み砕いていきながら個人的見解を述べていきたいと思います!
Atomic Designを読む
Atomic Design ~堅牢で使いやすいUIを効率良く設計する
2018/04に刊行ということで、今、大変人気な本ですよね!(2018/07/30現在)
ただ、この本を読んだデザイナーの方はこんなことを思うのではないでしょうか…
「コード多すぎwwwwww」
そりゃ草ぐらい生えますよ。SNS世代ですもの。
この本は、Reactをベースに書かれていて、そのReactの話が前半を占めているので、挫折するデザイナーが多いと思うのです。
私もReactがめちゃくちゃ分かるわけではないですが、ある程度わかるので、前半とかは結構すらすら読み進めていった感じでした。
ただ、デザイナーの人がReactをできなきゃいけないわけでもないですし、ReactがわからないとAtomic Designを理解できないなんて、そんなのもったいないじゃないですか!!!そうですよね!?!?!?
なので、デザイナーには少し学習コストが高いAtomic Designを、上記で書いた3つの疑問を元に、デザイナーが気になるところであろうところを説明していきたいと思います。
ButtonはAtomなのか、Moleculeなのか
まず一つ目の疑問、ButtonはAtomsとMoleculesのどちらに含めるべきかを考えていきます。
世の中の記事を読んでみたり、なんとなくの感覚的には、いやはやAtomsに入るでしょ!と思うかもしれませんが、前述したものをもう一度思い出していただきたいです。
「ButtonってIconも文字も入ってくるけど、これってAtomsでいいの!?もしかしてMolecules!?」
そうなんです。Buttonには、Atomsとして定義するであろうIconが中に入り込んでくるのです。
さらに「文字」もAtomsにあたるので、Buttonは2つのAtomsをラップするものということになります。
「MoleculesはAtomで構成されるもの」なんて言われていますし、ButtonはやっぱりMoleculesに含まれるのでは?と悩んでしまうわけです!困りました…
そんな中、前述したAtomic Designを読み進めていくと、P74にAtomにしていくにはどう分解すれば良いのかが実は書いてあります。以下、引用です。
つまり、Atoms層は、「それ以上UIとしての機能性を破壊しない最小要素」となるように分割します。
ここで重要になってくるのは**「機能性」**という言葉です。
もともと、今回悩むこととなってしまった原因は「AtomsをラップするものはMoleculeなのではないか?」と考えていたからでした。
しかし、先ほどの引用文を見ると、Atomをラップするとかそういうことは特に関係なく、定義しようとしているコンポーネントが、1つの機能として成立するかどうかがとても重要になってくるということです。
今回例に挙げているButtonというものはどういうものかというと、
「それの中に書かれた文言によって想起できるユーザが期待した処理を、ユーザのクリックアクションによって実施するUI」
であると、私は思うわけです。
回りくどく言いましたが、ボタンの中に「購入する」と書かれていたら、「購入処理」が実施されてくれればいいわけです。
そして、このButtonという機能をこれ以上に分解した時に、それぞれ分解されたものは機能として成立するかどうかを考えていけばよいわけです。ちょっと考えてみます。
- 「文字」だけだと「クリックしたら何かする」という機能が欠如する
- 「矩形」だけが存在し、それがクリックできたとしても、「文字」が入っていない場合はユーザは何ができるかを想起できない
ざっと考えてみてこんな感じでしょうか… 矩形と文字を抜いて考えてみました。
この考えが正しいのかどうか不安なところではありますが、Buttonの機能はこれ以上分解すると機能が破綻してしまう気がするので、これはAtomsとして定義して良さそうです!
実際にReactで書いてみる
めでたし!ということで、それをReactで実際に動くものを作ってみます。
import React from 'react';
const Button = ({ onClick, children }) => (
<button onClick={event => onClick(event)}>{children}</button>
);
export default Button;
かなり簡略的に書いていますが、これを作ると以下のように使えるようになります。
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => (
<Button onClick={event => { alert('こんちは!'); }}>挨拶するよ</Button>
);
ReactDOM.render(<App />, document.getElementById('#App'));
Reactやプログラミングがわからない人のために、上記で書いたコードがどうなっているのか少し丁寧に説明していきます。
まず、Button.jsxに書かれている<button>
というのはHTMLの<button>
として使っていますが、大文字で書かれた<Button>
というのは私が勝手に定義したコンポーネントになります。const Button
という箇所によって、コンポーネントの名前が決まりました。
(Reactで書く<button>
とHTMLで書く<button>
正確には同じものではないですが、ここでは同じものという認識でOKです)
その自身で作ったButtonコンポーネントを<Button>
という形で使っています。これもReactならではの機能です。
その<button>
の中にonClick
という記述を書き、その後ろにHTMLで属性値を入れるのと似た形で自分の好きな処理を入れています。
今回は「こんちわ!」というポップアップが出てくるものを書きました。これは、Button.jsxでonClick
という受け入れる口を作っているから指定できるわけです。<Button onClick={...}>
と書くと...
に書いたものがButton.jsxのonClick
に渡されていきます。
また、<Button>
と</Button>
の間に書かれたものはchildren
に渡されていきます。これもReactの機能となります。
つまり、Buttonは「文言やアイコン」と「クリックされた時の処理」を受け付けられるようになっているということです。
このようにしておくことで、様々な場面でこのButtonという機能を使うことができるというわけです。
機能に対してデザインをしていく
UIというのはユーザとシステムをつなぐものなので、機能と密接な関わりがあります。ある機能をユーザが使えるようにするには、その機能を想起できるようなデザインを考案しなければなりません。
そのデザインを考案したときに、「ボタンという機能を提供するときは、枠線があって角丸な矩形を提供する」というのを決めたときに、このデザインルール以外のデザインを適用されては困るわけです。
しかも、Buttonのデザインをわざわざ何度も考えるのは大変無駄ですし、サイト内全てのボタンのデザインを変えなければならない場合も、ボタンがバラバラにデザインされていたら、一括でリデザインするのも大変です。
なので、そのButtonというコンポーネントのデザインを、HTMLとCSSで作成しておいてしまえばデザインすらも統一できるようになるわけです。
Reactでは<button className="button">
というように書くことができます。
これは、HTMLの<button class="button">
と同じで、Reactだとclass
をclassName
で書かなければならない決まりがありますが、どちらもやっていることは「クラス名をつける」ということです。
なので、<button className="button">
と書いてあれば.button { ... }
というようにCSSを書くこともできます。
このように、機能で分割していくことによって、UIもきれいに分割されて、さらにはデザインまで統一することができるというわけです!!!オトク!!!
AccordionやPopupというようなアニメーション系のコンポーネント
jQuery等でサイトを実装するときは、よく「Accordion」や「Popup」というようなものは実装したのではないでしょうか。
ただ、こういうアニメーション系というか、インタラクション系というか、こういうようなものたちは、Atomic Designにおいてどこに分類すべきなのかイメージが湧きづらいです。
イメージが湧きづらい理由は「実体が無い」から
先に見出しで結論を書いてしまいました。少し掘り下げていきます。
AccordionやPopupは、インタラクションの定義ですよね。
Atoms、Molecules、Organisms、templatesが、AccordionやPopup内のコンテンツになり得ることができ、それらをどのように表示、非表示するかを決めるのがAccordionやPopupになります。
jQueryのプラグインでそれぞれのインタラクションを付与する場合も、コンテンツ自体は自前で作成して、それをポップアップ化したい場合はその自前のコンテンツのDOMに適用されるように少しJSを書いていくなんてことをしたことがある人も多いと思います。
このように、「インタラクションはJS」で「コンテンツはHTMLとCSS」というような従来の正しい知識が影響して、AccordionやPopupのようなインタラクションを定義するようなものはAtomic Designに分類しづらくなっているのではないかと私は考えています。
Buttonコンポーネントを思い出す
AccordionとPopupの話の前に、ButtonコンポーネントはAtomかどうかを考えましたが、その時に引用した文章をもう一度引用したいと思います。
つまり、Atoms層は、「それ以上UIとしての機能性を破壊しない最小要素」となるように分割します。
そう、Atomic Designは機能で切り分けていけばいいのです。
つまり、AccordionやPopupは、機能として分解できるのか否かを考えていけばいいわけです。
AccordionとPopupは以下のような機能です。
- Accordionは、ボタンを押した指定したコンテンツが下に伸びるアニメーションと共に表示されるもの
- Popupは、ボタンを押したら黒や白のオーバーレイの上に中央寄せでコンテンツが表示されるもの
これをさらに分解できるかどうかを考えていくわけですが、「ボタンを押して下にコンテンツが表示される」ことができなければAccordionではないですし、「ボタンを押してオーバーレイの上に中央寄せでコンテンツが表示される」ことができなければPopupではありません。
AccordionもPopupもこれ以上分解する機能が成り立たなくなってしまうので、どちらもこれ以上分解出来なさそうです。
なのでAccordionやPopupはAtomsとして定義して良さそうです!
そして、どんなに実体が無くても**「それ以上分解できない一つの機能」として定義できれば、それはAtomsに分類できる**わけです。
このようなものをAtomsとして定義できれば、インタラクションデザインもサービスで共通化できるようになる上に、リッチなUIを作るのも楽になって一石二鳥です!
そんなAccordionをAtomsとして作成した記事を書いたことがあるので、Reactをやっている方はぜひ!
Context APIを活用して、Reduxのstate管理から外したAccordionコンポーネントを作る
Pagesって…いる…?
最後に、「Pages」の話をしていきたいと思います。
ここは、デザイナーが一番疑問に思いながらも、一番なんとなく解釈している項目な気がしております!
Reduxから「Pages」を知る
Reactというものは「UIを作成するためのライブラリ」なので、実際のデータの管理や、非同期でデータを引っ張ってくるというようなことは、基本的には担当しません。
Reactで作り上げたUIに、データを流し込んでいくことによって初めてページが完成されるのです。
その、流し込むデータを管理するのが「Redux」で、そのデータを流し込む場所がAtomic Designで言うと「Pages」になります。
Pageは、Templateに必要なデータを選んで、それをTemplateに渡して、さらにOrganisms、Molecules、Atomsに流れていくというわけです。
必要なデータとは、Reduxで管理しているstate(ユーザ情報、検索結果などなど)や、stateを書き換える合図をする処理(Action Creator)などが挙げられます。
例えば、Reduxで検索結果20件分のデータを持っていたとしたら、それをPageからTemplateに流し込まれ、その流し込まれたデータはOrganismに流し込まれて、検索結果が表示されることになります。
検索ワードを変えて検索結果の並び順を変更する場合は「ソートするよ!」というstateを書き換える合図の処理を、Buttonコンポーネントまで流し込み、押されたらその処理がButtonコンポーネントにより実施されます。その合図が発行されると、Reduxの検索結果のデータをソートされて、そのデータがまたPageからTemplate、そしてOrganismに流れて、ユーザにはソートした結果を見せることができるわけです。
このようにすることによって、UIの定義とデータのつなぎ込みを依存させないようにできます。
jQueryで書いていた時は、非同期で取ってきたものを出力するためにHTMLの構造もそのJS内に書かなければいけませんでした。
しかし、データの取得とUIの管理を別にしてあげれば、UIの変更とデータ構造の変更を別ファイルとして管理することができ、とてもシンプルになります。
なので、Pagesというものを作って、Templatesにデータを流し込むという考えを作り出しているのかなと私は思っています。
デザイナーも「Pages」を意識することの重要性
Pagesは「データを流し込むためのもの」という風に述べたので、「まぁそういうものなのね」と思っていただいても良いのですが、もう少し「データが流れてくる」ということの重要性についてお話します。
確かに、Pagesというのものは、UIパーツライブラリとしては特に気にする必要はないと思います。
ただ、デザイナーはUIを定義する上で、そのUIにはデータが流れてくることを意識してデザインしたほうが良いです。
例えば、Moleculesとして検索窓を作成した時に、placeholderを外部から受け付けるか、固定で持っておくかは悩みどころです。
サービス内でplaceholderを変えてライブテストを行いたいとか、placeholderを広告として売りたいとか、そういうビジネス要件がある場合は外部から受け付けられるようにした方が良いです。
しかし、そこまで大きくはないサービスで、どちらかといえば表記揺れを起こす方が気になるという場合は、Molecules内に文言を固定で入れてしまったほうが良いでしょう。
Atomic Designは、そのコンポーネントがどこまで共通項として持っておくべきなのか、どこまで外部のデータを流し込めるようにしておいたほうが良いのか、これを常に考えながらデザインすることによって、再利用性が高くて工数のかからないデザインが行えるようになるはずです。
Pagesというものは、「UI」にとっては特に必要はないものですが、「UI」をデザインする上ではとても重要な考え方となってくるので、ここを意識した上でAtomic Designを元にデザインをしていくのが良いのだろうと考えています。
最後に
いろいろと私個人の見解が多いので、正しいかどうかはわからないのですが、この記事を元にデザイナーもAtomic Designの理解が少しでも促進され、デザインの統一化と再利用性向上の両方ができるようになると、ものづくりがとても良い環境になるのだろうなと思っています。
そんな中で、デザインを統一しながら再利用性も高めるような環境を作り上げるには、どうしてもデザイナーもいろいろと分かっていなければいい環境も作れないと思ったので、今回このような記事を書いていました。
これを元に「もっとこうしたほうがいい!」というような意見とか、議論とかが発生したら、さらにより良いものづくり環境ができあがっていく種になると思うので、なにかあればコメント欄に書いてください!
追記
さらに、MoleculesとOrganismsに対してどっちにどっちを属させるべきかを考えた記事をさらっと書いたので、そちらも合わせて読んでみてください。
MoleculesとOrganismsのこと