ygoto3.com

Front-end engineer at CyberAgent

フロントエンド視点:デザイナーと協業して作るスタイルガイドの難易度を下げる

前回 Atomic Design を実案件に導入した話で触れたコンポーネントリストを作り始めたとき、個人的にいろいろと学びがありました。

コンポーネントリストやスタイルガイドは、フロントエンドエンジニアとデザイナーが協業して作る必要がありますが、この協業がなかなかうまくいかず、スタイルガイド運用をワークさせるのは難易度が高い印象がありました。

自分自身、今まで携ってきた開発プロジェクトにおいて、うまくワークしたと思えるスタイルガイド作りができなかったのですが、現在のプロジェクトで開発初期からスタイルガイドを作り、リリース後、運用フェーズまでワークさせることができました。

本記事ではフロントエンドエンジニアとデザイナーが協業してスタイルガイドを作り始めるにあたって気をつけたことについて書いていきます。

共通言語としてのスタイルガイド

開発において、スタイルガイドが欲しい理由は、開発中のコミュニケーションにおいて、デザインを言語化できないことが多いからです。スタイルガイドの役割はデザイナー以外の職種にも通じる(デザイン要素に関する)共通言語として働くことです。そしてたぶんメインデザイナーとそれ以外のデザイナー間での共通言語としても働いてくれると思います。

1つの作業を2者で行う場合、2者の間に共通言語がないと、コミュニケーションコストは一気に高くなります。今の職場では、基本的にデザインとフロントエンドエンジニアリングは分業しているので、デザイナーがエンジニアリングを理解するか、エンジニアがデザインを理解するか、いずれかの状況でない限り(もしくはその状況であったとしても)、コミュニケーションコストは高いです。それを下げる意味でスタイルガイドを作ることは開発において大きな意味を持ちます。

スタイルガイドは死にやすい

しかし、たとえ本格的に開発が始まる前にスタイルガイドを作ったとしても、スタイルガイドがプロダクトのデザインで使えるものになっていなければ、いずれ誰からも参照されない状態になってしまいます。

過去に別のサービスを作っていた際、開発速度を上げるため最初にスタイルガイド/コンポーネントリストを定義し、 それを PSD ファイルで管理するようにしました。以降、画面デザインはそのコンポーネントを使って行う手法を試みました。しかし、残念ながらそのコンポーネントをそのまま使うことは少なかったです。

デザイナーがプロダクトの画面デザインを先に行うことなく、プロダクトの画面上で実際に起こる問題に対して、デザイン的な解決を汎用的なコンポーネントに落とし込むことができなかったからです。実際に画面上に定義したコンポーネントを置いたときに、解決すべき問題が解決できないことが頻発しました。

問題の解決を行うに足りるコンポーネントがないと、新しいコンポーネントを別途作るしかないので、コンポーネントは延々と増え続け、管理できなくなり、そのサービスをリリースする頃には誰もスタイルガイドを見ることはなくなっていました。

予想以上に開発初期にスタイルガイドを作ることは難しい

タイトなスケジュールでスタイルガイドを見直す時間もなかったのと、見直すこと自体を開発フローに組み込んでいなかったため、スタイルガイドは作っただけで意味のないものになってしまいました。

レギュレーションをしっかり決めた方が今後のデザインにブレがなくなるだろうという想いもあり、最初からスタイルガイドにいろいろと定義をつめこみすぎたために(そしてその定義が完璧とは程遠いため)、デザイナーも窮屈になってしまったのだと思います。デザイナーが早々にスタイルガイドを参照することをやめてしまっていました。

自分たちが思っていた以上にスタイルガイドを最初から完璧に作ることは難しかったのです。

エンジニア主導だったスタイルガイド作り

そしてエンジニア主導でスタイルガイドを作った点もスタイルガイドが死んでいった要因だったように思います。そのときのデザイナーはスタイルガイドを作ることにあまり利点を感じていなかったように思います。今思えば、自分たちエンジニアも、デザイナーにスタイルガイドの利点を伝えきれていなかったと思うので、当然かもしれません。スタイルガイドがある開発フローに対して成功体験がなかったので、伝えきれるわけもないとも思います。

特に開発初期は、エンジニアが主導になってスタイルガイドを完璧に作ることはほぼ無謀に近いでしょう。これから実際にデザインを考えていくのはデザイナーです。しかし、スタイルガイドを作るというモチベーションはエンジニア側にあることが(少なくとも自分の周りでは)多いように感じます。

スタイルガイドを作るモチベーションがデザイナーよりエンジニア側にある場合、エンジニアは主導になるのではなく、ファシリテーターとして動くように意識すべきだったなと思います。

もろもろの後悔もあって、今のプロジェクトで開発を開始した時、なんとかリリースまで生き続けるスタイルガイドを作ろうと思いました。とりあえずちょっとした成功体験があるだけでも今後の視野が変わりそうだなと。

デザイナー以外でもデザインを判断できる状況を目指す

フロントエンドエンジニアの視点で言うと、デザインに関して、デザイナーしか判断できない事柄が多すぎるのは大きなツラミです。デザイナーしか判断できない状況は、Photoshop や Sketch のデータから読み取れない事柄において、全てデザイナーに判断を仰ぐ必要がある状態です。それはとてつもなくコミュニケーションコストが高いのです。コミュニケーションコストが高いからと言って、エンジニアが勝手に解釈して実装してしまえば、デザイナーに意図に沿わず、結局実装後に修正することになり、更に工数が膨れます。

コミュニケーションコストを下げるためにも、デザイナーの頭の中がプロジェクト全体に共有され、簡単なことであれば徐々にエンジニアでもデザインに関する判断を下せるようになっていけるのが理想です。生きたスタイルガイドがあれば、デザイン要素に関する最低限の判断は誰でもできる状態にすることができます。仕組みによって、判断しなくて良い状況を増やすからです。

そしてスタイルガイドを作る過程では、デザインを論理的な言葉に置き替えていく必要もあるため、その作業をエンジニアが一緒に行うことでデザイナーがビジュアルを通じてユーザーに伝えようとしている意図を言葉で理解する手助けになります。

箱だけスタイルガイドを作る

過去の後悔を踏まえつつ、デザイナーとエンジニアが無理なく協業できる方法を工夫しようと考えました。特にデザイナーに負担が少ないように、できるだけ最初は既存のデザインフローを変えないように心掛けました。

  • スタイルガイドは最初から定義しすぎないようにする
  • 作りながら定義を追加していく

開発開始時はスタイルガイドには何も定義がされていない状態にしました。ただ、これから定義していく項目だけ決めておくことにしました。中身がない箱だけ用意したイメージです。決める項目というのは、一般的な Web アプリケーションに最低限必要そうな要素です。

  • アプリケーションの基本的な背景色や文字色、ボタン色などのカラーコードを今後決める
  • 要素感の余白のサイズやフォントサイズ、ボーダーの幅、角丸の大きさを今後決める
  • UIアニメーションの長さやイージングを今後決める

などです。今後決める、となっているのは、背景色やフォントサイズなどの値はこの時点で決めないからです。この時点では今後決める項目だけを決めます。

このタイミングで挙げた項目のほかにも必要になる項目は出てくるとは思いますが、必要になったときに追加すれば良いと割り切りました。定義する項目の粒度がパターンとして分かる程度にしておきます。こうしておくことで後から追加する項目の粒度も揃いやすくなります。

スタイルガイドのたたきを Sketch で作る

上記の項目を箱として用意し、実際の値としては定義していない状態で、スタイルガイドを Sketch データにします。

スタイルガイド Sketch データ

上の画像で NO SET となっているところが実際の値が定義されていない項目です。この時点で決まっている値があれば定義し、決まっていない、分からない値については無理に決めず、 NO SET としておきます。

そして、Sketch で設定した値を CSS のカスタムプロパティとして設定します。(今回のプロジェクトでは cssnext を使用しているため、カスタムプロパティとして設定しました。Sass や Stylus などでも変数で設定しても良いかもしれません。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
:root {

/* background */
--bg-regular: #000000;
--bg-highlight: #f0163a;
--bg-hover: #191919;
--bg-active: none;

/* background - light */
--lt-bg-regular: #ffffff;
--lt-bg-highlight: #f0163a;
--lt-bg-hover: #fafafa;
--lt-bg-active: #fafafa;

/* font size */
--font-size-xxl: 22px;
--font-size-xl: 18px;
--font-size-l: 16px;
--font-size-m: 14px;
--font-size-s: 13px;
--font-size-xs: 12px;
--font-size-xxs: 11px;

/* font color */
--font-color-regular: #eeeeee;
--font-color-success: none;
--font-color-danger: #f0163a;
--font-color-warning: #f0163a;
--font-color-info: #8c8c8c;
--font-color-link: #6fb900;
--font-color-link-hover: #c5c5c5;
--font-color-active: none;

/* font color - light */
--lt-font-color-regular: #1a1a1a;
--lt-font-color-success: none;
--lt-font-color-danger: #f0163a;
--lt-font-color-warning: #f0163a;
--lt-font-color-info: #8c8c8c;
--lt-font-color-link: #6fb900;
--lt-font-color-link-hover: #c5c5c5;
--lt-font-color-active: none;

...
}

上のコードで none となっているところは、Sketch で NO SET としたところと同じ意味です。定義できている値のみ設定して、定義できていないものはプロパティ名だけ用意しておいて none を設定しておきます。

プロダクトの UI コンポーネントにあてる CSS は基本的にこのカスタムプロパティを参照し、特別な理由がない限り、値をハードコードすることを避けるようにします。

ここで、最初に Sketch でスタイルガイドを作るのは、Sketch から始める方がデザイナーが心理的な障壁なく作業に入りやすいためです。最終的にスタイルガイドは HTML で管理する方がプロダクトのコードと同期しやすいので、本当は Sketch を介さず、最初から CSS のカスタムプロパティと HTML でドキュメント化できると、効率は良さそうにも思います。ただ、ステップをファシリテートするという意味では、Sketch や Photoshop などから始める方が良いように個人的には思い、今回のプロジェクトでは Sketch から始めました。

Interface Inventory を実践しながら箱を埋めていく

ここまでで、今後決める項目は決めることができたので、ここからは項目に実際の値を入れていきます。箱を埋めていく作業です。箱を埋める作業は各画面のデザインカンプを作りながら、必要に応じて進めていきます。

前回の投稿で、Interface Inventory をゆるく実践したと書きましたが、このように、デザイナーにはデザインカンプを通常通り作ってもらいながら、カンプ上で使用した色やフォントサイズなどで、定義していない値を使うたびに適切な項目への値として埋めていくようにしてもらいました。

フロントエンドエンジニアもカスタムプロパティを参照して CSS を書くので、定義されていない値がカンプに出現した場合は、デザイナーと話してその値をどの項目として定義するかを決めてから実装することにします。これを繰り返してスタイルガイドに定義する値を徐々に埋めていくことになります。

デザイナーの中には画面上に色などのデザイン要素を配置するとき、感覚で配置されている方もいると思います。そういったデザイナーとの協業だった場合でも、最初に埋めるべき箱がデザイン要素としての意味を持った名前とともに用意されているので、名前の意味と異なるカラーコードが出てきたら、そのカラーコードを見直すきっかけになります。

そして、既存のどの箱にも適切に入らない値が出てきたタイミングにのみ、新しい箱を用意します。

新規の箱は既存の箱と十分と向き合ってから作る

新しい箱に入れる必要がある新規の値がデザインカンプ上に出現した時に意識したいのが、箱を本当に新規で追加する価値があるのかを再度デザイナーと考えてみることです。今回も、既存の箱に入っている値では本当に画面上の問題を解決することができないのかということをデザイナーと時間をかけて一緒に考えました。

箱が増えるということは、プロダクトを通してのトンマナがブレるリスクがあるだけでなく、UI を通して送るユーザーへのメッセージの種類が増えることになります。基本的にユーザーへのメッセージの種類はシンプルな方が良いので、増やさなくて良いのであれば、それに越したことはありません。意図したメッセージが適切に伝わりづらくなるというリスクが増すからです。

箱は適切な抽象度を意識する

それでも新規の箱が必要になった場合、箱の名前は適切な抽象度を保っているかを注意します。新規の箱は、それが必要になったデザインカンプの画面のコンテキストにすごく影響されて命名してしまうことが多いです。例えば、コメント一覧 UI の画面デザインで新規に必要になった背景色のカラーコードに対する箱の名前を --bg-comment と命名するなどです。

「コメントの背景」という名前では画面の UI 上でどんなデザイン的にどんな働きをするのかが分かりません。もちろん、コメント系モジュールの背景はどんな画面にレイアウトしたとしても同じ色で統一するのであれば問題ないかもしれません。その色がコメントを表す特別な色という意味を持っているということであれば、 --bg-comment という名前も適切かもしれませんが、実際は別の画面になればコメントより目立たせたい要素が別にあるなど、コメント系モジュールであっても、別の色が適切な場合は多いはずです。

その場合はデザイン的な働きを適切な抽象度を持った名前で表現することが大事だと思います。その画面上でユーザーに最も注目してもらいたい要素であれば、 --bg-highlight という名前で コメント一覧モジュールの背景を塗るのが適切でしょう。

新規の箱に具体的な名前をつけて別項目として設定しまうことは簡単です。なので、その誘惑に駆られることは何度もありました。しかし、そうやってつけられた名前は適切な抽象度を持たないため、別の画面では使われない可能性が高くなる上に、別の箱を作る要因になるので、あっという間に人が管理できない個数へと箱が増えてしまいます。

適切な抽象度とは、色でいうと、基本色や強調色、警告色といったアプリケーションにおいて普遍な要素名に対してサービスのキャラクターづけがされた値を設定するようにします。これより具体性が高い要素名は、カンプ上に配置されたコンテキストに強く影響されている可能性が高いので、デザインレビュー時に再度名前の見直しをするようにしました。

サービスにおいてコアバリューに近いものに関しては具体性が高い要素名が適切な場合があるかもしれません。先程の例で言うと、コメント機能がサービスのコアバリューでほかの要素とは完全に差別化し、どの画面にいてもコメントが特別だと分かるように色を一色に統一したい、という場合は具体的な名前が適切でしょう。ただそういった名前は、サービス1つにつき多くても1、2個のように思います。

明パターンと暗パターンの箱を用意する

プロダクトの強調色や警告色など、全ての色は2パターン決めておくとよいです。スタイルガイドは背景色を白で用意することが多いと思いますが、もしプロダクトのベースが白であっても、配置するモジュール郡の中には暗い色のものもあると思います。

スタイルガイドで定義したカラーコードが、これら暗い色のモジュールを考慮していないと、明度差が足りなくて視認性や可読性が下がったりして、強調色が強調色として働かない可能性が出てきます。

そこでスタイルガイドには最初から明るいパターンの背景上に乗るもの用と暗いパターンの背景上に乗るもの用を用意しておき、色系の要素には常に2パターンの箱がある状態にしました。

Sketch 明パターンと暗パターン

CSS のカスタムプロパティも2パターン用意します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* font color - dark */
--font-color-regular: #eeeeee;
--font-color-success: none;
--font-color-danger: #f0163a;
--font-color-warning: #f0163a;
--font-color-info: #8c8c8c;
--font-color-link: #6fb900;
--font-color-link-hover: #c5c5c5;
--font-color-active: none;

/* font color - light */
--lt-font-color-regular: #1a1a1a;
--lt-font-color-success: none;
--lt-font-color-danger: #f0163a;
--lt-font-color-warning: #f0163a;
--lt-font-color-info: #8c8c8c;
--lt-font-color-link: #6fb900;
--lt-font-color-link-hover: #c5c5c5;
--lt-font-color-active: none;

最終的にHTML (というか React と JSX)で作ったコンポーネントリストでは、実際に明るい背景と暗い背景の上にコンポーネントを置いて管理しました。これにより明るい背景では使えるけど、暗い背景ではそのまま使えないコンポーネントを一目で確認できるようになります。

React JSX 明パターンと暗パターン

空き箱を用意することで運用の難易度が下がった

空き箱を適切な抽象度を意識して用意することで、スタイルガイドの運用はうんと楽になりましした。以前は自分の中に、スタイルガイドは(ガイドというくらいなので)UI デザインを先導するものであるべきという意識がありました。先にスタイルガイドがあって、デザインがそのガイドに従って作られるべきと。でも、自分たちはある意味未知のものを創っているのに、それを先導するものを作る難易度はとても高いです。今回は作ってみたデザインカンプからガイドとなるパターンを見つけていく仕組みを緩く作ることで、スタイルガイドが以前よりもワークするようにできました。

今回のプロジェクトでスタイルガイドに助けられた部分は大きいです。スタイルガイドがあることでデザイナーとの会話はしやすくなりましたし、今まで Photoshop や Sketch を通してしかできなかった部分のコミュニケーションを大きく補足してくれました。そしてエンジニアがデザインについてすこし深く考えるためのツールにもなったと思います。

そして「こんな感じでスタイルガイド作っていきたいんだけど」って相談したら一晩で Sketch のテンプレート作ってくれた @pekep に感謝。

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/