🥺

デザインシステムを育てたい(切実)

2024/12/13に公開

本記事は 株式会社ココナラ Advent Calendar 2024 14日目の記事です。

デザインシステムの構築は難しく、「作る」ではなく「育てる」という発想が大切です。
本記事では、弊社ココナラで進行中のデザインシステム刷新プロジェクトを例に、「なぜ育てる発想が重要なのか」をざっくり掘り下げてみました。

状況として、デザイン定義としての大枠は8~9割方完成に近づいているものの、実装には課題が山積しています。そのうえで改めて「何が難しいのか」を言語化し、どういうスタンスで進めるべきかという指針を社内の関係者(主にWebエンジニア、一部デザイナー)に共有しました。
本記事はその時に書き殴った資料の一部(とは言えほぼ全部だけど)になります。
異論はあるでしょうがそんなもんなんで大丈夫です。


背景・前提

課題

  • 「多角化」のフェーズに足を踏み入れるための横串の必要性
  • デザイン思想の統一
  • アウトプットの統一
  • 車輪の再発明の防止
  • 品質の向上、均一化
  • 生産性の向上
  • 上記を実現するためのシステム化

デザインシステムは難しい

「デザインシステムの育て方 継続的な進化と改善のためのアプローチ」

  • ↑の本を必読書としたい
  • 「作る」ではなく「育てる」という発想
  • なぜ難しいのか?
    • 必要なフェーズに差し掛かっているが、新規プロダクト開発の優先度も高く体制を整えることが難しい
    • 今のところ専任を置いているわけではないため、イニシアチブを取る主体がない(もしくは曖昧)
    • デザインシステムは全体としての開発効率性や品質に貢献するが、構築するには投資が必要という構造的ジレンマを抱える
    • 経営視点で捉えると間接的・中長期的な効果がメインで、直接的・短期的な効果を定量化するのが難しい
    • 各プロダクトの開発者はアプリケーション開発が主眼であるため、全体最適への貢献に対する興味が不可抗力的に薄くなる
    • それらを総合すると各ステークホルダーの行動を促すインセンティブが働きにくい
  • それでもやる意味?
    • 「今」が最もチャンスが大きいと考えるから
    • 時期的な問題
      • デザインシステムを再定義した(v3)
      • 経営として多角化を戦略としている
      • 「第二創業期」と銘打っている
      • 一般論としての失敗例と成功例が揃い始めている
    • 機運的な問題
      • 社内における技術に対する投資の機運が高まっている
      • 「やる気」のあるメンバーが少なからず居る
      • 具体的に会議体や目標が設定されている
      • こういった取り組みは自然消滅しやすい
      • モメンタム重要
    • 効果が大きい
      • 新アプリケーション群への適用可能性が高い
      • 必要チームが3チーム以上存在する

デザインシステムの開発はスタートアップと同じ

  • 正解があるようでないような状況
  • 世の中に出ているあらゆる前例は「彼らのケース」にフィットしたものでしかない
    • 思想
    • フェーズ
    • メンバー
  • 過度な一般化は危険であり忌避すべきもの
  • そもそも全アプリケーションが一般化できるなら全世界がMUI使えば十分
  • スタートアップに必要なのは「模倣」と「特化」の二要素をバランスすること
    • 既に世の中に出ているシステムは思った以上に完成度が高い
    • スタートアップがいきなりその状態を目指すと間違いなく失敗する
    • 大事なのはPMF的な発想であり、ユーザーである自分たちに徐々にフィットさせていくこと
    • 一般論も大事だが独自の要求を見つけていくことの方がもっと重要

実現したいこと

  • ココナラ経済圏のあらゆるプロダクトがスターターキットの一つとして当該デザインシステムライブラリをインストールして使える世界
  • 公開するのが目的ではなく、ユーザーである自分たちが「使って嬉しい」を実現するのが目的
  • 公開するほどの品質は目指したいところであるがあくまでも副次的なものと捉えるべき
  • いくら美しく堅牢でも現場で使えないものはガラクタです

進め方

  • 大事にすべき観点は上述の本に載っているので読むべし
  • プロダクトの開発チームはデザインシステムの実装を目的にするのではなくあくまでもサブ的業務と捉えて良い(優先すべきはユーザーへの価値提供)
  • 例えば、プロジェクトローカルのコンポーネントとして設計・実装し、同じような実装が使われるシーンになったらデザインシステム化するという流れでもOK
  • 一気に全パターンを網羅しようとしなくて良い
  • その代わり、その実装がプロジェクト特化になっていないかをちゃんと見定める
  • ただし、3チーム以上が使いそうなパーツはなるべく実装する(レビュー観点の一つとして捉える)

設計について

特に気をつけるべきポイント

  • 命名
  • インターフェイス
  • 責務(スコープ)

具体と抽象の境界を探る

  • 汎用性とは抽象度の度合いの話
    • 抽象度が高い≒汎用性が高い≒使えるシーンが限定されない
    • 抽象度が低い≒汎用性が低い≒使えるシーンが限定される
  • どちらが良いということではない
    • シーンと用途に応じて判断するべき
    • 汎用コンポーネントの中にも具象は存在する
    • HTMLにも抽象度の高い要素と低い要素が混在している
      • Div>Section>Header>H1
      • ここではそういう視点が重要ということを言いたいだけ
      • Divですべてを完結させることは可能
      • でもセマンティクスを考えると不適切
      • 塩梅が難しい
    • 限定すべきものと開放するべきものは混在しておりどちらが良いという原理的な判断軸はない
      • ネイティブHTMLの拡張コンポーネントは開放した方が良い場合が多い
      • なぜなら汎用性に主眼が置かれることが多いから
        • スタイルのみカスタマイズしたいだけとか
        • ネイティブHTMLのラッパーとして扱う場合が多い
      • だから {...rest} みたいなアプローチは必ずしも悪ではない
      • <Button>コンポーネントは<button /><input type="button" />のラッパーであることが多く、受け入れるpropsを限定すると無限に再定義するpropsが増える
        • 例えば、disableddisabledそのまま受け入れる
      • <IconButton />のようなコンポーネントは<Button />の拡張だが用途をあえて限定する
        • 規約によってはisDisabledのようにしても良い
    • 開放しすぎると無法地帯になるので基本は限定する方向で良い
    • 大事なのは何を意図しているコンポーネントかを明確にすること

UIコンポーネント設計における二軸の視点

  • コンポーネント設計には二軸の大きな視点が必要
    • スタイリングとロジック
    • ReactやVueのコンポーネントはこれらを同時にやるもの
    • スタイリング用途だけのものもあればロジック用途だけのもの、その両方を司るものが混在している
  • ポイントはそのコンポーネントの「責務」を見極めること
    • 責務がわかれば表に露出するべきインターフェイスと隠蔽すべきものの境界がわかる
  • 視点はUI特有だが、考え方は他のシステム設計と同じ
    • 徹頭徹尾、の組み合わせ
    • それぞれの細胞の責務と振る舞いを定義し組み合わせる
    • それだけ

命名、インターフェイス、責務

命名

  • 命名は文字通り「名前」によって「命」を吹き込む行為である
  • コンテキストが重要
    • 「デザインシステムについて」の会話をしている最中に「デザインシステムは」という主語をいちいち付けなくて良いのと同じ
    • そのコンポーネントが持つコンテキストは命名の抽象度を規定する
    • 逆にすべての命名にコンテキストを明示するとかなり冗長になる
      • 例:渋谷とは?
        • 宇宙の天の川銀河の太陽系の地球の日本の東京の渋谷
          • UniverseMilkyWaySolarSystemEarthJapanTokyoShibuya
        • 「Tokyo」というコンテキストが揃っていれば上位概念は端折れる場合がある(渋谷は東京以外にもある)
        • 逆に明示した方が良い場合もあるが明示範囲は限定的で良かったりする
    • 大事なのは他人や将来の自分が見た時に意図が伝わるか、意味が通るか
    • 暗黙的なコンテキストと明示すべき具体を見極めながら判断すべき
    • ディレクトリ名、コンポーネント名、props名(引数名)、変数名…あらゆる命名対象に言える
    • ディレクトリ名
      • ディレクトリ名はコンテキストを規定する。だからディレクトリ設計は重要
      • ローカルコンポーネントはコンテキストが限定されている
        • だからローカルコンポーネントは相対パスとしてアクセスして良くなる
        • import LocalItem from './_components/LocalItem'
      • 変数名も同じ
        • コンテキストが揃っていれば一般用語のみでも意味や用途が推測しやすい
        • input要素のvalue属性が「入力値」を示すのと一緒
        • 仮にdivにvalueがあっても何用途なのかわからない
    • 発想は普通の関数設計と同じ
      • function calculateBMI(weight, height) { ... }
      • 「BMI(体格指数)」を「計算する」というコンテキストがあるため、 weight と height は「何の」重さと高さなのかが暗黙的に表現されている
      • 逆にコンテキストが揃っていない場合はより具体的な名称を明示するべき
    • 命名におけるコンテキストの重要性としてわかりやすい例
      • Hamburger or HamburgerMenu
      • ハンバーガーは「ハンブルガー(ハンブルク風の)」の英語読み
      • ハンブルク(グ)はドイツの地名でしかない
      • 我々が知っている「はんばーがー」は、「ハンブルガーステーキ」→「ハンバーガーサンドイッチ」が語源
      • Hamburgerという単語は静的に一般化されているか?
      • そもそもここで表現しているのは厳密には「三」というメニューボタンの形そのものである
      • ドロワーを含む場合とそうでない場合がある(=コンテキストの一致が必要)
      • 人によってはメニューボタンが「三」的な形でないにも関わらず、ドロワー自体をハンバーガーメニューとして会話する人も居る

インターフェイス

  • 関数コンポーネントにおけるインターフェイスとはpropsのこと(children含む)
  • 関数コンポーネントの前はクラスコンポーネントが主流だった
    • 関数コンポーネントのprops(プロパティ)はクラスコンポーネントのコンストラクタ引数と同義である
    • どちらも親コンポーネントから渡される props を受け取るために使用される
  • つまり使う側から見てそれらが扱う「対象」と「振る舞い」を与えるもの
    • 対象はデータや別コンポーネント
    • 振る舞いは挙動やロジック
  • UIコンポーネントにおけるI/Oは以下
    • Input = props
    • Output = 描画されるHTMLと挙動
  • ディレクトリ設計もある意味インターフェイス設計
    • そのディレクトリに注入すべきデータや振る舞いを規定する
  • インターフェイスのインターフェイスに気をつけよう(ダジャレ)

責務

  • そのコンポーネントが持つ責務を見極める
  • コンテキストを特定(命名)し、インターフェイスを適切に定義することで、そのコンポーネントは過不足ない丁度よい責務を持つ
  • 責務が曖昧だと本来入り込むべきでない知識が入り込む
  • 「見出し」要素にクリックイベントを付けてはならない
  • もし、見出しに何かしらのイベントを購読させたいならそれは「見出し」以外の用途があると考えるべき
  • 例(あえて極端にしているので現実的ではないが)
    • 下記は<Heading>コンポーネントに onClick イベントを持たせてるのではなく、用途を限定した別のコンポーネントとする
    <button onClick={onClick}>
      <Heading>{children}</Heading>
    </button>
    
    • 汎用的に使い回すような用途なら上記を<ClickableHeading />として「振る舞い」に焦点を当ててコンポーネント化する
    • 使うシーンに着目するならシーンに合わせた命名、例えば<ArticleHeading />みたいにする
    • コンポーネント化しない判断も大事
  • 命名は責務範囲を(ある程度)表現することが可能
    • どうしてもすべての単語には解釈の余地が残るため完全でないことに注意

デザイナーとの協業

  • デザイナーとエンジニアの間にはエンジニア<>エンジニアの間よりも大きな情報差分がある
  • 一見、デザインシステムはデザイナーが設計したものをエンジニアが実装するように感じるがそうではない
  • 前述の通り、「育てる」という発想に立てば、お互いがお互いの思考を共有する必要がある
  • 今あるデザイン定義を疑おう
    • 完璧なコードなど存在しないのと同様、デザインにも完璧はない
    • 本当にこの定義は目的に対しての回答となっているのだろうかという疑問を常に持つことが大事
    • もし、疑問に思ったらすぐ確認すること
    • デザイン定義が間違っていることは往々にしてある

番外編

※ デザインシステム構築のような組織横断プロジェクトでは、特にコミュニケーション課題が顕著です。そこで、プロジェクト成功のために欠かせないコードレビューの心構えを改めて確認しました。

レビューにおける注意事項

テキストコミュニケーションの功罪

  • テキストコミュニケーションは「深く」考えてアウトプットするにはとても有用
  • ただし、コミュニケーションにおける「ニュアンス」が剥がれ落ちがち
  • それを補強するために必要な情報量はバカにならない
  • 「ニュアンス」の理解にはコンテキストの共有が必要

コミュニケーションにおけるコンテキスト

  • コミュニケーション一般におけるコンテキストには「何を言ったか」以外にも相当に暗黙的な情報が含まれている
  • 誰が言ったか?
    • どういうバックグラウンド?
    • スキルレベル?
    • 知識量、幅(ドメイン、技術)?
    • 文章のクセ?
  • どういう関係性か?
  • 前提が揃っているか?
  • 目的が共有できているか?
  • どういうつもりで言ったか?
  • どういう受け取り方をするか?
  • 特有の状況にあるか?
    • その時の体調や感情状況
    • 業務の逼迫度合い

これらをいちいち把握しながら進めるのは不可能

  • 関係者が一人増えるごとに指数関数的に難易度が上がる
  • トップダウンによる決定のインセンティブはここにある
  • 多数決はある意味トップダウン的な決定アプローチの一つの手法(「多数意見」を絶対君主とみなす)
  • ルールメイクも同様(ルールを絶対神とする手法)
  • 前提を合わせるためには関係性の構築が必要

どうするとよいのか?

  • 口頭でのコミュニケーションとテキストでのコミュニケーションは組み合わせることが大事
  • コミュニケーション手法は限定しない
    • テキスト、画像、動画、口頭

チーム開発は関係者を一つの脳として動かす行為そのもの

  • 一人ひとりはニューロン
  • 関係性はシナプスの繋がり方
  • 有機的につながるにはコンテキストの共有が重要
  • 世の中にある一般論は各現象を標準化しているものに過ぎないため、その知識を共有しながらも自分たちにあったやり方を模索する必要がある
  • レビュー行為は一つの脳みそが行っているプログラミングの一つと捉えるべき
  • 宗教論争は楽しい時もあるかもしれないが無駄も多い
    • 宗教論争が起こるということは正解が複数あるという こと
    • どちらをとっても所詮結果論でしかない。結果的にその選択で事業が意図通り成長すればそれが正解
    • 一番大事なのは「何で作るか」ではなく「何を作るか」
    • ただし、間違ってはいけないのが「What」ばかりに注目すると「動けばええやん」という発想になるがそれは絶対ダメ
    • 「動けば良い」は短期小規模なら正義の場合もあるが、中長期中大規模になると悪
    • HowがWhatを手助けすることは往々にしてある
      • だから知識大事
  • レビューコメントでのやりとりが長くなりそうになったら口頭で補足しあおう
    • テキストである必要性と口頭の方がスムーズな場合両方あります
    • ちゃんと意識して使い分けましょう
    • もしもしモシモシもっしもし

以上です。

最後に

明日は@tm_1219さんによる、LazyVimの紹介 です。

ココナラでは積極的にエンジニアを採用しています。

採用情報はこちら。
https://coconala.co.jp/recruit/engineer/

カジュアル面談希望の方はこちら。
https://open.talentio.com/r/1/c/coconala/pages/70417

もちろんデザイナーも募集しておりますm(_ _)m
https://note.com/takumitono/n/na7ef0ba0b0db

筆者について

首藤宏朗。株式会社ココナラで自称ハイパーメディアクリエイター見習いとして10年超、ココナラ初期の開発と(全部ではないけど)ほとんどの新規事業サービス(ココナラ法律相談ココナラ募集ココナラテックココナラアシスト、他…)の立ち上げに従事。現在も別の新規事業プロダクトの開発を担当している。社歴マウントなら大体負けない。

過去記事

https://zenn.dev/coconala/articles/82b6117fcb9b59

Discussion