タイトルは釣り。
ユースケースvsドメイン
ユースケースは「こういう時に使うもの」と言えるもの、ドメインは「この業務知識」と言えるもの。
破綻する理由は、ユースケースとドメインがひとつのコンポーネントで混ざり合ってしまっているから。
まず、ユースケース別なコンポーネントと、ドメイン知識が含まれるコンポーネントは明確に分けるようにするだけでもかなりマシになるはず。
以下は、それをどう実現するかの雑記。
バケツリレーvs状態管理(またはcontext)
propsのバケツリレーのネストの深さや親コンポーネントへのイベント通知のため、状態管理やcontextを使うのは、基本的に悪手になるケースが多い。特定コンポーネントが別なコンポーネントと一緒に利用されていないと使えない状態になるので、密結合になる。
今のところ1番気に入っているアーキテクチャは、ドメインロジックを含むコードをpagesのみに記述し、コンポーネントには一切のドメインロジックを記述せず、propsのバケツリレーにする方法。
バケツリレーのネストが深くなってしまう理由としては、ページ内のブロック単位で安易にコンポーネントを切り出していることで、パーツの依存方向がめちゃめちゃになってしまい、結果としてネストが深くなってしまっているだけで、状態管理やcontextを使っていい理由にはならず、とどのつまりアーキテクチャが良くないからそうなっているものを無理やり動かすために状態管理やcontextを使って繋ぎ止めているだけだろう。
どうしてもcontextを使いたいのであれば、パーツとして共通利用可能なコンポーネントをまず作り、さらにそれを特定ドメインでのユースケースに限定したcontextでラップした新たなコンポーネントを用意し、意図しない共通利用を避けるようにし、このルールをコーディング規約として徹底させる。
この手法の場合の嬉しい副作用として、コーディングできるデザイナーが参加しているプロジェクトで威力を発揮する。デザイナーは共通利用できるコンポーネントのみに手を入れることで不意なロジックの破壊を防げるので、デザイナーが安心して積極的にコーディングに参加できるようになる。
加えて、Storybookを使っているプロジェクトであれば、基本的に特定contextで括られたコンポーネントについてはパーツ単位で見られるようにする必要はないだろう。
CSS設計
CSSは見た目におけるドメイン知識なので、コンポーネントを横断して伝播するような書き方を避ける。そうしないと、特定コンポーネント間の依存系の場合にのみ発生する見た目のずれがでたり、逆に特定コンポーネント間の依存であれば意図した通りの見た目になるのに、別なコンポーネントとコンポジションすると意図した見た目にならならず、しょうがなくワークアラウンドのためコンポーネントにユースケース毎の場合分けしたCSSが混入してしまうと、コードで言う密結合な状態となり、意図しないデザイン崩れが依存系に発生するなどの副作用がきつく、手がつけられなくなる。
対策としては今のところトライ段階だが、CSSセレクタをうまく使う(小結合子 > や、Owlセレクタ * + *)ことで、無駄なマージン定義クラスの爆発的増加を避けたり、意図しない子コンポーネントへのスタイル適用を防ぐような規約にできないか検討している。
Atomic Designをどう捉えるか
社内外問わず、色々な人から「Atomic Designはうまくいかない」という声を聞く。よく話を聞くと、Atomic Designであることがうまくいかない理由ではなく、上記のようなコンポーネントの切り方を誤り発生している依存関係がカオスな状態をAtomic Designのせいにしているだけなのではと最近は思う。大切なのは、依存関係を一方通行にさせること、コンポーネントのコンポジション性を保つことで、それがまもられればAtomic Designでなくても、分割ルールを各プロジェクトや会社で決めてもらえればいいので、分割の手法そのものにこだわる必要はない。
ドワンゴのBCD designや、食べログのアーキテクチャなど、エンジニアを納得させやすいAtomic Design以外のアーキテクチャがある。カオスなプロジェクトに対して最も提案しやすくてことある毎に引き合いに出している程度にはおすすめ。
Figmaとデザイントークン
Atomic Designがうまくいかない理由はエンジニアのわがままやスキル不足であると述べたが、その上段、つまりデザインカンプに問題があるケースがあることもある。
たとえば、ボタンに法則性不明な複数のバリエーションがあったり、Rectangleの間隔に法則性がなかったり、そもそもコンポーネントが使われていないので修正漏れがぽろぽろ起きる、というものだ。
デザインレビューで無駄なボタンのバリエーション爆発が起こっていることは指摘できるが、間隔についてはそこまでチェックしていない現場が多いのではないだろうか。
間隔がまちまちになると、エンジニアがよしなにその意匠を読み取る必要が出てくるため、コミュニケーション齟齬が起きたり、実装コストが高くなるうえ、法則性が見出せないので、変更に弱いDOM構造やCSSスタイリングにせざるを得ないケースに発展する。
もしあなたが感度の高いUIデザイナーでFigmaを使っているのであれば、直ちにFixedなレイアウトをやめて、全てをAutoLayoutベースで作り直すべきだ。
また、、UIデザイナーはデザイントークンにも気を使ってほしい。
figmaを使うことでエンジニアは簡単に指定された色を使っことができるので、デザイナーはさまざまな色を指定してしまいがちだが、その結果、全ての特定の色を変更したくなったタイミングで、全置換になる(Figmaはそれを簡単にできるが、CSSではそうならない)。その色が正しく指定されていれば良いが、カラーパレットからピックした似たような色のバリエーションがあった場合、置換対象から漏れてしまい、色が変わっていないページが爆誕することになる。これはいわばデザインのバグである。
対策として、最低でもフォント・色はトークン化し、可能であれば design lint で不正な値が使われていないか確認する体制をとってほしい。
デザインフレームワークを使っている場合
MUIやVuetifyといったフレームワークを使う場合に気をつけないといけないのはカスタマイズとの兼ね合い。デザイナーの方でガツガツスタイリングしても、ライブラリのほうではそのトークンはカスタム不可能ということが普通にあり得る。
その場合の選択肢としては二つあり、
ライブラリの利用をやめる
カスタマイズ可能な範囲で妥協する
これだけだ。ある程度グロースしていたり、その意匠やuiがプロダクトのブランディングやユーザビリティに不可欠なものでありながらコンポーネントを0から開発するコストが取れない場合は、頑張ってカスタマイズすることも選択肢には入ってくるが、ある程度のカスタマイズまで行くと、スクラッチで開発した方が安上がりになることの方が多い。特にVue系のフレームワークは成熟が進んでおらず、カスタマイズ性に難があるため、早々に諦めた方がいい。
ただし、カスタマイズしすぎると、特定ユースケースに特化したコンポーネントにせざるを得なくなり、コンポーネントのメンテナンス性に問題が起こる。デザインシステムが未整備のプロジェクトでMVPやABテストをやる場合は、デザインもある程度妥協する必要が良いだろう。
このためにも、エンジニアとデザイナーは相互理解しながら双方の妥協点を見出せる関係性を作らなければならない。
まとめ
正直これはMVVMの再発見にすぎない。
強いて言えば、MVVMを拡張したなにか?
Model、ViewModelは技術領域、Viewはプレゼンテーション領域とした時、NextやNuxtのpagesに相当するレイヤーは既存の枠組みだとどこになるのかと考えた時、pagesはActionでありながら、Controllerでもあるのだろうと思う。
ただし技術的な制約で、controllerをactionから引き剥がすことができない(hooksやsetup)ため、Action&Controllerが蜜結合したものとして使うことが必要になる。
そこまでやるならRailsやLaravelのようなフルスタックFWのほうがいいのではと思う方もいると思うが、その通りだと思う。ただし、この思考でエンジニアを規定してしまうと、それはフルスタックにデザイン領域が含まれてしまい、さらに採用が難しくなる。現実的な解として、メンテ性、グロース性、スケール性を考えると、やはりフロントとバックは分けておくに越したことはない。