自分で書いたはずのコードが、読めなくなったことはありますか。先週の夜、1年前に自分が8割を AI と一緒に書いた WordPress テーマを開いて、5分で閉じました。バグではありません。知人との雑談で「もう一度動かせないか」という話が出て、久しぶりに手を入れようとしただけです。VS Code でファイルツリーを眺め、当たりをつけて1つ目を開いて、5分。書いたのは自分なのに、何が書いてあるのか分かりませんでした。
先に、その5分で思い出した結論を置きます。AI と一緒に書いたコードも、自分のコードです。そして、動いた瞬間は完成ではありません。半年後の自分が読めて、はじめて完成です。以下は、そこに気づくまでの記録と、次に同じ轍を踏まないために自分へ課したルールです。
確認日:2026年5月26日。振り返る開発期間は2025年春〜秋。当時の環境は WordPress 6.8 / PHP 8.3.21 / Local by Flywheel + Xserver スタンダード。使っていた AI 補助は Claude Code、Cursor、ChatGPT(GPT-4 系)。テーマは仮に LMS と呼びます。
開いて5分で閉じたソース
2025年の春から秋にかけて、Slack ライクなコミュニケーションテーマを作っていました。チャンネル、DM、メンション、通知、絵文字リアクション、ファイル添付、スレッド、未読バッジ。Slack で日常的に使う機能を、ほぼ一通り実装したつもりでした。完成後にクライアントへ評価で出して、そのまま立ち消え、別案件で忙しくなり、頭の片隅へ。それが先週、雑談をきっかけに開いたわけです。
何が起きたか、具体的に書きます。最初に開いたのは channel-controller.php のような中心ファイルでした。PHP だけで数十個、JS と CSS を足すとさらに増えます。当時この構成をどう決めたのか、思い出せません。関数名から処理が想像できない。processMessage のような抽象的な名前を grep すると、3つのファイルから見つかりました。引数は似ていて、中身が微妙に違う。チャンネル用、DM 用、スレッド用と区別したつもりだったのかもしれませんが、今読むと違いが分かりません。同じ名前の関数を別ファイルに作って、呼び出し側が間違えれば一発で壊れる構造です。
ヘルパーも妙に細かい。getUserNameById、getUserNameFromCache、getUserDisplayName、formatUserName。全部自分が書いたはずですが、どれがどれを呼んでいるのか、追うだけで時間が溶けます。コメントは英語と日本語が混在し、「user is not authenticated」のすぐ下に「未読バッジを更新」が続く。AI が生成したコメントを、そのまま受け入れていた結果です。そして「// TODO: remove after refactoring」付きの関数が、どこからも呼ばれないまま生き残っている。リファクタリングは、ついぞ行われませんでした。5分眺めて、閉じました。
8割を AI に書かせた半年
当時のコードは、感覚で8割を AI に書いてもらっていました。複雑な構造は Claude Code、部分的な書き換えは Cursor、調べ物や壁打ちは ChatGPT。AI に設計案をもらい、ざっと読んで「これで進めて」、出てきたコードを貼り付け、動かなければエラーを貼り直し、動いたら次へ。最初の数週間でチャンネル一覧とメッセージ投稿が動いて、気持ちよかったのを覚えています。機能を増やすこと自体が目的になっていました。
問題は、書くスピードに自分の理解が追いつかないまま走ったことです。仕様書なし、設計図なし、ファイル構造はその場の思いつき、テストコードはゼロ。「とりあえず動くものを早く」で半年突っ走りました。「この処理、前にも書いた気がする」と思っても、過去ファイルを探すより AI に書かせ直すほうが速い。結果、似た処理が3か所に増える。これが後の重複地獄を生みました。AI を使うこと自体は、今でも間違っていなかったと思います。あのスピードがなければ完成にすら届きませんでした。間違っていたのは、AI に書かせている間、自分がレビュアーではなく、コピー&ペーストの仲介役になっていたことです。良し悪しを判断する役割を、自分で手放していました。
2025年春の AI の限界
正直に書くと、2025年春から秋の AI コーディングは、今ほど成熟していませんでした。当時は Claude 3.5 Sonnet、GPT-4o、Cursor の組み込み AI。どれも当時は強力でしたが、今と比べると一段下です。同じ処理を別の言葉で頼むと、まったく違うコードが返る。前回の設計を覚えていない。「関数 A を改善して」と頼むと、B も C も別物になって返り、差分を見ながら「何が変わったんだっけ」と確認に時間を取られる。
コンテキスト窓も今より短く、長いファイルを丸ごと貼ると、AI は途中までしか覚えていない状態になっていました。当時はそれに気づかず、全体を見せたつもりで会話していたので、AI の返答がファイル前半だけを前提にしていた。それに気づかず「動くから OK」で進んだ箇所が、たぶん今のデッドコードの一部です。機能追加のたびに新しいセッションを開き、新しいファイルを増やす。「続きから」ではなく「ゼロから」を繰り返せば、設計の一貫性は保てません。今の Claude Code や Cursor は、長いコンテキストを保ち、ファイル横断で構造を読み、既存の関数を使い回してくれます。1年前に自分が苦労していた一貫性の部分を、AI 側がかなり支えてくれる。でも、当時の AI と書いたコードは、当時の限界をそのまま引きずっています。AI のせいにする気はありません。クセを理解せずに走ったのは自分です。
これからやるリカバリ
今どう向き合っているか。正直、まだ向き合えていません。ソースが多すぎて、どこから読み解くか考えている段階です。やろうとしている順番だけ書き出します。まず Claude Code に LMS 全体を読ませて、ファイル構造と関数の対応図を作らせる。「主要なファイルを5つ挙げて、それぞれの責務を50字以内で」あたりから始めます。AI に書かせたコードを AI に解説させる、皮肉な構図ですが、今はこれが一番現実的です。次に、参照されていない関数やコメントアウトされたブロックを物理的に削る。PHP なら PHPStan や Psalm、JS なら ESLint で Dead code を検出させると速い。当時は通していなかったので、まず通すところからです。それから、機能ごとにファイルを再編成して、channel/、dm/、thread/、notification/ の大枠に整理し直す。ここまで終えて、ようやく後付けで仕様書を書く準備ができます。完了予定は立てていません。本業の合間に少しずつで、もしかしたら作り直しの判断をするかもしれません。作り直しのほうが早いケースは、現実によくあります。
次に課す自分ルール
リカバリが終わってから、ではありません。今ここで決めておかないと、同じことを繰り返します。次に何かを長期で作るときに自分へ課すのは、この6つです。
- 仕様書を、機能ごとに小さくても書く。AI にコードを書かせる前に書く。channel.md に「チャンネルは複数メンバーが投稿、時系列順、未読数はメンバーごと」程度の短い説明があれば、半年後の自分でも思い出せます。
- ファイル構造は最初に決める。途中で思いつきで増やさない。「とりあえずルートに置こう」を禁止するだけで、構造は格段に保てます。
- 関数名は AI 任せにしない。processData と書いてきたら postMessageToChannel に直す。手間は5秒です。
- コメントも自分の言葉で。1関数1行でいい。書くのは「何をするか」ではなく「なぜ必要か」。なぜだけは AI には書けません。
- テストは軽くても、実装と同じタイミングで書く。後回しにすると、LMS のように一生書けなくなります。
- 長期プロジェクトでは AI セッションを毎回新規にしない。ルートに CLAUDE.md を置いて、設計方針・命名規則・ファイル構造を書いておけば、AI も参照してくれます。
そして一番大事なこと。動いた瞬間を完成にしない。コミット前に、自分で1分だけ読み返す。命名は変か、コメントは残せているか、デッドコードは混ざっていないか。1分のセルフレビューが、半年後の自分を救います。
次の自分に渡すメモ
短く、自分のために書き留めておきます。AI は同僚みたいなものです。便利だし、いてくれないと困る。でも、書いたコードの責任は自分にあります。仕様書を書かずに始めない。関数名とコメントは自分の言葉に直す。ファイル構造は最初に決める。テストは実装と同時に書く。動いた瞬間を完成にしない。当たり前のことを、ソースを開いて閉じた5分間で、ようやく思い出しました。LMS をどう復活させるか、決まったらまた書きます。書き直しを選んだら、なぜ選んだかも残します。失敗から学ぶには、失敗を残しておくしかありません。
この LMS で Long Polling まわりを実装した試行錯誤は、Xserver でリアルタイムチャットを Long Polling で作った話に書いています。AI コーディングや WordPress 開発の実体験は、Web Development カテゴリにまとめています。










コメント