はじめに
前回の記事では、Windowsもネイティブ開発もRustも未経験の自分が、AIに任せてWindowsネイティブの画像ビューワ「mImageViewer(mIV)」を作り、ソースコードをほとんど読まないまま、約22万行・2か月で一般配布まで持っていった——という話を書きました。
「コードを読まないなら、トラブったときどうするの?」というのは、当然わいてくる疑問だと思います。今回はその、詰まったとき・失敗したときに、実際どう対処したかを、具体例で紹介します。AIに大きめのものを任せると、人間が手で書くのとは少し違う失敗の仕方をするので、その"あるある"と対処、という感じで読んでもらえればと思います。
AIにありがちな失敗と、その対処
並行作業で、2つの事故をやらかした
mIVは途中から、2つのAI(Claude CodeとCodex)を並行で動かす場面が増えました。すると、並行作業ならではの事故が起きます。
1つは、片方のAIのコミットが、もう片方のまだ作業中のファイルまで巻き込んでしまうこと。意図しない変更が混ざったコミットは、後から原因を追うのがやっかいです。最初は「コミットするファイルを毎回明示的に指定する」ことで対処しようとしました。
ところが、それでも完全には止まりませんでした。そしてもう1つ、もっと派手な事故が起きます。作業コピーを片付けたら、共有していた依存ファイル置き場(DLLやAIモデルが入った、合計数百MBのフォルダ)が、まるごと巻き添えで消えたのです。しかも翌日もう一度。原因は、Windowsの「ジャンクション」(フォルダへのショートカットのようなもの)を、Gitが"中身の詰まった普通のフォルダ"と勘違いして、リンク先ごと削除してしまうことでした。
最終的にたどり着いた対処は、作業をまるごと別の作業コピー(Gitのworktree)に分け、依存フォルダはジャンクションで共有せず、実体をコピーして持つこと。共有をやめたら、巻き込みも巻き添え削除も起きなくなりました。「共有して楽をしよう」が完全に裏目に出た例です。
日本語が文字化けする(2種類あった)
文字化けにも何度かやられました。が、よく見ると原因は2種類ありました。
1つは、Claude Codeが書いた日本語のファイルを、Codexがうまく読めないという問題です。Claude Codeはファイルを「BOMなしのUTF-8」という形式で書き出すのですが、Windowsの日本語環境では、目印(BOM)のないUTF-8を、昔ながらの文字コード(Shift_JIS/CP932)と取り違えて読んでしまうツールが今でもあります。どうやらCodexもこれにあたるようで、Claude Codeが書いた日本語ドキュメントが、Codex側で化けて読めない、ということが起きました。対処は、ファイルの先頭に「これはUTF-8ですよ」という目印(BOM)を付けること。これで安定しました。
もう1つは、UIに使った記号が表示されないというもので、これはフォント側の別問題でした(環境によって、その記号を持っていないフォントがある)。✕のような記号を×のような安全な文字に置き換えて回避しています。同じ"文字化け"でも、原因がまったく別物だった、というオチでした。
ファイルのブラウズが、思ったように滑らかに動かない
画像やフォルダを次々めくっていくと、表示がもたつく。こうした速度の問題は、AIにとって苦手分野のようでした。「ここが遅いから直して」と単純に頼むと、AIはコードを眺めて"たぶんここだろう"と推測で直そうとするのですが、なかなか本当の原因にたどり着けないのです。
そこで効いたのが、まず測らせるというやり方でした。「もし遅いなら、原因を調べられるように、必要ならログ(どこで何ミリ秒かかったか)を仕込んで」とまず依頼し、実際にログを取ったうえで、「このログを分析して、どこが遅いか突き止めて」と指示する。推測ではなく計測から入らせると、原因の特定がぐっと早くなりました。
たとえばこの"もたつき"の正体のひとつは、画面を描く担当(UIスレッド)が、ファイル読み込みのような重い処理まで自分で抱えていたこと。原因さえ分かれば、あとは裏方の作業スレッドに逃がすだけです。ほかにも、フォルダの一覧を作るときにファイル1つずつ「フォルダ? ファイル?」を問い合わせていて、数百ファイルで1秒近く待たされる、というのもありました。難しいのは"直す"ことより"本当の原因を見つける"ことで、そこはAI任せにせず、計測の段取りをこちらが用意する必要がありました。
AIは、コードの整形をいつも忘れる
AIは機能の中身には集中しますが、コードの見た目(整形=インデントや改行の統一)はしばしば崩れたまま放置します。これは正直、今でも起きます。毎回「整形して」と頼むのも面倒なので、対処は仕組みで止めることにしました。Gitのpre-commitフック(コミット直前に自動で走るスクリプト)で整形チェックをかけ、整形されていないコードのコミットを機械的に弾いています。AIが忘れても入口で止まるので、リポジトリは常にきれいに保たれます。
PDFの処理が、10秒も固まる
PDFのページを並列で描画する仕組みで、操作が最大10秒もフリーズすることがありました。中を見てみると、AIは最初、「資源が空くまで、短い待機をはさみながらロックを取り続ける」——いわゆるビジーループの作りにしていました。これは複数の処理が資源を奪い合うと、運の悪い処理がいつまでも順番待ちのまま放置される、古典的なアンチパターンです。対処は、優先度つきの順番待ち行列できちんとさばくように直させること。これで固まらなくなりました。
観察:AIは"コード量が少ない方"を選びがち
このPDFの件で気づいたのですが、AIはしばしば「コード量が少なくて済む方」を選ぶ傾向があるようです。ビジーループは、きちんとした順番待ちの仕組みを組むより、行数が圧倒的に少なくて済みます。だからAIは、特に何も言わないとそちらに流れる。
正しさよりも"短く書けること"を優先しがち、と言い換えてもいいかもしれません。これはAIが悪いというより、「短く済む実装は、たいてい初手で出てくる。だから性能や安定性が効く場所では、人間が"ここはちゃんと作って"と一段、方向を指定してやる必要がある」ということだと思います。コードを読まない私でも、ここだけは口を出す、というポイントでした。
似た傾向で、AIはいま動いている既存コードのやり方にも強く引っ張られます。周りがビジーループだらけだと、新しい場所もビジーループで書いてくる。裏を返せば、最初に良い"お手本"を1つ作っておくと、その後はそれに倣って勝手に良い書き方へ寄ってくれる。最初の数件だけ方向づけを丁寧にやる、というのが効きました。
もうひとつのクセ:AIは"何でも実装してしまう"
これも付き合ううちに分かったことです。AIは、こちらの「あれも欲しい、これも欲しい」を、基本的に全部受け入れて実装してくれます。気前がいいのですが、これが曲者でした。
要望を足すたびに、仕様はどんどん複雑になっていきます。すると、条件がいくつも絡み合う部分でバグが出て、直すとまた別のバグが出る、というモグラ叩きが始まる。AIは目の前の要望には素直に応えてくれますが、「この機能とあの機能が同時に起きたらどうなるか」の整合性までは、放っておくと面倒を見きれないのです。
ここは、人間が引き受けるしかない部分でした。「この条件の組み合わせは、仕様レベルで切り捨てる(そもそもサポートしない)」という割り切りの判断は、こちらでやる必要があります。全部を完璧に両立させようとすると、複雑さに押し負けてしまう。
とはいえ、その"整理"自体はAIに手伝ってもらえます。仕様が膨らんできたなと感じたら、「この機能、仕様が複雑になりすぎている。どう整理したらシンプルになると思う?」とAI自身に相談する。少し引いた視点で「ここは統合できる」「この分岐は要らないのでは」と案を出してくれるので、それを叩き台に、複雑になりすぎないよう舵を切っていました。
意識して指示した、数少ないこと
ここまで「AIが勝手にやらかす」話ばかりでしたが、逆に私が意識して頼んでいたこともあります。コードを読まない代わりに、効くと感じてやっていたのは、実はこれくらいです。
- 設計をドキュメントにまとめさせる。 mIVは複数の仕組みが絡み合っていて、「ここを直すと、あっちが壊れる」が起きやすい。AIはコードは書けても、全体の繋がりを毎回覚えているわけではないので、サブシステムごとに設計メモを書かせ、関連する修正の前に読ませるようにしました。これは何度も明示的に指示しています。
- テストコードを、時々まとめて充実させる。 機能を追っているとテストが手薄になりがちなので、ときどき「このあたりのテストを増やして」と頼みます。動作確認の一部をAIに肩代わりさせるイメージです。
- 時々、コードレビューをまとめて実行させる。 機能を追っている間は先へ進むのを優先しがちなので、区切りのいいところで「ここまでのコードをレビューして、気になる点を直して」と、Claude CodeやCodexにまとめてレビューと修正をさせることもしていました。
- 「再発防止に、メモしておいて」と言う。 同じ失敗を繰り返したとき、「次やらないように書いておいて」と一言頼みます。すると Claude Code が、それをプロジェクトの注意書きファイル(CLAUDE.md)にまとめてくれます。
最後のひとつだけ補足すると、私はこの注意書きファイルを、自分で計画的にメンテしているわけではありません。「書いといて」と言うだけで、あとはAIがいい感じに整理してくれて、気づけば失敗の記録がずらりと並んだファイルが育っていました。意図して作った仕組みというより、AIに任せていたら勝手にできていた副産物に近いです。それでも、新しい作業の前に読まれるので、同じ罠を踏みにくくなる効果は地味にありました。
AI同士の相談は、いまだに手作業
2つのAIをどう使い分けているか、もう少し具体的に。
コードを書く流れの中では、Claude Code から Codex をコマンドで自動的に呼び出してレビューさせることもできます。これは席を外して放置しているときは便利です。ただ、リアルタイムで進み具合を見ながら作っているときは、これがちょっとストレスでした。Codexのレビューに入ると、進捗が見えないまま10分くらい黙って止まることがあり、「今どこまで進んだ?」とやきもきします。
なので、込み入った相談をしたいときは、結局手作業です。Claude Desktop と Codex の Windows アプリを両方立ち上げ、片方の言い分をコピペでもう片方に伝える、を人力で往復させる。面倒ですが、この方がそれぞれのAIが何を考えているかが見えるので、途中で止めたり、割り込んだりできるのがメリットでした。
正直、AI同士が自動で、しかも様子を見せながら相談し合ってくれる仕組みがあれば一番いいのに、とよく思います。今のところは、この人力コピペが現実的な落としどころです。
それでも、AIに任せきれないこと
ここまで威勢よく書きましたが、AIに丸投げできない領域もはっきりしてきました。
- 動作確認:実際にアプリを動かして「なんかおかしい」と気づくのは、結局のところ人間の仕事。
- 性能の測定:「速くなったか」はAIの自己申告では分かりません。ベンチマークを書かせて実測し、条件を変えて何度も測る、を細かく指示する必要があります。
- 設計の判断:「どっちの作りがいいか」は、最後は人間が決める。AIは案を出すのは上手ですが、選ぶのは苦手です。
- 品質の見極め:前回書いたとおり、品質が出ずに諦めた機能もあります。AIは"量"はこなせても、"狙った品質"に届くかは別問題。
まとめ
コードを読まずにAIに任せる、と言うと「丸投げ」に聞こえますが、実際は 失敗の仕方のクセを掴んで、要所だけ人間が舵を取る作業の連続でした。短く済む実装に流れがちなところを「ちゃんと作って」と引き戻し、設計やテストはドキュメントに残させ、踏んだ罠は「書いといて」と言って記録させる。それくらいで、専門外の自分でも、そこそこの規模のものを2か月走らせることができました。
次回は趣向を変えて、「インストール不要の単体exeで配る」という配布まわりの話を書く予定です。巨大な依存(FFmpegなど)を1ファイルに詰め込むために、Windows特有の罠とけっこう格闘したので、その舞台裏を紹介します。