コンポーネントライブラリの「再利用可能」という約束は、具体的にどんな前提の上に成り立っており、その前提はいつ破綻するのですか?
再利用可能という約束は、「このコンポーネントが将来使われる状況が、最初に設計されたときの状況と十分に似ている」という前提の上に成り立っている。この前提は製品の初期段階では通常成り立つ。機能がまだそれほど拡張しておらず、コンポーネントが直面する状況の変化が少ないからだ。しかし製品が成長し機能が増えるにつれて、この前提は徐々に成り立たなくなっていく。もともと最も単純な状況だけを処理すればよかったコンポーネントが、ますます多くの新しいバリエーションに対応するよう求められるようになる。
この前提が破綻する境界点は、通常明確な時点ではなく、段階的なプロセスだ。最初に1つか2つの新しいpropを追加しても問題があるようには感じられないが、あるコンポーネントが十数個から二十個のpropを蓄積し、それらの組み合わせの関係が追いにくくなると、そのコンポーネントは事実上「シンプルで再利用可能な積み木」から「複雑なパラメータシステム」へと変貌しており、その保守コストはすでにひそかに、本来節約するはずだったコストを上回っている。
「30%のコンポーネントが一度も使われたことがない」というのは無駄に聞こえますが、コンポーネントライブラリ自体の設計が悪いということですか?
完全にそうとは言えない。この数字の背後には、別々に判断すべき少なくとも2つのまったく異なる原因がある。1つ目は健全な休眠だ。一部のコンポーネントは確かに特定の状況のために設計されたものの、その状況が後に実際には持続したり広まったりしなかったため、コンポーネントが自然と使われなかった。この場合、使われずに休眠していることはむしろ良いことだ。「あらゆる仮定の状況に対してコンポーネントを作る必要はない」という当初の判断が正しかったことを意味し、無理にこれらのコンポーネントを使わせようとすることこそが本当の無駄になる。
2つ目はコミュニケーションの失敗による休眠だ。コンポーネントは確かに存在し、あるチームが直面している問題を確かに解決できるのに、そのチームがその存在を知らない、あるいは知っていてもそれを使う方法を調べるよりローカルでカスタムバージョンを作る方が早いと感じている場合だ。この2つ目のケースこそが本当に注意を払うべき問題であり、解決策は通常これらのコンポーネントを削除することではなく、発見しやすさを改善することだ。例えばドキュメントで「このコンポーネントはどんな状況に適しているか」をより明確に示す、あるいは似たようなニーズが出てきたときにチームがコンポーネントライブラリを調べようと自然に思いつくような、スムーズな導線を作ることなどだ。
共有コンポーネントを拡張する審査コストが高いなら、いっそ審査を緩め、各チームが自由に共有コンポーネントを修正できるようにすればよいのではないですか?
このやり方は、今とはまったく逆だが同じくらい深刻な問題を生み出す。すべてのチームが共有コンポーネントを自由に修正できるなら、あるチームが自分たちのニーズのためにコンポーネントの挙動を調整した際、知らないうちに別のチームがもともと依存していた使い方を壊してしまう可能性が高い。これこそが、共有コンポーネントに審査の仕組みが必要な理由だ。審査は余計な官僚的手続きではなく、修正が他の利用者に波及して壊すことがないようにするための必要なステップなのだ。審査を完全に緩めることは、「コンポーネントライブラリが現実から乖離する」という問題を「コンポーネントライブラリ自体が不安定で予測不能になる」という問題に置き換えるだけで、根本的なギャップを実際には解決しない。
より現実的なやり方は、審査を撤廃するのではなく、審査プロセス自体を速く、軽量にすることだ。例えば「既存の使い方に影響しないオプションのpropを追加する」ことと「既存の使い方に影響しうるコア機能を修正する」ことに対して、異なる厳格さの審査経路を設計する。前者はより速いプロセスで進められ、後者にこそ完全なチーム横断的な確認が本当に必要になる。こうすることで、日常的に発生する拡張ニーズの大半は速く処理でき、本当にリスクの高い変更だけがそれに見合った審査コストを払えばよくなり、両者が同じプロセスに縛られなくなる。
AIデザインツールで画面を生成している場合、AIの生成速度が速いために、コンポーネントライブラリの肥大化がむしろ深刻化するのではないですか?
深刻化する可能性もあれば、改善する可能性もある。鍵となるのは、生成時に既存のコンポーネントライブラリと照合するよう要求されているかどうかだ。AIが新しい画面を生成する際、既存のコンポーネントライブラリをまったく参照としてインポートしていなければ、毎回統計的に推測して「ボタンのように見える」何かを生成することになる。これは実質的に、コンポーネントライブラリを調べずに毎回自分で新しく作ってしまうメンバーがチームにもう一人増えたようなものであり、しかも人間のエンジニアよりはるかに速いペースで生成するため、肥大化は加速するだけだ。
しかし逆もまた真である。生成プロセスに既存のコンポーネントライブラリを明示的にインポートし、AIに既存のコンポーネントを優先的に使うよう要求し、本当に適切な選択肢が見つからない場合にのみ新規追加を提案させるようにすれば、AIはむしろ怠けることのない監査役を担える。生成のたびに、そのニーズが既存のコンポーネントと既存のprop組み合わせで満たせないかを先にチェックするよう要求でき、毎回まったく新しいものを生成することをデフォルトにしなくて済む。つまり、AIツールの導入によってコンポーネントライブラリの肥大化が悪化するかどうかは、チームが「既存のコンポーネントを先に調べる」という原則を、AIの生成プロセスに明示的に組み込んでいるかどうかにかかっており、自動的に起きる結果ではないということだ。
あるエンジニアが自身のチームでコンポーネントライブラリの監査を行った際、コンポーネントライブラリに依存するすべてのチームが心に留めておくべき一連の数字を発見した。もともと「再利用可能」であるように設計された1つのボタンコンポーネントが、18カ月の間に23種類の異なるprop組合せを生み出し、47の異なる実装に分散していた。バンドルサイズの分析では、チームがコンポーネントライブラリ全体をインポートしているにもかかわらず、実際に使用されているコンポーネントは全体の15〜20%に過ぎないことが分かった。コンポーネントの全体的な採用率は最初の1年後に約67%で頭打ちになり、チームは新しく現れる「エッジケース」に対して、既存のコンポーネントを再利用するのではなく、カスタムの実装を作り続けていた。これらの数字が明らかにしているのは、このチームが特別ずさんだったということではなく、「再利用可能なコンポーネント」という概念自体が、見落とされやすい隠れた前提を含んでいるということだ。
コンポーネントライブラリの核心的な約束は「一度作れば、どこでも使える」ことだが、この約束が成り立つのは、そのコンポーネントが将来使われる状況が、最初に設計されたときに想定していた状況と十分に似ている場合に限られる。しかし現実には、製品機能は常に拡張し続け、新しい使用状況が常に現れる。もともと「テキストとアイコン」を処理するだけでよかったボタンが、次第に「読み込み中の状態」「アイコンを右に配置」「破壊的操作用の赤いバージョン」「モバイルでより大きなタップ領域」を処理するよう求められるようになる。新しい要件は一つ一つ見れば妥当に見えるが、コンポーネントのコア設計がこうした変化を受け入れる十分な柔軟性を残していなければ、結果としてすべての新しい要件が新しいpropになり、積み重なるうちに、もともとシンプルだったコンポーネントは理解しがたいパラメータの組み合わせへと変わっていく。
コンポーネントの採用率が頭打ちになる核心的な理由は、チームがライブラリの存在を知らないことではなく、既存のコンポーネントを拡張するのに必要なコミュニケーションと審査のコストが、まったく新しく書くことよりも時に高くつくという点にある。共有コンポーネントを修正するのに完全なレビューサイクルを経る必要があり、それをすでに使っている他のすべてのチームと調整して既存の使い方を壊さないことを確認する必要がある一方で、ローカルバージョンを書くには自分のチームの了承だけで済むなら、合理的な選択はたいてい後者になる——たとえその選択がコンポーネントライブラリと実際に稼働しているコードとのギャップを広げることになっても。これは「30%のコンポーネントが一度も使われたことがない」という統計が必ずしも悪いニュースではない理由も説明している。それらのコンポーネントの一部は、確かに過剰設計であり、そもそも存続しなかった問題を解決していたのであり、長期間放置されているのはむしろ正しいシグナルだ。しかし別の一部は、単にチームがその存在を知らなかった、あるいは知っていたがカスタマイズする方が手っ取り早いと感じただけかもしれない。
この現象を「コンポーネントライブラリの管理が不十分だ」と単純化してしまうと、解決策は新しいコンポーネントの追加をより厳しく制限し、すべての新規追加をより慎重に審査することだと思い込みやすい。しかし本当の根本原因は、ほとんどのコンポーネントライブラリに継続的なフィードバックの仕組みが欠けている点にある。「エンジニアが実際の状況で既存のコンポーネントでは足りないと感じる」ことが、コンポーネントライブラリ自体の進化に効果的にフィードバックされるのではなく、誰にも二度と見られることのないローカルの回避策へと変わってしまう。このフィードバックループがなければ、コンポーネントライブラリの進化速度は製品の実際の要件の進化速度からどんどん遅れていく。その差こそが、23種類のバリエーションと67%で頭打ちになった採用率の背後にある本当の原因だ。
もしあなたのチームがコンポーネントライブラリを使っている、あるいは構築を検討しているなら、まず問うべき問いは「いくつのコンポーネントを入れるべきか」ではなく、「エンジニアが既存のコンポーネントでは足りないと気づいたとき、それを報告し拡張するプロセスはどれほどスムーズか」だ。もし答えが「完全なレビューサイクルを経る必要があり、数週間待つこともある」なら、コンポーネントライブラリ自体がどれほどよく設計されていても、長期的には上記の事例と同じ運命をたどる可能性が高い。コンポーネントの実際の使用状況(どのコンポーネントが本当に参照されているか、どれが一度も使われていないか、どれが大量にカスタムの実装で回避されているか)を定期的に監査することは、ライブラリがすでに保守困難なほど肥大化してから慌てて対処するのではなく、固定の定例作業にする価値がある。この監査コストは、コンポーネントライブラリ全体が実際のコードベースから乖離していたことを後になって発見するコストよりも、はるかに低い。