Claude Code は速い。指示を出せば数秒でコンポーネントが生える。しかしその速さのなかで、AI は平気でマジックナンバーを埋め込む。fontSize: 14、duration: 300、color: '#3b82f6'。見た目は動く。しかし次の瞬間、ちょっとした仕様変更でコードベース全体にばらまかれた固定値を一つひとつ探して直す羽目になる。
課題:AI が陥りやすい3パターン
マジックナンバー
AI への指示に「フォントサイズ 14px」と書けば、コンポーネントに text-[14px] が直接刻まれる。CSS Custom Properties やデザイントークンを経由しない。次のコンポーネントでも同じ値を使えと言えば、今度は別ファイルに 14px が重複する。変更時の影響範囲を追うのが困難になる典型パターンだ。
フォント直接指定
AI は loadFont を個別コンポーネントで呼びたがる。Remotion を使ったビデオ制作などでは致命的で、複数コンポーネントが同じフォントを個別に読み込み始めると、バンドルが肥大化するうえに「どこで何を読んでいるか」が不透明になる。フォント設定は集約ファイルに一元化し、各コンポーネントはそれを参照するだけにしなければならない。
絶対フレーム・絶対タイミング
アニメーション実装で AI が書くコードは、from: 0, to: 90 のような絶対フレーム指定になりやすい。シーンの長さが変わったとき、すべての to 値を手で直す必要が生じる。正しくは「シーン Duration に対する比率」として相対的に記述することだ。
この3パターンは本質的に同じ問題を指している。設計の意図を持った「単一の真実の情報源(SSOT)」を持たず、実装が散在するという問題だ。
アプローチ:config 駆動
解決策はシンプルだ。設定値を集約ファイルに持ち、すべてのコンポーネントはそこから参照する。
八雲の開発環境では、プロジェクト共通の設定を config/defaults.ts に集める。フォントサイズ・スペーシング・カラートークン・アニメーション値など、コンポーネント実装で使われうる定数はすべてここに定義する。
// config/defaults.ts
export const FONT_SIZE = {
body: 14,
heading: 24,
caption: 11,
} as const;
export const MOTION = {
duration: {
fast: 200,
normal: 300,
slow: 500,
},
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
} as const;
コンポーネント側は値を持たず、参照するだけにする。
import { FONT_SIZE, MOTION } from '@/config/defaults';
// ❌ ハードコード
style={{ fontSize: 14, transition: 'all 300ms' }}
// ✅ config 参照
style={{ fontSize: FONT_SIZE.body, transition: `all ${MOTION.duration.normal}ms` }}
新しい値が必要になったとき、集約ファイルに定数を追加してからコンポーネントで参照する、という順序を守る。逆の手順(コンポーネントで値を決めて、後で集約ファイルに移す)は「後でやる」が「永遠にやらない」になりやすい。
ウェブサイトの場合は CSS Custom Properties を経由させる。--color-primary: #3b82f6 を :root で定義し、コンポーネントは var(--color-primary) を参照する。Tailwind を使うなら theme.extend で CSS 変数を参照させ、ユーティリティクラス側でもトークンが一貫して使われるよう設計する。
CLAUDE.md にルール明記
AI にコードを書かせる場合、ルールは「プロンプトの中」ではなく「プロジェクトの設定ファイル」に書く。プロンプトは揮発するが、CLAUDE.md はプロジェクトに残り続ける。
八雲のグローバル CLAUDE.md には以下を明記している。
- マジックナンバー禁止: フォントサイズ、スペーシング、色、アニメーション値は必ず集約設定ファイル(
config/defaults.ts等)から参照する- フォント直接指定禁止:
loadFontを個別コンポーネントで呼ばない。集約フォント設定を使う- 絶対フレーム禁止: アニメーションは相対タイミング(シーン Duration に対する比率)で記述する
- 新しい値が必要な場合: 集約設定ファイルに定数を追加してから、コンポーネントで参照する
Claude Code はセッション開始時に CLAUDE.md を読む。ここにルールを書くことで、AI は毎回「config 経由で書く」という制約のなかでコードを生成する。プロジェクト固有の詳細ルールがあればプロジェクトルートの CLAUDE.md で上書きする。
ドキュメントとコードの連動については ドキュメント自動更新ルールの設計 でも詳述しているが、設計意図を CLAUDE.md に書くことで「AIが書いたコードがなぜそうなっているか」の説明責任も同時に果たせる。
運用してわかった効果と落とし穴
効果。デザイントークンの変更が1箇所の修正で全コンポーネントに伝播するようになった。AI が生成したコードのレビュー時に「var(--color-*) を使っているか」「config/defaults.ts からの参照か」という機械的なチェックが可能になり、レビューコストが下がった。
落とし穴。集約ファイルが肥大化すると逆に使いにくくなる。何でも defaults.ts に入れるのではなく、ドメイン別に分割する設計が必要になる(config/motion.ts、config/typography.ts など)。加えて、AI は「近くにある値を再利用する」より「新しい値を書く」傾向がある。レビュー時に既存定数との重複がないかを意識的に確認する習慣を持つことが重要だ。
もう一点。AI へのルール遵守は完璧ではない。特に長いコンテキストの後半では CLAUDE.md の内容が薄まりやすい。定期的にコードベースを grep して固定値の混入を検出するリントルールを設けることが実用的な対策になる。
まとめ
AI 駆動開発で品質を担保する設計の要点は、「AI が守れるルールの形にして CLAUDE.md に書く」ことと、「config 集約という単純な設計原則に徹する」ことの2つに尽きる。複雑なアーキテクチャよりも、シンプルで破りにくい構造の方が AI との協働には向いている。
AI 駆動開発の全体像は 八雲の AI 駆動開発概論 にまとめている。