😎

共通UIライブラリを開発の振り返りや今後の展望

2024/12/27に公開

2024 年もあと少しとなりました。早すぎる…。この 1 年は、ひたすらデザインシステムの UI ライブラリの開発に専念した一年でした。

私が所属する会社には約 40 のプロダクトが存在し、技術スタックも多岐にわたります。このように多様な環境のなかでデザインの統一性を保つため、デザインスタンダードを基盤とした UI ライブラリの開発を進めてきました。

2023 年から PoC フェーズとして調査を進め、今年の 2 月ごろから本格的に始動したプロジェクトは、12 月についにメジャーバージョンリリースを迎えることができました。

この記事では、UI ライブラリの開発を振り返り、やってよかったことやより改善できたこと、そして今後の展望についてまとめています。少しでも、これから社内の UI ライブラリを開発しようとしている方や、興味のある方の参考になれば幸いです。

なお、一般的にデザインシステムでは、ライブラリを普及させたり既存のデザインを置き換えたりと、開発以外の部分も合わせて語られることが多いです。私が所属するチームでもさまざまな取り組みを行っていますが、本記事では開発面に重きを置いて振り返ります。

UI ライブラリの詳細については以前弊社のテックカンファレンスで同じチームの Taiga Kiyokawa さんのスライドをご覧ください。

https://techday.moneyforward-dev.jp/2024/sessions/talk-04/

やってよかったこと

最初に、やってよかったことをいくつか振り返ります。もちろん他にもいろいろありますが、大きく 3 つに絞ってみました。

1. スクラッチからの開発

私たちのチームは、UI ライブラリの開発においてサードパーティ製の UI ライブラリに依存せず、ゼロから実装することにしました。外部ライブラリへの依存を排除することで、バンドルサイズの削減や、ライブラリの実装都合上デザインスタンダードから逸脱してしまうリスクを防ぐ狙いがあります。

また、スクラッチで開発することで内部実装をチーム全員が把握し、責任を持ってプロダクトの開発者に届けられるようになりました。副次的な効果として、React への深い理解を得られたことも大きかったです。通常のアプリケーション開発ではあまり使わない API に触れる機会にもなり、他の UI ライブラリの設計に触れてベストプラクティスを吸収できました。

2. 早い段階からプロダクトに使ってもらった

今年は、UI ライブラリのメジャーリリースに向けてコンポーネントを整備するフェーズでした。コンポーネントの不足や破壊的変更などが頻繁に起こる中でも、早い段階からプロダクトに組み込んでもらえたことは大きな成功でした。

社内で利用される UI ライブラリでは、プロダクトの開発者がユーザーになります。プロダクトチームと早期の段階で関係性を構築することで、ユーザーテストが可能になりました。改善のためのフィードバックはもちろん、スタイリングライブラリやバンドラとの相性で起こる不具合なども早期に発見できました。協力してくださったプロダクトチームのメンバーには感謝しかありません。

早期導入の工夫としては、ヘッダーやサイドナビゲーションなど大きめのコンポーネントを優先的に実装したことが挙げられます。ボタンやチェックボックスなど汎用的に利用されるコンポーネントは置き換え箇所が多い反面、影響度が小さく大きな問題を発見しづらいです。また、プロダクト側にも導入のメリットがそこまで大きくありません。

一方、ヘッダーやサイドナビゲーションといったサービスのイメージに大きく関わるコンポーネントは導入時に得られる統一感が明らかで、実際に使ってもらいやすいものでした。1 つのプロダクトに導入してリリースしたという実績が話題となり、他プロダクトからも自主的に利用していただけたため、フィードバックや不具合報告も増え、早い段階で改善を回すことができました。

3. デザイナーとの連携

今回の UI ライブラリ開発で最も重視していたのは、デザインスタンダードへの準拠です。多くのプロダクトの UI を支えるライブラリがスタンダードに準拠していれば、プロダクトは自然と統一されます。

私たちのチームでは Figma をデザインツールとして使っています。Figma は優秀なツールですが、React コンポーネントとして実装する段階で微妙に再現しづらいデザインや挙動が出てくることがあります。その結果、エンジニア側で実装したものがデザイナーの意図とずれてしまうケースもあり、アクセシビリティに影響が出ることも少なくありません。

そこで、デザイナーとエンジニアが一緒に開発を進める体制にしました。具体的には、コンポーネントごとの意図や仕様をデザイナーからエンジニアに伝える MTG を実施し、コンポーネントが完成したら Chromatic でデザイナーによるレビューを必ず通すようにしています。その結果、デザイナーが意図した挙動をより正確に担保できるようになりました。

4. Panda CSS を利用

詳しい技術選定の経緯はここでは省きますが、UI ライブラリのスタイリングには Zero runtime CSS-in-JS ライブラリである Panda CSS を利用しました。

今後も続々と増えていくであろう React Server Component や SSR を利用するプロダクトでも使えるよう、静的なスタイルを配信する必要がありました。そのうえで開発生産性を落としたくなかったため、Panda CSS を選定しています。

Panda CSS はまだ新しいライブラリですが、機能は充実しており開発でも大いに助けられました。途中で Panda CSS の利用方法が二転三転しましたが、柔軟な API を提供してくれていたおかげでライブラリ自体を根本的に作り直す必要はありませんでした。

より改善できたこと

次に、より改善できたと感じる点を挙げます。

1. 拡張性の不足

先ほどの「3. デザイナーとの連携」でも述べたように、私たちはデザインスタンダードへの準拠を重視してコンポーネントを提供してきました。つまり、プロダクトごとのデザインの差分を吸収せず、定義されたデザイン以外では利用できない仕様としていたため、初期設計でコンポーネントの Props をできるだけ制限していました。

しかし実際には、スタンダードがすべてのプロダクトデザインを網羅しているわけではありません。複雑なデザインや長く運用されている画面ほど、スタンダードだけではカバーしきれない部分があります。そのため、ライブラリを導入しづらいという声がプロダクトチームから多く寄せられました。

当初は、UI ライブラリの導入を機にスタンダードへ準拠したデザインに置き換えてもらう想定でしたが、頻繁に新機能追加が必要なプロダクト開発では、デザインの全面刷新にコストをかけにくい状況もあります。たとえば、Dialog コンポーネントの title を文字列しか受け取れない仕様にしたり、SelectBox コンポーネントにオプションのヘッダーをつけられないようにしていたりと、拡張性を大幅に制限していたのが原因です。

そこで最近では、一部のコンポーネントに「スロットパターン」という仕組みを導入し、Props で任意のコンポーネントを挿入できるようにしました。最低限のスタイルはライブラリで担保しつつ、各プロダクトの既存デザインをある程度活用できるようにすることで、導入ハードルを下げようとしています。今後もこのような制約を見直し、プロダクト側のコストを抑えながら段階的にライブラリを導入できるよう改善していく予定です。

2. 多言語対応の後手

コンポーネントの多言語対応を後回しにしてしまったのは、かなり痛い失敗でした。はじめはコンポーネント内で固定のラベルや代替テキストを日本語で定義していたため、多言語対応しているプロダクトでは利用しづらくなっていました。後から Props で上書き可能にする対応を加えましたが、実装者の負担が増え、不具合のリスクも高まります。

また、デザインスタンダードにはライティングガイドが含まれており、本来は文言も統一したいところです。プロダクトで自由に上書きできる仕様だと、プロダクトごとやページごとに微妙に表現が異なるなどの問題が起きます。

多くのライブラリでは、主要な言語の文言を内部に保持して切り替えられる仕組みを備えています。私たちも早い段階で同様の仕組みを取り入れておけば、ライブラリの利用価値をさらに高められたと反省しています。

React Aria の多言語対応を調査した記事がとても参考になりました。
https://zenn.dev/mehm8128/articles/adv2024-react-aria-i18n

3. スタイリング方針の変遷

前述のとおり Panda CSS を採用したことで、開発途中にスタイリング方法を大きく変更する必要が生じました。

1 つ目は、生成されるクラス名に関する問題です。当初は Tailwind CSS のように単一スタイルごとのクラスを利用していましたが、プレフィックスを付与したことで、HTML の要素に大量のクラスが付与される状態になってしまいました。要素単位でスタイルを上書きできるよう固有のクラス名を付けていたため、クラスが多すぎて探しにくくなるという問題が起きたのです。

そこで、Panda CSS の Config Recipe を使い、それぞれの要素のスタイルをひとつのクラスにまとめる方法に切り替えました。BEM に似た構造のクラス名が生成されるため、HTML の可読性も向上し、要素を特定しやすくなりました。

Panda CSS の二種類のクラスについては以前書いた記事をご一読頂けると嬉しいです。
https://zenn.dev/moneyforward/articles/7184f5b09ab929

2 つ目は、プロダクト側で定義されたスタイルとの競合問題です。これについては別の記事で詳しくまとめていますが、やはり Panda CSS の柔軟な API に助けられ、ライブラリ自体を作り直す必要まではありませんでした。

この問題についてより詳細に書いた記事もご一読ください。
https://zenn.dev/moneyforward/articles/89f5a798ba4def

こうした問題は、UI ライブラリに関する知見不足が原因でした。他のライブラリの事例を調査したり、発生しうるケースを想定しておけば回避できたはずです。しかし実際には予想外の事態はつきものであり、日頃からドキュメントを熟読したり、他のライブラリの設計を学んだりして、柔軟に対応できる力を養うことが大切だと痛感しました。

今後の展望

最後に、今後の UI ライブラリの展望について書いていきます。

1. コントリビューターを増やす

このライブラリは今後長期にわたって利用される想定です。現在は私たちが専任チームとして開発していますが、将来もずっとこの体制を維持できる保証はありません。

そこで、軽微な不具合修正や改善を気軽にコントリビュートできる文化をつくりたいと考えています。現状はプロダクト開発者からフィードバックをいただいても、修正はすべてチーム内で行っています。これでは知見がチーム内にとどまってしまいます。UI ライブラリは汎用的な知識で実装可能ですし、社内のライブラリなので OSS よりもコントリビュートのハードルは低いはずです。OSS へのコントリビューションを練習する場として使ってもらえるよう、心理的ハードルを下げていきたいと考えています。

とはいえ、本ライブラリはデザインスタンダードへの準拠が目的なので、何でもかんでも受け入れると本来の目的から逸脱してしまいます。そのため、修正や改善を受け入れる基準を明確に定義し、コントリビューターが「これはコントリビュートできそうだ」「これはフィードバックだけにとどめておこう」と判断しやすい状態を目指します。

また、コアコントリビューターのコードレビュー負担も懸念しています。品質を担保しようとするあまり指摘が多くなり、コントリビューターのモチベーションを下げてしまうのは本末転倒です。そこで、AI を使ったレビュー補助などの仕組みも検討し、効率的な開発体制を整えていきたいです。

2. コンポーネントの拡張性向上

先述のとおり、現在のコンポーネントは拡張性が制限されており、導入のハードルとなっています。これまではメジャーリリースに向けてコンポーネントをそろえることを最優先にしていましたが、今後はプロダクトへの導入フェーズに入ります。

そのため、スタンダード準拠のデザインで利用できることはもちろん、既存のスタイルをそのまま生かせる柔軟性の高いコンポーネントづくりが求められます。プロダクトチームが大きなコストをかけずに導入できるよう、Props の制限やカスタマイズ性を適切に見直していく予定です。

3. 実践的な利用例の充実

現時点では、Button や CheckBox のようなパーツレベルのコンポーネントや、ヘッダーやサイドナビゲーションといった大きめのコンポーネントを中心に提供しています。しかし、デザインスタンダードには基本的なフォームの組み方や画面全体のレイアウトパターンなど、実際のプロダクトで役立つ情報がまだまだ定義されています。

そこで、shadcn/ui のようなサンプル集の形式で複雑なレイアウトパターンやユースケースを共有し、プロダクト開発者がより簡単に画面を組めるようにしていきたいです。コンポーネントとして提供するのか、ドキュメントやサンプル集として提供するのか、プロダクト開発者が使いやすい形を模索しながら利便性を高めていく予定です。

おわりに

今年一年の UI ライブラリ開発を振り返り、よかったことや改善点を挙げてみました。あくまで一例として参考にしていただければ幸いです。

振り返ってみると反省点も多々ありますが、個人的には非常に勉強になる 1 年でした。何はともあれ、無事にメジャーバージョンリリースを迎えられたのは大きな成果です。来年も頑張っていきます!

GitHubで編集を提案
Money Forward Developers

Discussion