StorybookとAtomic Design、理想と現実のギャップ
フロントエンド開発の世界で、「Storybook」によるコンポーネント管理と「Atomic Design」による設計思想は、もはやスタンダードとなりつつあります。UIコンポーネントを独立して開発・テストできるStorybookと、再利用性を極限まで高めるAtomic Design。この二つを組み合わせれば、開発生産性は飛躍的に向上し、美しいデザインシステムが構築できる──。
多くのエンジニアがそうした理想を抱いて導入を試みます。しかし、現実はどうでしょうか。
- 「Atoms(原子)の粒度が細かすぎて、管理コストが爆発した」
- 「Storybookを導入したが、結局コンポーネントのカタログで終わってしまい、開発プロセス自体は変わらない」
- 「デザイナーのデザインデータとStorybookのコンポーネントが、いつの間にか乖離している」
こうした「理想と現実のギャップ」に悩む声は少なくありません。特に、厳密なAtomic Designのルールを適用しようとするほど、プロジェクトの初期段階で疲弊してしまうケースが見受けられます。
本記事の目的は、Atomic Designの理論を否定することではありません。むしろ、その優れた思想を「どうすれば現実のプロジェクトでうまく機能させられるか」という実践的なアプローチを提案することです。
キーワードは、「components/common」と「先行開発」です。
なぜ厳密なAtomic Designは失敗しやすいのか?
Atomic Designは、UIを「Atoms(原子)」「Molecules(分子)」「Organisms(有機体)」「Templates(テンプレート)」「Pages(ページ)」という5段階の階層で捉える強力なメンタルモデルです。しかし、このモデルを文字通りに解釈してディレクトリ構成などに適用しようとすると、いくつかの問題に直面します。
粒度のジレンマ:「Atoms」が細かすぎる問題
例えば、「Button」コンポーネントを考えてみましょう。Atomic Designに従えば、これは「Molecules」または「Atoms」に分類されるでしょう。しかし、ボタンの中の「Icon」や「Label(Text)」を「Atoms」として切り出すべきでしょうか?
理論上は「Yes」かもしれません。しかし、実開発において「Iconだけ」「Labelだけ」で単独に再利用するシーンは稀です。むしろ、過度に細分化することで、propsのバケツリレーが複雑化し、コンポーネントの見通しが悪くなる(=管理コストが増大する)デメリットの方が大きくなりがちです。
命名規則とディレクトリ構成の破綻
「このコンポーネントはMoleculesなのか? Organismsなのか?」
こうした議論は、プロジェクト初期には活発でも、時間が経つにつれて曖昧になりがちです。明確な基準がないまま階層構造を維持しようとすると、ディレクトリの移動(リファクタリング)コストが非常に高くなります。
結果として、/components/atoms や /components/molecules といったディレクトリが形骸化し、どこに何があるのか分からない「コンポーネントの墓場」が生まれてしまうのです。
解決策としての「components/common」アプローチ
そこで私たちが提案するのが、厳密なAtomic Designの階層に固執せず、より実践的な粒度から始める「Atomic Design風」アプローチです。その中核となるのが /components/common(または /components/ui, /components/shared)ディレクトリの活用です。
「Atomic Design風」とは何か?
これは、Atomic Designの「再利用性」や「関心の分離」という優れたエッセンスは取り入れつつ、厳格な5階層(特に Atoms / Molecules / Organisms)の分類を強制しないアプローチです。
/components/common (or /ui)
プロジェクト全体で共通して使用される、状態(State)を持たない汎用的なUIパーツを配置します。Atomic Designでいう「Atoms」と「Molecules」が混在するイメージです。
/components/features (or /domain)
特定の機能やドメイン(例:ユーザー登録フォーム、商品一覧)に特化したコンポーネントを配置します。これらは「Organisms」や「Templates」に相当し、/common のコンポーネントを組み合わせて構築されます。
このように、階層をシンプルに「汎用的か、ドメイン固有か」という観点で分けることで、コンポーネントの置き場所に悩む時間を大幅に削減できます。
「common」に配置するコンポーネントの基準
/common には何を置くべきでしょうか? 基準は「プロジェクトのどこからでも(どのドメインからでも)呼び出される可能性があるもの」です。
ButtonInputCheckboxModalTooltipSpinner(ローディングインジケーター)Avatar
これらは、アプリケーションのコンテキスト(状態やビジネスロジック)から切り離されており、見た目(View)と振る舞い(Props経由)がStorybook上で完結するものたちです。
Storybook「先行開発」の具体的なステップ
/components/common のアプローチは、Storybookによる「先行開発」と非常に相性が良いです。これは、アプリケーション本体(例:Next.jsやNuxt.js)のロジックを実装する前に、UIコンポーネントをStorybook上で先に完成させるワークフローを指します。
ステップ1:デザイントークンと共通コンポーネントの合意
まず、デザイナーとエンジニアが協力し、Figmaなどのデザインツール上で「デザイントークン」(色、タイポグラフィ、スペーシング)と、前述の「common」コンポーネント(Button, Inputなど)の仕様を定義します。
この段階で、コンポーネントのバリアント(例:Buttonの primary, secondary, disabled 状態)を洗い出しておくことが重要です。
ステップ2:components/common をStorybookで実装
エンジニアは、アプリケーション本体のページを作り始める前に、まずStorybookを起動します。そして、ステップ1で合意した仕様に基づき、/components/common ディレクトリにコンポーネント(例: Button.tsx)と、そのストーリーファイル(Button.stories.tsx)を作成していきます。
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta = {
title: 'common/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
backgroundColor: { control: 'color' },
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
};
この段階では、API連携や複雑な状態管理は一切不要です。ただひたすらに、**Propsを受け取って正しく表示されること**だけに集中します。
ステップ3:ページ(コンテキスト)への組み込みとレビュー
/common のコンポーネントがStorybook上で揃ったら、いよいよアプリケーション本体(/features や /pages)の実装に移ります。
この時、エンジニアは「ボタンの見た目」を気にする必要はもうありません。Storybookで動作確認済みの <Button> コンポーネントを配置し、ビジネスロジック(例:onClick で何をするか)の記述に集中できます。
デザイナーやPMも、StorybookのURL(静的にデプロイされていると尚良い)を参照すれば、いつでも最新のUIコンポーネントを確認できます。
デザイナーとエンジニアの協業をどう変えるか
この「commonから始めるStorybook先行開発」ワークフローは、開発効率以上に、チームの協業プロセスに大きなメリットをもたらします。
Storybookを「信頼できる唯一の情報源(SSoT)」にする
デザインの「正解」はどこにあるべきでしょうか? Figmaでしょうか、それとも本番環境のHTML/CSSでしょうか? この認識がズレると、前述の「デザインと実装の乖離」が起こります。
Storybookを先行開発のハブに据えることで、「Storybookで定義されたコンポーネントこそが、UIの信頼できる唯一の情報源(Single Source of Truth)」という共通認識をチームで持つことができます。
デザイナーはFigmaで定義したコンポーネントがStorybookで正しく実装されているかを確認し、エンジニアはFigmaに立ち戻らずともStorybookを見れば正しいUIを組み立てられる。この好循環が生まれます。
ビジュアル・リグレッション・テスト(VRT)の活用
StorybookをSSoTとして維持するためには、意図しない変更(リグレッション)を防ぐ仕組みが不可欠です。
Storybookは、ChromaticやLokiといったVRT(ビジュアル・リグレッション・テスト)ツールとの連携に優れています。これらをCI/CDプロセスに組み込むことで、「ある変更を加えたら、意図せず共通ボタンのスタイルが崩れた」といった事故を、Pull Requestの段階で自動的に検出できます。
これにより、エンジニアは安心して /common コンポーネントのリファクタリングに取り組むことができ、UIの品質が継続的に担保されます。
まとめ:小さな「common」から始める、実践的なコンポーネント設計
Atomic Designは強力な設計思想ですが、その原則に厳密に従おうとするあまり、管理コストが増大し、開発が停滞してしまっては本末転倒です。
重要なのは、階層構造の美しさではなく、「再利用可能で、テストしやすく、メンテナンス性の高い」コンポーネントをいかに効率よく生み出すかです。
まずは /components/common という小さなスコープから、Storybookを使った先行開発のワークフローを試してみませんか? 汎用的なボタンやインプットがStorybook上で整備されるだけでも、アプリケーション開発の速度と品質は大きく向上するはずです。

