AtomicDesignについて深掘りする
前回のスクラップでAtomicDesignをそのままコンポーネント設計に当てはめてもうまくいかない(そもそもそういうものじゃない)ことはわかったが、有用とされている記事・書籍もあるためもっと深掘りしてみたい。
まずはこちらの書籍を読んでみる。
ReactでAtomicDesignを適用したコンポーネント設計手順が紹介されているので、ポイントをこのスクラップに残しながら読み進めていく。コンポーネントベースのメリット
- 複雑なUIも確実に組み立てられる
- しっかりとコンポーネントごとに分けられたUIの機能は再利用性が高い
- 多くの画面に対して少ないコードで実装できる
- 再利用性が高いコンポーネントは、統一された使い勝手をユーザーに提供できる
- 画面別ではなく機能別に分けられたUI設計が複数人の並行実装を実現し、開発速度がアップ
- テストがしやすい
複雑なUIを確実に組み上げる
互いが複雑に作用し合うUIは意図せずバグを産む。
(あるUIの機能を変更したら別のUIが動かなくなった、レイアウトが崩れた)
コンポーネント化されたUIが個別で不具合なく動作することがテストされていれば、それを正しく使ったアプリのUI品質も保証できる。
堅牢なUI開発を実現する
コンポーネント単位でテストできる
アプリの品質を担保するためにコンポーネントベースのUI開発が持つ最も重要なポイント。
UIはアプリに組み込まれるとアプリの状態に左右されてしまうので単体でテストすることが難しい。
コンポーネント化されたUIであればアプリの状態に依存せず単体でテスト可能。
適切に分割された小さな実装であれば必要なテストケースも少なく、テスト項目も作りやすい。
不具合のリスクポイントを減らすことができる
一般的に書くコードの量が減ればバグの量も減る。
再利用可能なコンポーネントを作成することで全体のコード記述量を減らすことができる。
また、コンポーネントの量が増えれば増えるほど新規画面の作成も早くなり、開発速度が上がる。
メンテナンスがしやすくなる
UIに変更を加えた際に影響を受ける範囲がコンポーネント内に留まる。
解決する問題を小さくすることで不具合発生リスクを減らす
複雑なコードより簡単なコードの方が不具合発生リスクは低い。
一つ一つのコンポーネントが単純な問題を解決するために作られているのであれば、実装の難易度も低くできる。
結果として可読性も高まり不具合が生みづらくなる。
見た目に関わる問題を解決するコンポーネントの場合、デザイナー自身がCSSを変更して見た目を変更することもでき、コミニュケーションコストを削減できる。
開発作業を効率化する
再利用で実装量を減らす
再利用しやすいコンポーネントを作ることは開発速度向上に直結
並行開発で待ち時間を減らす
画面単位の開発ではなくコンポーネント単位の開発だと、1画面に必要なUIを複数人で並行開発することも可能。
コンポーネントはアプリから切り離されているため、他のタスクに依存せず開発可能。
仕様変更による手戻り作業を効率化する
画面単位でUI開発していた場合、画面仕様に変更があれば手戻りが発生する。
小さなコンポーネントを積み上げて大きな部品を開発する方式だと、仕様変更によって影響を受ける画面自体に依存したコードは少なくなる。
また大きな部品ほど後から作られるので、仕様変更のタイミングでまだ画面自体の実装に着手していない可能性もある。
新規参入開発メンバーを最短で戦力化する
コンポーネント内で使用する技術スタックだけ知っていれば開発可能なので、サービス背景についての知識は概要だけで良い場合もある。
複数のテスト・アプローチでテスト工数を下げる
コンポーネントがアプリに依存しない環境で単体実行できるので、さまざまなアプローチでのテストが可能。
複数アプリケーションの開発を容易にする
UIコンポーネントが部品としてアプリから分離できる形になっていれば、別のアプリでコードを再利用することが可能。
仕組み次第では複数アプリから同じコードを参照して、全体のメンテナンスコストを下げることもできる。ただし、コードを変更したときの影響範囲がかなり大きくなるので、より堅牢な運用が必要となる。
ユーザーメリット
多機能アプリのユーザービリティ向上
アプリが多機能になるとたくさんのUIを画面に表示するため複雑になる。
あるUIコンポーネントが別の画面で使われていたとしても、そのコンポーネントが同じである限りユーザーはすでにそのUIコンポーネントの使い方を知っているため、すぐにその機能を使い始めることができる。
コンポーネントが持つ4つの特徴
カプセル化されている
コンポーネントを使いたいとき、インターフェースだけ知っていれば内部の実装を気にしなくて良い。
置換可能である
インターフェースさえ同じであれば違うコンポーネントに差し替えることができる。
再利用可能である
再利用可能なコンポーネントは、そのコンポーネントがになっている責務に対して過不足なく機能を提供している。
「過不足なく」というのは意外と難しい。特にありがちなのが機能を過剰につけてしまうこと。
ある画面の文脈では必要な機能でも、別の画面では邪魔になることもある。
コンポーネントの責務を常に意識し、再利用性を損なうことがないようにすることが大切。
組み合わせて別の大きなコンポーネントを作成可能である
再利用性が十分に高いことの裏付け。
一つ一つのコンポーネントは小さな問題しか解決できないが、大きな問題を小さな問題に分割し適切なコンポーネントに振り分ける役割を持つコンポーネントを作れば、それ自体が大きな問題を解決するコンポーネントになる。
コンポーネント設計のポイント
単一責任の原則
コンポーネントが責任を持つ問題は1つにするべき。
ソースがシンプルになることで可読性が向上する。
ソース変更時の影響範囲が明確になることで保守性が向上する。
関心の分離
アプリの機能変更時、コンポーネントの機能が目的別に分離されていれば、変更したい目的を担当するコンポーネントだけを修正すれば良い。
コンポーネントの分割基準を考える
AtomicDesignではコンポーネントの分割基準は示されていない。
簡単な分類方針が示されているだけ。
そのためコンポーネントをどの層に分割すべきかの具体的な基準は自分たちで決める必要がある。
階層の依存関係を整理する
AtomicDesignは階層化アーキテクチャと捉えることができる。
上位層は下位層に依存するが、下位層から上位層へは依存しない。
全てのコンポーネントの責務がどこかの層に属するように設計する。
一つの層は共通性がある責務を持ったコンポーネントの集合体として捉えることができる。
デザイン視点で関心の分離を考える
階層化アーキテクチャでは 責務(関心)に応じて層を設計するので、関心の分離が重要。
UIデザインはユーザーがUIを通してどのように行動してほしいかをデザインすること。
意図するユーザーの行動とデザインすべき対象(UIデザインにおける関心ごと)それぞれをAtomicDesignで階層化する。
行動プロセス | デザインすべき対象 | 階層 |
---|---|---|
画面全体から情報を探す | 画面全体のレイアウト | Templates |
興味を引くコンテンツを見つける | ユーザーの行動を促すコンテンツの見せ方 | Organisms |
コンテンツに促されて行動する | 行動を阻害しない操作性 | Molecules |
全体を通してサービスに良い印象を抱く | デザインの統一性 | Atoms |
pagesはコンポーネントが所属する層ではなくプロダクトそのもの
階層化のメリット
アプリ開発におけるUIデザインはトライ&エラーを繰り返すが、階層化アーキテクチャはメンテナンス性が高くトライ&エラーしやすいので相性が良い。
全体を考慮する必要がなく1つの層の責務に関わる課題だけに集中できる
例えばユーザー分析の結果ユーザーが欲しい情報を見つけられていないことがわかった場合、「画面全体のレイアウト」に問題があるためTemplates層のコンポーネントに集中して解決案を考えれば良い。
同一層で代替可能
階層が責務によって分割されているので、あるコンポーネントで解決できない問題があった場合、同一層の別コンポーネントに差し替え可能。
コンポーネントのバリエーションが作りやすくなるのでA/Bテストも行いやすい。
下位層のコンポーネントは変更に強い
アプリのUIデザインにおいて変更頻度が高いのはTemplatesやOrganismsなどの上位層。
階層化アーキテクチャでは下位層は上位層の変更に影響を受けないように設計されるので、上位層でトライ&エラーを繰り返しても変更箇所は最小限に留められる。
Atomsを設計する
あらゆるUIコンポーネントの最小単位。
Atoms以外4つの粒度のコンポーネントは全てAtomsに分解できるように設計する。
AtomicDesignにおいて最も大切な粒度。
Atoms層はそれ以上UIとしての機能性を破壊しない最小要素になるように分割する。
Atoms層でコンポーネント化したほうがよいものは以下の4つのカテゴリー。
- プラットフォームのデフォルトUI
- プラットフォームのデファクトスタンダードなUI
- レイアウトパターン
- セマンティック(意味を付加するような)デザイン要素
プラットフォームのデフォルトUI
WebアプリならHTMLが提供している要素の多くはAtoms層のコンポーネントとして扱える。
HTMLのデフォルトUIにオリジナルの見た目を定義するCSSを一緒にコンポーネント化したものをAtoms層に作っておくと、再利用性とトンマナの統一性を同時に再現可能。
例
-
ボタン
・クリックした時に何らかの処理を開始する機能
・処理を開始するためにクリック可能な範囲を視覚的に表現する機能
これらの機能を分割するとボタンのUIとしての機能性を破壊してしまうので、ボタンはAtoms層に分類するUIコンポーネントと言える。
どんな処理をするかまでは含めない。それを含めると「それ以上機能的に分解できない最小単位」ではなくなる。 -
テキストインプット
・キーボードなどを通してテキストデータを入力する機能
・クリックしたときに入力を開始するトリガー機能
・入力されたテキストデータをユーザーへのフィードバックとして表示する機能
・入力されているテキストデータを外部から取り出すためのインターフェース -
テキスト
・任意の情報(テキスト)を表示する
プラットフォームのデファクトスタンダードなUI
バルーン・バッジ・カードなどユーザーがすでにUIの機能や意味を瞬時に理解できるものについても、アプリに依存する機能ではないので、Atoms層としてコンポーネント化しておくと、再利用性とトンマナの統一性を同時に再現可能。
レイアウトパターン
UIのレイアウトパターンも機能として考えることができる。
レイアウトは特定のコンテンツに依存しないのでAtoms層のコンポーネントとして作成すると良い。
セマンティック(意味を付加するような)デザイン要素
画面上の要素に意味を付加する(セマンティックな)デザイン要素もAtoms層としてコンポーネント化すると良い。同じ意味を持つコンテンツに常に同じ見た目をデザインすると、見た目を通してすぐ意味が理解できる。
例
-
見出し
アプリのトンマナを統一するために、見出し要素はAtoms層としてコンポーネント化 -
本文
ユーザーに極力違和感を与えてはいけない存在。行間や行送りの幅、背景色に対して弱すぎず強すぎないコントラストの文字色、書体などがページごとで統一されていないとユーザーが違和感を感じる。確実にコンポーネント化しておきたい。
記事本文デザインとその他の文字デザインを区別せず、単純なテキスト表示コンポーネントとしてひとまとめに扱う場合もあるかもしれないが、その場合でもこれらのポイントは意識する必要がある。 -
コンテンツ画像
「コンテンツがそこに存在していることをユーザーに知らせる」という責務を持つ。
テキストが表示されてから画像が表示されるまでの間を繋ぐ機能(Progress, プレースホルダー)をコンポーネントに含めることもある。
これらのデザインが統一されていることで、ユーザーは画像の存在を迷わず知ることができる。 -
デコレーションや区切り線
特定のエリアに意味を持たせるために使われる。ペーパーなど。見た目と意味を一貫させるべき。 -
アニメーション
UIアニメーションと呼ばれるUIの操作性を補助するための機能。
「あるUIの状態から次のUIの状態に遷移する際のコンテキストを説明する」機能を持つ。
動作を統一させておくべき。
デザインの統一感を支える
上記は全てデザインの統一感に直結するもの。
同じアイコンが画面によって異なる機能を表現していたらユーザーは混乱する。
サービスのブランディングという観点においても、トンマナが統一されていることは重要。
全てのUIの基礎であるAtoms層のコンポーネントが、統一されたデザインコンセプトに従っていることが重要。
Moleculesを設計する
Atoms層のUIコンポーネントを複数組み合わせて作る
ユーザーの動機に対する機能を提供する
Atomsは最大限抽象化されており、機能としても「ボタンをクリックする」「テキストを入力する」といったもので、ユーザーがどんな動機でそれを行うのかは考慮していない。
Moleculesでは「何のために」ボタンをクリックするのか、「何のために」テキストを入力するのか、機能を組み合わせてユーザーの具体的な動機に応える機能の単位でUIをコンポーネント化する。
例
-
検索フォーム
「何かキーワードで検索したい」という動機に応える場合、Atomsの例に上がったもののうちテキスト、テキストインプット、ボタンの3つを組み合わせて作成する。
Atomsでは非常に抽象的だった各コンポーネントがかなり具体的な役割を担うことになる。
コンポーネント名 | Atomsの時の機能 | 検索フォームでの機能 |
---|---|---|
テキスト | 任意のテキストを表示する | 何が検索できるのかの説明を表示する |
テキストインプット | 任意のテキストを入力する | 検索したいキーワードを入力する |
ボタン | クリック時に任意の処理を開始する | 検索を開始する |
Moleculesのデザインを統一するには
Moleculesが担うのはユーザーが意識してやりたいと思っていることに対して機能を提供すること。
Atomsが提供する「ボタンをクリックする」「テキストを入力する」といった機能は、それ自体がユーザーがやりたいことではなく、やりたいことを実行するための手段でしかない。
ユーザーがMoleculesを通してやりたいことを簡単に行うためには次の2点を満たす必要がある。
- 以前に使ったことがある、または、直感的に使い方がわかる形をしている
- 似た形をしたものは常に同じ挙動をする
これを達成するためには、適切で重複することのない抽象的な機能を持ったAtomsが、多くのMolecules内で共有されていることが重要。
Moleculesをユーザーの同期に対する責務でコンポーネント化することで、ユーザーのタスク完遂に対する効率性を最大化する。
Organismsを設計する
Atoms, Moleculesを組み合わせて作るか、もしくはOrganisms自体が別のOrganismsを構成する要素になる場合もある。
独立して成立するコンテンツを提供する
Moleculesはユーザーの関心事に対して機能を提供したが、Organismsはコンポーネントで完結する機能を提供する。
例はインスタのカードをイメージするとわかりやすい。ユーザーのアイコンや名前、フォローボタン、写真、本文などで1投稿記事に関する情報をまとめてえられて1つのコンテンツとして独立することができる。
Organismsは独立してコンテンツを提供するので、この単位で切り取って画面に配置可能。ヘッダー・ヒーローイメージ・投稿リスト・フッターなど。
MoleculesとOrganismsの分け方
どちらに分類するか迷った時は
- Molecules:独立して存在できるコンポーネントではなく、ほかのコンポーネントの機能を助けるヘルパーとしての存在意義が強いコンポーネント
- Organisms:独立して存在できるスタンドアローンなコンポーネント
例として、インスタ投稿のユーザー情報コンポーネントは、投稿記事に含まれて初めて「この投稿をした人のユーザー情報だ」という具体的な情報がわかる。
投稿記事リアクションコンポーネント(いいね、コメントなど)も同様に、記事に含まれて初めて「この投稿記事に対してリアクションする」という具体的な機能を持つ。
Templates, Pagesを設計する
ここからは開発者外とのコミュニケーションで使用するもの。
Pagesはユーザーが実際に触れるプロダクトのUIそのもの。
Templates
ページの雛形。
具体的なデータは持たないが、Organisms, Molecules, Atomsを実際のサービスページ同様に配置する。
Templatesの目的はコンポーネントがページ上で正しくレイアウトされるか確認すること。
具体的なコンテンツが無いのでレイアウト構造のものものの良し悪しに集中して確認可能。
また、レイアウトのほかにもTemplatesが含むコンポーネントがページ全体で適切に連携して動作するかを確認可能。特定のコンテンツに依存した作りになっていないかを確認するために重要。
コンテンツとプロダクトのUIを分離するための大事な層。
Pages
Templatesに実際のコンテンツを流し込んだもの。
実際のコンテンツに影響されるためカプセル化はできず、再利用もできないので、コンポーネントと言えるかも微妙。
Pagesの役割はTemplatesを介してコンテンツやルーティングをコンポーネントに接続すること。
PagesとTemplatesを分離することで、レイアウトデザインをコンテンツから分離できるため、レイアウトテストを効率良く行うことができる。