※この記事は、Claude Codeで1人開発しているSNS運用SaaS「ThreadPost」の開発日記です。
SNS運用を自動化しませんか?
ThreadPostなら、投稿作成・画像生成・スケジュール管理まで全てAIにお任せ。
終わらない微調整
「スクリーンショット通りに直した」
Claudeがそう言うたびに、ブラウザをリロードした。そして絶望した。

ボタンの角丸を直せば、文字量の選択肢が崩れる。
アスペクト比を整えれば、生成枚数が画面外に消える。
20回直して、20回崩れた。
気がつけば外は明るくなっていた。
41コミットの代償
画像生成ダイアログを作ろうとした。
1日で41回のコミットを積んだ。

新機能は1つだけだ。
バグ修正が2回。
残りの38回は全部「崩れたUIを直す」作業だった。
機能数1に対してコミット数41。
スタイルを12種類に拡張し、アスペクト比・文字量・生成枚数を設定できるようにした。
複雑なUIをAIに作らせようとした、僕の完全な敗北だった。
終わらない「スクリーンショット通り」の呪い
画像生成ダイアログのUIを作っていた。
最初は簡単な作業だと思っていた。
「ImageGenerationDialog layout to match exact screenshot specifications」
Claudeにデザインのスクショを渡し、完璧に再現させようとした。
これが地獄の始まりだった。
「アスペクト比、文字量、生成枚数のボタンスタイルを修正」
チェックマークを消し、選択時は白背景、未選択時はグレー背景にする。
ブラウザを確認する。
ボタンは綺麗になった。
しかし、その下にあるAIモデル選択のアイコンが巨大化していた。
「ボタングループのスタイルをスクリーンショット通りに修正」
今度は全体のグレー背景を整え、ボーダーを消す。
直ったと思ったら、今度は文字量セクションが縦に間延びしている。
しんたろー:
41コミット中20回以上がUIの微調整。成功率0%。「ちょっと右」と言うと別の場所が「大きく左」に動く。CSSのジェンガを延々とやらされてる気分。
Reactのコンポーネント設計で、状態と見た目を混ぜすぎるとこうなる。
一つの要素のスタイルを変更すると、親コンテナのFlexboxの計算が狂う。
それが子要素全体に波及し、予期せぬレイアウト崩壊を引き起こす。
Tailwind CSSを使っていると、クラス名の羅列が長くなる。
Claudeも文脈を見失いやすくなる。
「ImageGenerationDialogの改善」
ヘッダーから不要なテストボタンを消し、背景色をベージュに変える。
ステータスメッセージをオーバーレイ表示にする。
綺麗になった。
そう思ってスタイル選択をスクロールしようとしたら、画面全体がフリーズした。
「ImageGenerationDialogのUI修正とビルドエラー解消」
JSXの閉じタグが不足していた。
見た目を直すことに必死で、コードの構文が壊れていることに気づかなかった。
Claudeは「直しました」と自信満々に言ってくる。
僕はそれを信じて、そのままコミットし続けていた。
スタイル12種類、アスペクト比3種類、文字量4種類、生成枚数5種類。
これにAIモデルの選択肢が加わる。
状態管理の複雑さは、UIの要素数に比例して指数関数的に増大する。
企業でのチーム開発なら、デザイナーがFigmaでコンポーネントの仕様を厳密に定義する。
フロントエンドエンジニアはそれに従って実装するだけだ。
それを1人で、AIとのチャットだけで完結させようとした。
「ImageGenerationDialogを大幅に簡素化」
積み上げた修正を全部捨てて、シンプルな構造に戻した。
複数スタイル選択のチェックボックスモードを廃止した。
スタイルごとに個別のプロンプト入力欄を配置した。
コードの行数は増えた。
しかし、見た目は最初よりシンプルになった。
そこからは1回の指示で通るようになった。
2時間かけて作ったUIを全部消した。
消した瞬間にビルドが通って、画面がサクサク動くようになった。
ここまで読んだあなたに
今なら無料で全機能をお試しいただけます。設定後は完全放置でプロ品質の投稿を毎日生成。
幽霊画像とフォールバックの勝利
UI地獄から抜け出した後、バックエンドの改修に入った。
「Claude→Geminiフォールバック機能を画像生成に追加」
Claude APIが失敗した場合、自動的にGemini 2.5 FlashやProに切り替える仕組みだ。
共通のフォールバックユーティリティを作り、関数を差し替えるだけ。
実装は10分で終わった。
APIの切り替えは成功した。
しかし、別の問題が起きた。
「Image leakage and stuck generation state」
生成中の画像が、いつまで経っても画面から消えない。
APIの切り替えには成功しているのに、クライアント側のポーリング処理がそれに追いついていなかった。
生成されたはずの画像が見当たらない。
あるいは、同じ画像が2枚表示される。
しんたろー:
バックエンドの処理は成功してるのに、フロントエンドが無限ロード。一番ユーザーがイライラするやつ。非同期処理のバグは再現性が低くて本当にタチが悪い。
Inngestのようなタスクキューで非同期処理を行っている場合、状態の不一致は致命的だ。
サーバー側のデータベースの状態と、クライアント側のポーリング状態がズレる。
企業の大規模システムでも、この「状態の不一致」による幽霊データの発生はよくある事故事例だと言われている。
複雑なポーリングロジックを捨てることにした。
「Resolve auto-generation bug and improve prompt generation robustness」
10分以上経過した古い待機中の画像を強制的にフィルタリングして消す。
失敗したプロンプトはループを止めるのではなく、スキップする。
「UX: Clear failed images when starting new generation」
新しい生成を始める時は、失敗した画像を画面から綺麗に消し去る。
不要な状態を「捨てる」ロジックを書いた。
画像生成の安定性は上がった。
エラーが起きても、UIは常にクリーンな状態を保つようになった。
しんたろー:
UI地獄の38コミットと比べると、フォールバック実装は10分で終わった。同じ1日の話とは思えない。設計がシンプルだと、AIへの指示も一発で通る。
落とし穴:「スクリーンショット通り」という最悪の指示
5回連続で同じ修正を繰り返した。
「ボタンの角丸を2pxにして」「やっぱり4pxに戻して」「隣のボタンと揃えて」
Claudeはその都度「修正しました」と返してくる。
問題は、Claudeが「修正した箇所」しか見ていないことだ。
全体のレイアウトへの影響を確認しない。
「スクリーンショット通り」という指示は、Claudeに「ピクセル単位で合わせろ」と言っているのと同じだ。
CSSのクラス名や具体的な数値を指定しないと、「それっぽい見た目」を生成し続ける。
不要なマージンやパディングがコードベースに積み重なっていく。
気づいた時には、誰も触りたくないスタイルの墓場になっていた。
次からはスクショを渡す前に、コンポーネントの責務を先に決める。
たぶん。
今日の開発データ
| 項目 | 今日の数字 | 比較対象 |
|------|----------|----------|
| コミット数 | 41件 | 先週の平均は1日8件 |
| 新機能 | 1件 | 普段は1日で3〜4件 |
| バグ修正 | 2件 | 機能追加の倍の時間を消費 |
| UI修正回数 | 20回 | 企業ならデザインシステムで1回 |
| フォールバック実装 | 10分 | UI調整の総時間は推定6時間超 |
先週の平均が1日8コミットだから、今日は5倍のペースだ。
ただし新機能は1つ。普段の3〜4件に対して4分の1以下。
企業なら20回のUI修正はデザインシステムで1回に圧縮できる。
1人開発でそれをやると、6時間が消える。
よくある質問
Q: 今回のUI崩壊は防げたか?
コンポーネントを作る前に「状態管理と見た目の責務を分ける」と決めていれば防げた。
今回は全部入りの巨大ダイアログを作ったから、一箇所の変更が全体を壊した。
次は先にコンポーネントの境界を決めてからClaudeに投げる。たぶん。
Q: Claude→Geminiフォールバックのコストはどう変わる?
ClaudeとGeminiでは1リクエストあたりの料金が異なる。フォールバック先のモデルによってコストが変動するため、今回の実装でDBにモデル名とコストを記録するようにした。どのモデルが何回使われたかダッシュボードで確認できる。Claude APIの障害時にGeminiに流れた分は、一般的にコストが下がる傾向がある。
Q: 非同期ポーリングの幽霊データはなぜ起きた?
Inngestのタスクが完了した後、クライアント側が古いIDでポーリングを続けていたからだ。新しい生成リクエストを投げても、前のリクエストのIDを参照し続けた。修正は「10分以上経過した待機中の画像を強制フィルタリング」と「新規生成開始時に失敗画像を削除」の2行だった。
今日の41コミットのうち、実際に動くものを作ったのは3件だ。
残りは全部「壊れたものを直す」作業だった。

この記事が参考になったら、ThreadPostを試してみませんか?
投稿作成・画像生成・スケジュール管理まで、全てAIにお任せできます。
ThreadPostをもっと知る