Atomic Design実践において現場の悩みに立ち向かう

#はじめに
**Atomic Designは難しいか？**
この問いに私は「イエス！」と即答します苦笑

私はビジネスSNS「[Goalous](https://www.goalous.com)」のリードエンジニアとして、サービスのデザインリニューアルに取り掛かる際にAtomic Designを導入しました。

サービスのデザインリニューアルの際、私は次のコンセプトを掲げました。

- デザインの世界観・ルールを統一する
- デザインの変更に柔軟に対応する
- コンポーネント修正による影響を最小限にする→堅牢である

これらを実現する方法論がまさにAtomic Designだったのです。

Atomic Designはとてもシンプルなデザイン手法です。
**原子（Atom）**、**分子（Molecule）**、**有機体（Organism）**、**テンプレート（Template）**、**ページ（Page）**の5つのレイヤーに分かれ、最小限のコンポーネントを組み合わせることによってUIを完成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/b37f925f-6792-7da7-33ba-fe6b2d6314ae.png)

Atomic Designの例として私はよく**LEGO**を用います。
LEGOの最小限のパーツは決まっています。しかしパーツを組み合わせることによって無限の可能性があります。
⬇️でも分かる様に同じパーツを用いたとしてもトラック・F1カー普通車のどれでも作ることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/cb7cd0b4-fe77-de9d-caf4-c98184e73cca.png)


ところがAtomic Design実践においては苦難と試行錯誤の連続でした。
Atomic Designはシンプルな方法論ですが実践は難しい！

この記事ではプロジェクトにおいてAtomic Designを導入・実践した時の悩みとそれに対してどう解決しようとしたかを紹介していきます。

■注意

- あくまで一つの解決方法であって全てのプロジェクトにあてはまるわけではありません。
- エンジニアだけでなくデザイナーの方々にも理解できる様に技術に特化しない説明をしています。

#お悩み集
Atomic Designを導入する際、私も含めてデザイナー・エンジニア全員がAtomic Designの知識・経験が無い状況からスタートしました。その前提で読み進めて頂ければと思います。

##コンポーネント各レイヤーの認識が人によって違う
###デザイナーとエンジニアの認識の違い
####Atomとは
まずAtomic Design導入初期にデザイナーとエンジニア間でAtomについての認識が異なりました。
Atomはそれ以上の要素に分割は出来ない原子であり、コンポーネントの最小単位を表します。

Atomic DesignのAtomでよく例に出されるのが以下の様なボタンです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/bf4559bd-0909-8b8a-b517-3fe1ccaf8c62.png" height="60px"/>

しかしこのボタン一つを取ってもデザイナー達にとってみれば「なぜこのボタンがAtom？Moleculeじゃない？」との疑問がありました。
というのもSketchなどのデザインツール上で分かるように、このボタンは角丸の四角形とその中に置くボタンラベルの二つの構成要素から成るからです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/07542591-446a-d619-4856-499a44363d21.png" height="100px"/>

要素を分割出来るのであればAtomではないということになります。
一方でAtomic DesignによればこのボタンはAtomと定めています。

ではAtomic DesignのAtomとは一体何なのか？

私はAtomic DesignのAtomは**該当「プロダクト」内のUIコンポーネントとしてそれ以上分割出来ない要素**を示していると考えます。
このボタンであれば角丸の四角形だけ、もしくはボタンラベルだけでプロダクト内に存在することはありません。
なので最小単位のコンポーネントのAtomになるのです。

そしてここから重要なのが、私の上の回答が正解かどうかは**Atomic Design実践において実はどうでもいいんです**。
Atomic Designとして正しいか間違っているかの議論と結論に価値はありません。
一番大事なのは**チームメンバーが納得し、認識を統一することによってデザインと開発がしやすくなること**です。
強いて言えばチームメンバー皆が合意するのであればそれがプロジェクトにとっての正解です。

プロジェクトの規模やメンバー構成・ビジネス要件が違えば実践方法や認識の合わせ方も違って当然です。
それを無理に「原則がこうだから従え！」とあてはめることは現場にとって苦痛でしかありません。

私のプロジェクトの場合結局どうしたかと言うと、上に挙げたボタンはAtomであり、ボタンを構成するラベルと角丸の四角形もAtomということになりました苦笑
しかしボタンを構成するラベルと角丸の四角形を意識するのはデザイン側に留めます。
開発側が実装するのはAtomic DesignとしてのAtomコンポーネントであり、 構成要素はAtomとして扱わないし意識しないようにしています。

Atomic Designを導入・実践する目的はデザイン・開発両面のクオリティとスピード向上です。
**原則の理解**は大事です。が、**原則の遵守**は目的ではありません。
正解・不正解ではなくプロジェクトにとって最適かどうかの観点で考えてみましょう。

####デザイン時には存在しないファンクショナルなコンポーネント
また見た目だけではなく基本的にデザイナーとエンジニアでのコンポーネントの作り方が違うことに気づきました。
デザイナーはビジュアルとしてのUIコンポーネントを作成します。
しかし実際にアプリケーションに落とし込む時にはエンジニアはビジュアルだけでなく内部の機能も備えたファンクショナルなコンポーネントを作らなければいけません。
ここにデザイナーが作るコンポーネントとエンジニアが作るコンポーネントに差異が生じました

例としてこのような「閉じる」ボタンのAtomがあるとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/1023c786-2afe-8936-ce05-d976d8321f47.png)

具体的には「閉じる」専用ではなく、様々なアイコンと色に対応出来る様に抽象的なAtomコンポーネントとして存在します。

```
<atom-button
  iconName="close"
  size="small"
  color="black" 
  (onClick)="onClose()"
/>
```

「閉じる」ボタンとして使いたければ`iconName`は`close`として情報を渡します。
またボタンをクリックした時はクリックイベント`(onClick)`で親コンポーネントに伝搬するようにします。

Atomic Designの原則に従えば、親コンポーネントはこのAtomを呼び出して任意の場所に配置するだけです。
しかし実際のアプリケーションはコンポーネントを配置するだけでは済まない様々なケースがあります。

以下は記事の投稿フォームで一つの画像を添付した後です。
一般的なサービスであるように、添付画像に重ねて「閉じる」ボタンが配置され、クリックすると添付画像を削除出来ます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/28c9901e-b4f8-73f2-db99-17ade6ac168f.png" height="360px" />

この「閉じる」ボタンだけでも仕様はいくつもあります。

1. 添付された画像の右上にオーバーレイで表示
2. ボタン表示出し分け
    - ファイルアップロード中は非表示でアップロード完了後に表示
    - 記事編集中であれば表示、そうでなければ非表示
3. ボタンをクリックしたら親コンポーネントにクリックイベントを伝えて、添付画像削除処理を行う
4. etc

さてこれらの仕様はどこが責任を負うべきでしょう？
親コンポーネント？それとも上に挙げた`atom-button`のコンポーネントでしょうか？

どちらでもありません。仕様を満たした新たなコンポーネントが必要となります。
なぜか。この仕様はどちらにも依存するものではなく、疎結合として簡易に付け外しが出来るアタッチメントのようなものであるべきだからです。

まず親コンポーネントが責任を負うとしたら、確かにコンポーネント内部に留まるので他のコンポーネントには影響を与えません。
しかし「閉じる」ボタンはプレビュー画像だけではないとしたら？
ドキュメントファイルのプレビューやダイアログなど他のUIコンポーネントで同じ「閉じる」ボタンの仕様があるかもしれません。
そうした場合に同じ処理を複数のコンポーネントに記述しなければならないので非常に冗長です。

また`atom-button`が責任を負うとしたら、コンポーネント開発の崩壊の前兆です:innocent:
Atomはなるべく抽象化したコンポーネントであるべきです。
具体性を持てば持つほど再利用性が低くなり、恐らくデザインは同じだけれども似た様なコンポーネントが乱立することになりかねません。

ただ「閉じる」に限らず他の目的やデザインのボタンがあるかもしれません。
再利用性を考えるなら以下を満たす「オーバーレイ」に特化したコンポーネント作成をおすすめします。

- オーバーレイで親要素の任意の場所に重ねて`atom-button`を表示する
    - 任意の場所は外から指定化(左上、左下、右上、右下等)
- 表示状態を外から与えられるようにする
- `atom-button`のクリックイベントをそのまま親コンポーネントに伝搬する

このコンポーネントをAtom、Moleculeのどちらで扱うかについては、
私のプロジェクトであれば該当のコンポーネントがAtomと
**is**関係であれば同じレイヤーのAtom,　**has**関係であればMolecule
と定義しています。

オーバーレイのコンポーネントは`atom-button`コンポーネントをラップし、より具体性を持たせたものなのでis関係とみなし、現場ではAtomコンポーネントとして作成しています。
が、もちろんこれはやり方の一つなので、Atom、Moleculeのどちらで扱うかはプロジェクト次第です。

一応言っておきますが、前提としてデザイナーが作成したUIコンポーネントはそのまま全て実装します。
そうでなければデザインとの整合性が取れなくなるからです。
ただその上でデザイン時では表せないファンクショナルなコンポーネントを作成する場合はデザイナーとエンジニアの両方に相談して、チームメンバーで認識を合わせながら進めた方が良いでしょう。

###MoleculeとOrganismの違い
Atomic Designにおいて恐らく現場が一番悩むのがMoleculeとOrganismをどう区別をつけるかだと思います。
どこまでがMoleculeでどこからがOrganismなのかは非常に悩ましい点です。
私のプロジェクトでも度々議論が発生しました。

この問題の解決については[Atomic Design の理解 : molecules と organisms をどのように分割するか](https://frasco.io/atomic-design-molecules-organisms-dc937b5989)の記事が参考になります。

つまりコンポーネントが
単体ではページに配置できないヘルパーの役割を果たしているのであれば**Molecule**、
単体でページに配置できる独立したコンテンツであれば**Organism**
になります。

しかし現場ではすぐに別の問題が浮上しました。
AtomとMoleculeの区別のように
is関係であれば同レイヤー、has関係であれば一つ上のレイヤーというルールを
MoleculeとOrganismの区別にも適用してしまうと、ヘルパーの役割にも関わらずMoleculeを所有しているからOrganismになるという矛盾が生じてしまいました。

そこでis-has関係はMoleculeとOrganismの区別には用いない様にして、かつ以下を許容しました。

- OrganismはOrganismを含む
- MoleculeはMoleculeを含む

新たに決めた上のルールによって以前のような「Molecule・Organismのどっちか」議論は格段に減りました。

##Moleculeの肥大化
コンポーネントがどこのレイヤーに位置するのかプロジェクト内で意識が統一され、開発が進むと新たな問題が浮上しました。
それは**Moleculeの肥大化**です。

通常Atomic Designでは各レイヤーの中でMoleculeコンポーネントの量が最も多くなります。
理由はMoleculeの役割がとても幅広いからです。
Atomから構成されており独立したコンテンツでなければMoleculeになります。加えて全体で共通するコンポーネントと機能に特化したコンポーネントが存在するのでどうしても量は多くなり、肥大化しがちです。

ただこのまま肥大化し続けるとどの用途のコンポーネントでどこにあるかが判別しづらくなるという危機感を抱いたので、私はこの問題の解決に取り組みました。

###Functional Molecule(高機能性分子)の誕生
Molecule肥大化問題でメンバーが認識している「どの用途のコンポーネントでどこにあるかが判別しづらくなる」をより突き詰めてみることにしました。
Moleculeは全体共通で使うコンポーネントと機能に特化したコンポーネントの大きく二つに分けることが出来ます。
その区別が付くだけでも開発のやりやすさが変わってくると考えました。
そこで私はいっそのこそMoleculeの中で区別するのではなく、**Functional Molecule(高機能性分子)**という全く新しいレイヤーを作成しました。

Functional Moleculeは機能に特化したMoleculeコンポーネントです。
対してアプリケーション全体で共通使用するコンポーネントは通常のMoleculeとして扱います.

例を挙げると、私のプロジェクトの場合でユーザーへの通知が当てはまります。
私達が開発している[Goalous](https://www.goalous.com)は冒頭で触れた通りビジネスSNSなので、自分の投稿に誰かがコメントした場合以下の様に通知が届きます。
赤枠の通知カードが一つのコンポーネントになりますが、通知機能でしか使用しない機能に特化したコンポーネントなのでFunctional Moleculeに区別されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71113/1c51f0e4-2ac6-054d-eddf-6aea728343b7.png)

こうすることによって全体共通かどうかがすぐに判別出来、コンポーネントの置き場所に迷わなくなったと同時に開発者にとっての検索性も向上しました。


#最後に
繰り返しになりますが、Atomic Design実践においてはAtomic Designとして正しいかどうかではなく、自分達が本当にやりやすい形は何なのか、プロジェクトにとって最適であるかの観点で考えた方が良いです。
Atomic Designはあくまで方法論であって、原則遵守にこだわりすぎるとはっきり言って失敗します。
最終的にはチームメンバー皆が納得することが大事です。
ただ自分達が一度決めたやり方で続けて良いかは定期的な振り返りの実施をおすすめします。

実際に私のプロジェクトでもある程度コンポーネントを作成した段階でMolecule肥大化問題が挙がり、話し合いを設けた結果Functional Moleculeのレイヤーを作成することに決定しました。

実は他にも色々な課題の取り組みはあったのですが、それは気が乗ればまた別の機会で紹介したいと思います:sweat_smile:

もし気になる点や質問、Atomic Designで悩みを抱えていたら気軽にコメントをください。お待ちしてます。