ygoto3.com

Software engineer at CyberAgent.

Atomic Design を実案件に導入 - UI コンポーネントの粒度を明確化した結果と副産物

ここ半年開発していた動画サービスをベータ版ながらリリースしました(正式リリースは 4 月)。そのサービスの開発において、以前投稿した Atomic Design を採用しました。本記事では Atomic Design を実案件に導入した結果と感想を書いていきます。

Atomic Design の基本的な概念に関して知りたい方は Brad Frost 氏の原文、もしくは私の以前の記事↓を参照できます。

最近よくクリエイターが移住するカナダで Atomic Design を学ぶ

Atomic Design を導入して正解

結論から書くと、今回 Atomic Design を導入したことは正解でした。コンポーネントの粒度を論理的に説明できるガイドラインとして十分すぎるほどの役割を果たしてくれました。

このガイドラインがあることで、デザインに関してさほど関心がない人(たとえばデザインよりもエンジニアリングが好きなフロントエンドエンジニアなど)でも、UI コンポーネントの粒度を考えるフレームワークとなります。

もちろん、Atomic Design でなくても、コンポーネントの粒度を決定する基準が個人の感覚に依存することが避けられれば、どんなものでも構わないと思います。

Atoms や Molecules はデザイン仕様の変化に強い

Atomic Design を導入する目的は、デザイン仕様の変更に強く、再利用性がコンポーネント郡を揃えることです。当然のことですが、粒度が小さく特定のコンテキストに依存しないコンポーネントは少しくらい UI デザインに変更が入ったとしても、そのまま再利用することが可能です。

内製で自社サービスを開発していることもあり、今回のプロジェクトではデザインの変更は日常的に発生しました。そのためコンポーネントは将来的なデザイン変更を見越した上で、現在のデザインカンプ上に見えるコンテキストにできる限り依存しないように注意してコンポーネントを作ることが重要です。

Atomic Design の 5 つのカテゴライズの中で Atoms や Molecules はコンテキストが極めて薄いコンポーネントです。コンポーネントを作る際に常に Atoms や Molecules の粒度で作るとどういうコンポーネントが理想かを意識することが変更に強い UI コンポーネント郡を備えていくことにつながっていきます。

デザイナーに Atomic Design の導入に協力してもらうことの難しさ

ここまで書いてきたとおり、コンポーネントベースの開発はフロントエンドにとってはメリットが多いですが、Atomic Design はその名前の通りデザイン手法なので、導入においてもフロントエンドだけで完結するものではなく、デザイナーに協力してもらうことが不可欠です。(今回のプロジェクトでは、デザインとフロントエンドエンジニアリングは分業でした。)

しかし残念ながら、コンポーネントベースのデザインというのは一般的にマークアップをしないデザイナーにとっては作業しづらいものです。画面上でほかのコンポーネントと一緒にレイアウトされたときに、そのコンポーネントがどのように見えるのかをイメージすることは、かなりベテランで腕の良いデザイナーでも難しいです。

Atomic Design のようなコンポーネントベースのデザインプロセスをデザイナーに協力してもらうのは大きな課題です。

Interface Inventory を開発初期から実践

この課題を解決するために、開発の初期段階から Brad Frost 氏が提唱している Interface Inventory をゆるく実践していきました。

Interface Inventory を実践したと言っても変わったことや難しいことをやったわけではなく、デザイナーには画面ごとのデザインカンプを通常通り作ってもらい、フロントエンドはそのカンプからいきなり画面を実装するのではなく、まず必要なコンポーネントを切り出して、コンポーネントリストを作成しました。

Atomic Design でカテゴライズしたコンポーネントリスト

Atomic Design でカテゴライズしたコンポーネントリスト

このコンポーネントリストは Pattern Lab のように Atoms や Molecules といったコンポーネントの粒度でカテゴライズされた状態で、デザイナーに共有します。(Git 上で例えば master にマージされたら、自動で最新のコンポーネントリストが開発チーム全体で共有されるようデプロイされるようにしておくと良いかと思います。)

デザイナーには次からの画面デザインを考える際、リストにあるコンポーネントを見て可能な場合はそれらを使ってもらうよう協力してもらいます。UI のトーンがブレないようにスタイルガイドを作っているデザイナーの方もいると思いますので、スタイルガイドと同じように使用してもらえると一番良いです。

コンポーネントが再利用できた方が実装工数が減り、コード量も少なくなるためバグも減り、プロダクトのパフォーマンスも上がるのでプロダクトにとってのメリットも大きいので、その点も伝えるのですが、デザイナーにとってはイメージがつきにくい場合もあるので、まずはスタイルガイドと同じように使ってもらうように促すのが一番なのかなと思います。

開発初期はコンポーネントリストの Atoms や Molecules を増やす

前述したとおり、Atoms や Molecules はデザイン仕様の変更に強いので、コンポーネントリストでも Atoms や Molecules を増やし、Atoms や Molecules から Organisms を構成することを意識します。

作ったコンポーネントたちがカテゴリー別に一覧化されていると、粒度のバランスが取れているかを意識しやすくなります。例えば Atoms や Molecules にそぐわない、ある一定のコンテキストに強く影響されたコンポーネントがないかレビューしやすくなります。

デザインカンプからコンポーネントを抜き出すので、実装者はその画面デザインが意図しているコンテキストに非常に影響されやすいです。そのコンテキストの一層下に UI コンポーネントが共通で持っている目的があるはずなので、その共通の目的以上のものが機能に含まれていないかをレビュー時に確認し、適切に Organisms などにコンポーネントを分離することが大切です。

実際に開発中盤以降もデザイン変更が頻発しましたが、Organisms 以上のコンポーネントはその変更により修正が発生しますが、Atoms や Molecules に関しては、ほとんど発生しませんでした。

コンポーネントリストとプロダクトのコンポーネントの同期

コンポーネントリストやスタイルガイドを運用する上で陥りやすい問題として、開発が佳境に入るとコンポーネントリストが更新されないことが多々起こりえます。プロダクトの方に開発の意識が集中しているので、それは当然ですが、コンポーネントリストが常に更新されなければ、いづれデザイナー含めチーム全体がコンポーネントリストを参照しなくなります。

コンポーネントリストを「生きたドキュメント」として保ち続けるために、コンポーネントリストの中のコンポーネントとプロダクトで使われているコンポーネントの実装が同じソースを見ていることが重要です。

今であれば、コンポーネント化を助けるライブラリとして React などを利用できると思います。今回のプロジェクトでは、 React で作成したコンポーネントをコンポーネントリストにもレンダリングしているため、プロダクトのコンポーネントとずれることがありません。

今回のプロジェクトでも、React + alexlande/react-style-guide を利用してコンポーネントリストを作成し、プロダクト上にあるコンポーネントと同期されるようにしました。

正しくコンポーネントを分離すれば、デザイナーが安心してコンポーネントに対してプルリクすることも可能

Atomic Design に限らず、コンポーネントを正しく分離するということは、デザインとして正しく論理的な意味を持ったコンポーネントとして設計することになります。サービス上で統一された正しい意味合いの色が適用されていて、コンポーネント単体が必要以上でも以下でもないマージン情報を持ち、どこにレイアウトされても自分以外を影響することのないように心掛ける必要があります。

スタイルがそのコンポーネント以外に影響しない状況が保持されていれば、アプリケーションの実装全体をそれほど把握していなくても、安心してコンポーネントに変更をかけることができます。それはフロントエンドエンジニアでなくても、デザイナーやほかの職種の人が実装に関わることができることを意味しています。

デザイン変更実装をデザイナー自身がプルリク

頻繁に変更するデザインには、簡単な色やラベリングの変更、余白の調整などが含まれます。これらの変更は作業的にはとても簡単なものですが、デザイナーがデザインカンプに対して変更したものをフロントエンジニアに渡して作業する場合は、そこそこの工数がかかります。

まずフロントエンドが実装したものをデザイナーに確認してもらう作業は二者のコミュニケーションが発生するため、確認が必要なときに他方の時間が空いているとは限りません。簡単な修正なので、デザイナーの確認が必要でないと思っていても、デザインカンプ上では良く見えていたものが、実際に実装されたら調整が必要だったということは多々起こりえます。残念ながら、デザイナーにしか気づけないもの点が存在するのは事実です。

また、実装したものを Pull Request すれば、ほかのフロントエンドエンジニアがレビューすることになると思いますが、その際にレビューできるのはコードに関することのみだったりします。(そして、これらのデザイン修正ではコードに関しては指摘する必要がないことの方が多いと思います。)

上記の 2 点は、デザイン変更に関する実装についてデザイナー自身が Pull Request することができると、工数をぐっと削減できます。デザイナー自身が実装しているため、実装後のデザイン確認作業は 1 者のみで済みます。また、Pull Request に対して、フロントエンドはコードのみをレビューすれば良くなります。

基本的な Git の使い方をデザイナーに学んでもらう必要はありましたが、デザイナーにとっても自分の意図を他人にフィルタリングされることなくプロダクトに反映できるので、デザイナー自身が Pull Request できることは大きなメリットがありました。

Atoms / Molecules / Organisms のみを採用

Brad Frost 氏の Atomic Design では 5 つのカテゴリー( Atoms / Molecules / Organisms / Templates / Pages )が紹介されていますが、今回のプロジェクトでは最初の 3 カテゴリー( Atoms / Molecules / Organisms )のみを管理しました。

今回のプロジェクトでは、Templates のような大きな粒度のものを再利用することがありませんでした。Templates と Pages については、何百や何千とページを量産するような案件の場合はコンポーネントリストなどで管理した方が良いように思いますが、そうでない場合は Atomic Design のカテゴリーから Atoms / Molecules / Organisms だけを採用するのも良いかと思います。

もちろん実際には Templates の役割をしている大きなコンポーネントは存在しているのですが、プロダクト上のみで確認できるだけで事足りるように個人的には思いました。

考え方に名前があると受け入れやすい

Atomic Design の良いところは、名前が分かりやすく、概念的にも難しいところがないことだと思います。(逆に悪いところは、カテゴリーの名前が若干恥ずかしいことかなと思います。「この Molecule が...」とかチームメンバーに言うのは最初は抵抗がありました - これについては t32k さんも予想してましたが。)

今回のプロジェクトでは、チームの半分弱がフロントエンド経験がないメンバーでしたが、Atomic Design の基本的なコンセプトはすんなり取り込めたようでした。

Atomic Design 自体は特に斬新な考え方なわけではなく、従来のコンポーネントを作る上でのふわっとした考え方に面白い名前がついただけですが、名前がついていることで認識の共有が加速する良い例だと思います。

結果

Atomic Design の考え方を借りて、コンポーネントの粒度を決定していった結果、以前より再利用性が高いコンポーネントを作ることができました。もちろん、Atomic Design だけではなく、コンポーネントベースのデザインプロセスに協力してくれたデザイナーのおかげもあります。(今回前向きにコンポーネントベースのデザインプロセスに協力してくれた @pekep に感謝。)

そして、適切なコンポーネントを分離できた結果、デザイナーがデザイン後の開発に参加できるという副産物も得ることができました。

Gilgamesh を使って UI コンポーネントを拡張してみる

UI をコンポーネント・ベースで開発していると、コンポーネントを開発した当初は予期していなかったカスタマイズが必要になることがあります。何でもカスタマイズできるような汎用性を持たせられれば、それが一番良いですが、過剰な汎用性はアプリケーションを不必要に重くするだけです。

しかし、アプリケーション固有の UI コンポーネントをある程度の大きさの粒度で作っている場合、必要十分な汎用性を予測することは非常に難しいことが多いため、必要になった時点で機能的な分岐を追加することが多いです。多くの場合、既存でそのコンポーネントを使っている箇所に影響を与えないように、分岐するためのフラグを要素の属性値として渡します。

ある程度の大きさの粒度というのは、例えば投稿フォームのような複数の input 、button 要素をテンプレートの中に持ち、バリデーションや Ajax などの機能を提供するくらいの粒度を想定しています。例えば、この投稿機能を提供する UI を下記のように使っている場合、

1
<post-form />

postForm コンポーネント

label という属性の値として変更したいラベルのテキストを渡すことで、属性値が設定されていた場合だけデフォルトとは違うラベルに変更できるようにします。

1
<post-form label="まずは試してみる" />

ラベルを変更した postFomr コンポーネント

ただし、変更が必要になったときにこれを繰り返し続けると、次のようなことにもなりかねません。

1
2
3
4
5
6
7
8
9
10
<post-form
label="最初の投稿"
size="small"
skin="dark"
is-followed="true"
stars="12"
limit="1000"
/>

さすがにこの例のような場合はデザイン的にも問題があるとは思いますが、運用を長く続けていると起こり得る自体です。

Gilgamesh

Gilgamesh は、Zhenyu Hou 氏が開発している JavaScript フレームワークを拡張するライブラリ集です。

JavaScript フレームワークを拡張する、とありますが、現在のところサポートしているフレームワークは、AngularJS のみです。今後 Polymer と React もサポートされる予定みたいです。

Gilgamesh には今のところ大きく2つの機能があります。

  1. テンプレート拡張ライブラリ
  2. データソースライブラリ

今回は、1つ目の「テンプレート拡張ライブラリ」としての機能を利用して AngularJS の Directive で作った UI コンポーネントの拡張を試してみます。

Gilgamesh を試す準備

Gilgamesh のリポジトリ を clone してきて、任意の HTML で jQuery と AngularJS を読み込ませた上で下記の script 追加します。

1
2
3
<script src="./adapters/angular/adapter.js"></script>
<script src="./build/Gilgamesh.js"></script>
<script src="./adapters/angular/directives.js"></script>

ちなみに、jQuery を外して実行してみたところ、エラーが出たので現状は jQuery に依存しているのかもしれません。(あまり深く追ってないです。)

Gilgamesh でコンポーネントを作成する

AngularJS の Directive 機能でコンポーネントを作るのとほぼ同様に、Gilgamesh のコンポーネントを作ることができます。Angular モジュール・オブジェクトの directive メソッドを component に置き替えるだけです。

1
2
3
4
5
6
7
angular.module('demo')
.component('postForm', function () {
return {
templateUrl: './template.html',
link: function () {}
};
});

これで下記のように &lt;div post-form&gt;&lt;/div&gt; をマークアップに配置するとこのコンポーネントを使うことができます。

1
<div post-form></div>

postForm コンポーネント

本当は、restrict: 'E' で、Element Derective にしたかったのですが、現時点では &lt;div post-form&gt;&lt;/div&gt; を配置するとエラーが出てうまく動作しませんでした。

コンポーネントのパーツを書き替える

Gilgamesh で作ったコンポーネントに対して、マークアップ側から変更を加えていきます。中止ボタンだけ別の見た目のボタンに変更します。

まず、コンポーネントで使っているテンプレートの中止ボタン要素に役割名を指定します。ここでは cancel という名前を指定します。

1
2
3
4
5
<div class="col-xs-2">
<button class="btn btn-block" ng-click=“user.cancel()"
gm-role="cancel"
>中止</button>
</div>

次にコンポーネントを使用する側で、中止ボタンだけ置き替えたい要素に上書きする記述をします。コンポーネントの要素に gm-tpl-partial という属性を書き加えて、子要素として gm-role="cancel" という属性を付けた要素を記述します。これが中止ボタンを上書きする要素になります。

1
2
3
4
5
<div post-form gm-tpl-partial>
<button class="btn btn-danger btn-block" ng-click=“user.cancel()"
gm-role="cancel"
>解除</button>
</div>

部分的にパーツを上書きした postForm コンポーネント

また、部分的にではなく、テンプレート自体を全体的に別のものにしたい場合は、gm-tpl-partial 属性を設定しないで、下記のようにコンポーネント要素の中身を上書きするだけで UI 全体が上書きされます。

1
2
3
<div post-form>
<!-- ここの記述でテンプレートをそっくり書き替える -->
</div>

コンポーネントのパーツを取り除く

部分的に上書きもできれば、部分的に取り除くこともできます。今度は中止ボタンをコンポーネントから取り除きます。gm-tpl-exclude="cancel" という属性をコンポーネントの要素に追加するとテンプレートで gm-role="cancel" 属性を与えられた要素だけ除外されます。

1
2
3
<div post-form
gm-tpl-exclude="cancel"
></div>

postForm からパーツだけ除外

コンポーネントの外にある要素をコンポーネントのパーツとして扱う

例えば、中止ボタンをテンプレートのマークアップ外に配置したい場合は、Gilgamesh のコンポーネントの外にある要素をコンポーネントのパーツとして扱うことができる機能が有効です。まずコンポーネントの要素に id を設定します。

1
<div post-form id="postForm"></div>

そして HTML の任意の場所に中止ボタンとして機能させたい要素を gm-import="postForm" 属性を加えて配置します。属性値を、先程の id 属性の値と同じにすることで、postForm コンポーネントの外にある要素をコンポーネントの中のものとして扱うことができるようになります。

1
2
3
4
<button class="btn btn-danger btn-block"
gm-import="postForm"
></button>
<div post-form id=“postForm”></div>

コンポーネントの外にあっても、gm-import 属性で紐付けられた要素内は postForm コンポーネントの scope に紐付きます。なので、要素内に書いた Angular 式は postForm のコンテキストで展開されます。

postForm コンポーネントに外部から要素を追加

コンポーネントを拡張する

あるコンポーネントの link に設定した機能を継承して別のコンポーネントを作ることができます。component メソッドで新しいコンポーネントを作るときに extend キーを追加します。値には継承したい親コンポーネントの名前を指定します。

1
2
3
4
5
6
7
8
9
10
11
angular.module('demo')
.component('postFormSubscribe', function () {
return {
extend: 'postForm',
templateUrl: './template.html',
link: function (iScope) {
// postForm の link が先に実行される
iScope.user.subscription = true;
}
};
});

これで postForm コンポーネントを継承して追加で iScope.user.subscription = true; という処理を postFormSubscribe コンポーネントにだけ実行できます。iScope.user.subscription = true; を実行したことにより、postFormSubscribe コンポーネントでは、購読チェックボックスがデフォルトでオンになるようにしました。

postForm コンポーネントを拡張して作った postFormSubscribe コンポーネント

この拡張機能は残念ながら、現時点で自分が試した範囲では link を継承することしかできないようでした。親のテンプレートを継承できるともっと使い道が広がりそうです。

まだプロダクトでは使えなさそうだが...

Gilgamesh のテンプレート拡張機能を試してみました。少しまだバグが多い印象なのでプロダクトにはまだ導入できないと思っています。しかし、予期できなかったけれど、必要になった汎用性を復活してくれるライブラリとして、機会があれば使ってみたいと思っています。

また本記事の内容については、こちらのスライドでも同様の内容を話しています。

Gilgamesh http://sskyy.github.io/Gilgamesh/

Gilgamesh: bring Angular to the next level http://www.reddit.com/r/programming/comments/2s5exu/gilgamesh_bring_angular_to_the_next_level/

最近よくクリエイターが移住するカナダで Atomic Design を学ぶ

こちらは Frontrend Advent Calendar 2014 19日目の記事です。

2014年 12月8日〜12月14日の間、カナダに滞在してきました。目的は12月9日〜12日に開催される Smashing Conference 2014 へ参加するためです。

海外のカンファレンスに参加するのはおろか、海外旅行もしたことがないので、今回1人でカナダに行くということで終始緊張の連続でした。(Frontrend の @hiloki さんが「僕も行こうかな」と言っていたので、心強く思っていたのですが、残念ながら叶わず。)

本記事は、カンファレンスが開催されたカナダという国にまつわるお話を Frontrend の話題を交えながら書きつつ、このカンファレンスで一番楽しみにしていたトピックである「Atomic Design」について書いていきます。

参加の理由

今まで海外カンファレンスなど参加したことがない自分が今回参加を決意した理由は、興味があるスピーカー陣が多くいたことがもちろん1番なのですが、2番目の理由として、今年に入ってからカナダという国そのものに興味を持つようになったからです。

興味を持ったキッカケは、カンファレンス募集期間の前後、立て続けに日本からカナダに移住する Web クリエイター・エンジニアたちに会ったことです。そのうちの一人が、Mr. Frontrend である @t32k さんでした。彼のブログ記事「Webエンジニアからみたフィリピン語学留学」で書いている通り、彼はフィリピンで語学留学した後、現在カナダでエンジニアとして働こうとしています。

アメリカに近いという点でのカナダの魅力

「偶然なのか、なんだか最近多くの人がカナダに行っている気がするな。」となんとなく思っていました。IT 業界でエンジニアとして働いている者であれば、一度はシリコンバレーで働きたいと願う人も少なくないでしょう。だから、アメリカ合衆国で働きたい、というのは分かります。しかし、なぜカナダなのでしょうか。

そんな疑問に答えるかのように、Frog というクリエイターのためのカナダ留学支援団体のサイトにはカナダのバンクーバーについてこんなことが書かれています。

  • バンクーバーはシリコンバレーと時差が同じ
  • Facebook やアマゾンなどの企業が進出
  • カナダで就労して、アメリカの就労ビザを取得したらシリコンバレー就職

なんともアメリカンドリームに近づけそうなカナダの魅力がそこにはありました。もし普通の日本人がアメリカで働きたいと思ったとしても、アメリカの就労ビザ取得は難しく、働きたくても外国人にあたる日本人はなかなか働く許可を得ることが難しいでしょう。それと比較すると、カナダは就労ビザの制度に融通が利きやすいということのようです。

実際、現地で出会った人の中にもいずれはシリコンバレーで働くことを目標にしている人もいました。

カナダ自身の魅力

vancouver

上記のような理由は、カナダ自身というよりはアメリカへのアクセスに対してのカナダの魅力しか示していませんが、実際カナダのバンクーバーに行ってみると、人は優しく、街は綺麗でとても魅力的な国でした。

私は学生時代に約6年アメリカに住んでいた記憶もあって、カナダに着いたとき、街中の標識や店頭の商品を見てアメリカととても似ているな、と感じたのですが、実際に人と触れ合うと(言い方は悪いですが)アメリカのようなドライさはあまり感じられません。むしろ優しさに溢れていました。

たとえばロックが開かなくなった荷物について私が空港の人に助けを求めると「私には開け方が分からない」と言いながらもあの手この手で開けようと頑張ってくれたり、カナダに来たばかりで電車の乗車券の買い方1つ分からない私に通りすがりの人がとても丁寧に買い方を説明してくれたり、気候とは裏腹になんだかとても暖かい国だなと感じました。

そして、移民も多いためか外国人に対して慣れている感じも見受けられます。物価が若干高いところと、気候が寒いところを除けば、日本人にとっても住みやすそうな街に感じました。もちろん1週間しか滞在していないので実際のところは分かりませんが、The Japanese Community in Canada が示すようにバンクーバーの人口の 1.3% が日系であることからも日本人にとっての住みやすさが想像できます。

英語の重要性

カナダで開催されるカンファレンスということもあり、やはりコミュニケーションは英語になります。長く英語を話す機会から離れているので、この点も今回の旅において心配する要因の1つでした。

少し前に、エンジニアミーティング vol.6-4 エンジニアの英語戦略 というポッドキャスト番組でも話があったように、特にここ1、2年はまわりにいるエンジニアが英語を話せるようになる必要性を強く感じてきています。

実際、職場の友人も、English Lunch という呼ばれる英語オンリーで会話するランチを定期的に開いたり、Frontrend の @1000ch が「2014年の振り返りと人気記事まとめ」で触れているように レアジョブ英会話 で毎日レッスンを受けたりしている人がたくさんいます。

私も同様に、生の声を聞ける機会に英語で恐れず話ができることは大事だと今回の旅で思いました。(恐れず、を強調したのは、別に流暢でなくてもコミュニケーションを取ることができれば良いと思っているからです。)私は漠然と開発における技術やワークフロー、考え方など欧米は日本より進んでいるように思っていましたが、実際にカンファレンス参加者と話すと日本で私たちが課題に持っているのと同じような課題を抱えていて、相手の話が身近に感じたり私の話に共感してくれたりするのがとても新鮮でした。

Smashing Conference Whistler

さて、今回参加した Smashing Conference ですが、ウィスラーというバンクーバーから車で2時間程離れたリゾート地で開催されました。(ウィスラーは2010年冬季オリンピック競技が行われたくらいのスキーリゾートなので、正直スキーやスノボというオマケにつられてカンファレンスに参加した、という人もいました。)

参加者は、やはりカナダ人、とりわけバンクーバーから来ている人が多かったのですが、アメリカ人も多くいました。逆に考えると、カナダからアメリカのカンファレンスなどのイベントに参加することもそのくらい気軽なのだろうと感じます。(日本からアメリカのイベントに参加しようと思うとウン十万円と費用がかかるので、この点においては羨ましい限りです。)

Mr. Brad Frost と Atomic Design

今回のカンファレンスで一番楽しみにしていたのは、Brad Frost 氏の Full-day ワークショップを受講することでした。Brad Frost 氏は Responsive Design のパターンやニュースなどを集めたサイト This Is Responsive を公開し、Adaptive Design に関する実用的で深い見識を持っています。

私がこのワークショップを楽しみにしていた理由は、彼がレスポンシブな Web をコンポーネントベースでデザインする方法論として、Atomic Design というものを提唱していて、このワークショップはその考えを学ぶことができる場だったからです。

ここ1年、私は2つのプロジェクトでフロントエンドの開発をしました。どちらのプロジェクトでもコンポーネントベースでの UI 開発を意識してきましたが、コンポーネントをどんな粒度で作るのが1番再利用性が高くなるのか、なかなか明確な基準をチームの中で共有することができないでいました。彼のワークショップを通して、コンポーネント開発に対する考え方を磨きたいと思いました。

ここからは、そのワークショップおよび、カンファレンスの1セッションでもあった Atomic Design について書きたいと思います。

Atomic Design とは

Atomic Design はデザインシステムを作るための1つの手段です。ざっくり言うと UI コンポーネントを粒度に応じたカテゴリーに明確に分ける手法です。Atomic Design では下記のようなカテゴライズのレベルが示されています。

  1. Atoms - 原子
  2. Molecules - 分子
  3. Organisms - 有機体
  4. Templates - テンプレート
  5. Pages - ページ

これらのカテゴリーは上から下に行くにつれて、粒度は大きくなり、抽象度は下がっていきます。下位カテゴリーのコンポーネント(例えば原子)を組み合わせて上位のコンポーネント(分子)を構成するようにデザインを考えていきます。

We’re not designing pages, we’re designing systems of components.

まさに Stephen Hay 氏の上記の言葉にあるように、ページをデザインするのではなく、コンポーネントで構成するデザインシステムです。

特徴的な名称

私が Atomic Design が手段としてとても優れていると思う点は、カテゴリーの名称がコミュニケーション・ツールとしても柔軟なところです。

5つのカテゴリーのうち、原子、分子、有機体に関しては、開発サイドにメリットがあるカテゴリー名です。この3つの名称は、およそ Web デザインには関係が無さそうな名前です。しかし、原子と原子が結合して分子になることから連想すると、コンポーネントを組み合わせて新しいコンポーネントを作り出すという特性をとても正確に表しています。

それに対してテンプレートとページという2つの名称はとても一般的です。前者3つのコンポーネントより具体性が増して、このレベルではクライアントやプロデューサーに見せるアウトプットになるので、彼らと会話するときに余計な違和感を与えることなくコミュニケーションできる名称になっています。

Pattern Lab

5つのカテゴリーを1つずつ説明する前に、Atomic Design を実践するために便利なツールである Pattern Lab を紹介します。Pattern Lab は Brad Frost 氏と Dave Olsen 氏の両名が作ったパターンライブラリかつ静的サイト・ジェネレータです。

パターンライブラリとしては、原子や分子、有機体といったコンポーネントパターンをコードベースで管理することができます。また静的サイト・ジェネレータとしては、ページやテンプレートと言ったサイトレベルのデザインを原子、分子、有機体から生成します。

Pattern Lab は Atomic Design のパターンを作るスターターキットとしてとても優れているので、ここからの5つのカテゴリの紹介は Pattern Lab で説明していきたいと思います。

Atoms - 原子

原子という名前の通り、これ以上分割することができない基本的な要素がこのカテゴリに含まれます。これ以上分割することができない要素なので、ラベルやインプット要素、ボタンなどの HTML タグは原子としてカテゴライズされます。カラーパレットやフォント、アニメーションなどもこれ以上分割することができない要素として原子に含まれます。

1
2
<!-- 見出し -->
<h1>Heading Level 1</h1>

1
2
<!-- ボタン -->
<p><a href="#" class="btn">Button</a></p>

button

原子にカテゴライズされる要素は、基本的に単体では UI として意味を成さないものばかりになりますが、この後に紹介していくカテゴリのコンポーネントも、ここの要素にあてられたスタイルがベースとなっていきます。この要素たちを集めて一覧化すれば、Dan Mall 氏の ELEMENT COLLAGES のような感じで、サイト全体のトンマナを要素レベルで俯瞰できるはずです。

Molecules - 分子

分子もその名の通り、原子がくっついてできる最小の単位です。ラベルやインプット要素、ボタンなどのコンポーネントを合わせて、例えば検索フォームという形にすることができます。原子は単体ではあまり意味をなさないものでしたが、組み合わせることで目的を持ったコンポーネントになることができます。

ただ、このコンポーネントが持っている目的はまだ汎用的なもので、コンポーネントとしての再利用性が5つのカテゴリの中で最も高くなるようにデザインしていく必要があります。これが Atomic Design システムの根幹を担います。この分子をいろいろな UI パーツに上手に組み込むことが Atomic Design のコツとなるように思います。

Pattern Lab では、このように既存で作った原子を組み合わせて分子としてのコンポーネントを作れるように、別のコンポーネントをインクルードすることができるようになっています。

1
2
3
4
5
6
7
8
9
10
11
<div class="block block-thumb">
<a href="{{ url }}" class="b-inner">
<div class="b-thumb">
{{> atoms-square }}
</div>
<div class="b-text">
<h2 class="b-title">{{ headline.short }}</h2>
<p>{{ excerpt.medium }}</p>
</div>
</a>
</div>

molecule

Pattern Lab はテンプレートエンジンとして Mustache を使っており、{{> そのコンポーネントの名前}} という記述でほかのコンポーネントをインクルードすることができます。上記のコードでは、原子のコンポーネントである atoms-square をインクルードしています。原子から分子というように小さいコンポーネントを使って大きいコンポーネントを作っていくことが簡単にできます。

Organisms - 有機体

有機体は原子や分子を組み合わせて、さらに複雑なコンポーネントを構成します。このレベルでは、インターフェースのパーツとして人が意味のある名前を付けるコンポーネントとなります。例えば、ヘッダーやフッター、記事一覧などのパーツが有機体に含まれます。

1
2
3
4
5
6
7
<header class="header cf" role="banner">
{{> atoms-logo }}
<a href="#search-form" class="nav-toggle nav-toggle-search icon-search"><span class="is-vishidden">Search</span></a>
<a href="#nav" class="nav-toggle nav-toggle-menu icon-menu"><span class="is-vishidden">Menu</span></a>
{{> molecules-primary-nav }}
{{> molecules-search }}
</header>

header

Templates - テンプレート

テンプレートはその名前の通りで、具体的なコンテンツを持っていないページのテンプレートです。ヘッダーや記事一覧などの有機体、ページネーションなどの分子をレイアウトして構成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="page" id="page">
{{> organisms-header }}
<div role="main">
<h1 class="section-title">Our Outdoor Blog</h1>
<div class="l-two-col">
<div class="l-main">
{{> organisms-latest-posts }}
{{> molecules-pagination }}
</div><!--end l-main-->
<div class="l-sidebar">
{{> organisms-recent-tweets }}
</div><!--end l-sidebar-->
</div><!--end two-col-->
</div><!--End role=main-->
{{> organisms-footer }}
</div>

Pages - ページ

最後がページです。テンプレートに画像やテキストなどの具体的なコンテンツが流し込まれて完成します。

1
{{> templates-homepage }}

Pattern Lab では、コンテンツは JSON によってテンプレートに適用され、ページとなります。ここではここまで作ってきたコンポーネント現実のコンテンツに耐え得るかを確認します。サンプルテキストやアテの画像ではないコンテンツを流し込んだときにレイアウトが崩れることなく、コンポーネントとして成り立つことができているかをテストするカテゴリーでもあります。

デザインシステムの運用におけるパターンライブラリの重要性

私も過去のプロジェクトで、デザインシステムらしきものを自分で考えて、そのシステムに従ってコンポーネントを管理していました。いわゆるオレオレデザインシステムです。そのデザインシステムで作ったコンポーネントの粒度が適切だったかどうかはさておき、ディベロッパー間で共通言語として使うところまでは上手くいったように思いましたが、コンポーネントを組み合わせて新しいコンポーネントを作成していくため、粒度の小さいコンポーネントに修正が入ったときの影響範囲が分かりづらくメンテナンス性にずっと課題を感じていました。

コンポーネントベースのデザインシステムを運用で実践していくにあたっては、コードのメンテナンス性を保つために最低限下記の機能を持ったパターンライブラリが必要だと思います。

  • 粒度の小さいコンポーネントをインクルードしてより大きなコンポーネントを構成する機能
  • インクルードされる側の粒度が小さいコンポーネントがどこで使用されているかを把握できる機能

「粒度の小さいコンポーネントをインクルードしてより大きなコンポーネントを構成する機能」に関しては、細かいコンポーネントたちを1ソースにまとめるために必要です。やはりコンポーネントに修正を入れるときは1ヶ所だけ修正すれば良い状態が理想です。

「インクルードされる側の粒度が小さいコンポーネントがどこで使用されているかを把握できる機能」に関しては、コンポーネントを削除する時に便利です。長く開発・運用を続けていると、定期的にコードの大掃除する必要に迫られると思いますが、そのコンポーネントを削除してもほかのコンポーネントに影響が出ないか確認できれば不必要なコンポーネントの掃除が容易になります。

Atomic Design 実践用のサポートツールである Pattern Lab は、「粒度の小さいコンポーネントをインクルードしてより大きなコンポーネントを構成する機能」を Mastache を採用することにより実現し、「インクルードされる側の粒度が小さいコンポーネントがどこで使用されているかを把握できる機能」を Lineage という機能で実現しています。

コンポーネントベースでのデザインを実践するときは、どうしてもそのデザインシステムに合ったコンポーネント管理機能を持つツールが必要になります。デザイナー・ディベロッパーは自分のプロジェクトに合ったデザインシステムを採用する必要がありますが、そのデザインシステムをサポートするツールがあるとは限りません。むしろ、ないケースの方が多いでしょう。Atomic Design の場合は、そのデザインシステムに特化した Pattern Lab というツールがすでに用意されていることが、これを採用する強い理由になるように思います。