
「動くけど読めない」AI生成コードを保守可能にする手直し手順
「とりあえず動いた」——AIに書かせたコードがテストも通って、無事にリリースまでこぎ着けた。 それから数週間後、別の修正でそのファイルを開いて、手が止まる。「これ、書いたの自分のはずなのに、何をやってるか読めない」。変数は data2 や tmp、一つの関数が画面2枚ぶん、条件分岐が入れ子で三段——動いてはいる。でも、どこを触ると何が壊れるのか、まるで見当がつかない。そんな夕方、ありますよね。
AIが書くコードは、「今この瞬間、要件を満たして動く」ことには強い一方で、「半年後の誰かが読んで直せる」ことは保証してくれません。動作と可読性は別のものだからです。しかも「AIを使え」と言われて数を出している現場ほど、この「動くけど読めない」コードが静かにたまっていきます。
この記事は、そんなコードを全部書き直すのではなく、保守できる程度に手直しする最低限の手順をまとめたものです。きれいな理想形を目指す話ではありません。「半年後の自分が、ここを開いて泣かない」——それだけを基準にした、地に足のついた手直しの型です。一度に全部やる必要はありません。まず一番こわい所から、一緒に見ていきましょう。
結論:「動くけど読めない」AIコードは、捨てて書き直すより部分的に手直しする方が安全です。順番は、①名前を直す(tmp・data2を意味のある名前に)→ ②長い塊を、意味のかたまりで分ける → ③コードに書かれていない「暗黙の前提」をコメントや名前で言葉にする → ④こわい所にテストで足場を作ってから触る → ⑤触らない所は無理に直さない。可読性は「きれいさ」ではなく「次に直す人が迷わないか」で判断します。最後に手直しの優先順位表とチェックリストを置きました。
動くコードを読めるコードにするのは、後ろ向きの作業ではありません。 未来の自分の時間を、今すこし前借りして守る作業です。
なぜAIのコードは「動くけど読めない」になりやすいのか

AIのコードが読みにくくなるのは、書き方が下手だからではありません。 AIは「その場で要件を満たすこと」に最適化されていて、「あとで読む人がいること」を前提にしていないからです。
具体的には、こんな癖が出やすくなります。
- 名前が仮置きのまま:
data、data2、tmp、resultなど、意味を持たない名前が残る - 一つの関数が長くなる:頼んだ処理を一気通貫で書くので、意味の切れ目で分かれていない
- 暗黙の前提が書かれない:「この配列は必ずソート済み」「ここは1始まり」といった前提が、コードにもコメントにも残らない
- やや凝った書き方を選ぶ:短く書けるほうを選ぶので、三項演算子の入れ子や一行に詰め込んだ処理が増える
- 文脈が毎回リセットされる:既存コードの命名規則や設計方針を引き継がず、その場限りの流儀で書く
どれも、その場で動かすには何の問題もありません。テストも通ります。 こわいのは、これが「読む人」の存在を織り込んでいないことです。コードは書く時間より、読まれる時間のほうがずっと長い。動いた瞬間に完成に見えても、保守の視点ではまだ半分なのです。
だから手直しのコツは、動作を変えずに「読む人向けの情報」を足していくことです。次の章から、その順番を手順にして見ていきます。
手直しの型:5つの手順
先に全体像を出します。上から順に、効果が大きくて事故りにくい順に並べてあります。
| 手順 | 何をするか | これで楽になること |
|---|---|---|
| ①名前を直す | tmp・data2 を意味のある名前に | 読むだけで何の値かわかる |
| ②塊を分ける | 長い関数を意味のかたまりで分割 | どこで何をしているか追える |
| ③前提を言葉にする | 暗黙のルールをコメント・名前で明示 | 「なぜこう書いたか」が残る |
| ④足場を作る | こわい所にテストを足してから触る | 手直し中に壊しても気づける |
| ⑤触らない | 読めている所・こわい所は無理に直さない | 手直しが事故に化けない |
ポイントは、5つ全部を毎回やらないことです。 名前を直すだけで読めるようになる箇所も多い。逆に、業務ロジックが濃い箇所は④の足場が先。その箇所で一番こわい所を選んでなぞれば十分です。全部やろうとすると、手直しが新しいバグの温床になります。
時間がない日の「10分版」最小セット:今日はどうしても時間がない、でもこのファイルをまた触る予感がある——そんな日は、これだけで構いません。①一番目立つ悪い名前を3つだけ直す + ③「この関数は何を前提にしているか」を先頭に1行コメントで書く。この2つは動作を変えずにできて、しかも次に開いたときの負担がいちばん減ります。残りは余裕のある日に足せば十分です。
では一つずつ見ていきます。
手順1:名前を直す(いちばん安く、いちばん効く)
可読性の手直しで、費用対効果が一番高いのは名前です。動作をまったく変えずに、読みやすさだけを上げられます。
直したい名前の代表例:
- 意味のない変数:
data、data2、tmp、x、arr→ 中身がわかる名前へ(activeUsers、sortedScoresなど) - 嘘をついている名前:
getUserなのに更新もしている、listなのに実は辞書 → 実態に合わせる - 省略しすぎ:
cnt、usr、calc→ 迷うくらいなら省略しない - 真偽値らしくない真偽値:
flag、status→isEnabled、hasErrorのように yes/no がわかる形へ
コツは、「この名前だけ見て、何が入っているか言えるか」を基準にすることです。 言えなければ直しどき。エディタのリネーム機能(シンボル一括変更)を使えば、参照箇所もまとめて安全に変わります。手で置換すると別物まで巻き込むので、必ずリネーム機能を使ってください。名前を直すだけで「読めない」の体感の半分は消えることが多いです。まずはここから。
手順2:長い塊を、意味のかたまりで分ける
名前が整ったら、次は長すぎる関数を分けます。AIは頼んだ処理を一気通貫で書くので、「入力の検証・本体の計算・結果の整形」が一つの関数に詰まっていることがよくあります。
やること:
- 関数の中の「ここからここまでは1つの仕事」という切れ目を探す(コメントを入れたくなる場所が切れ目のサイン)
- その塊を、やっていることがそのまま名前になる関数に切り出す(
validateInput、calcTotal、formatResultなど) - 切り出すときは振る舞いを変えない——これはリファクタなので、出力が同じであることを必ず保つ
ただし、分けすぎにも注意です。1〜2行の関数が大量に増えると、今度は「あちこち飛んで読めない」別の読みにくさになります。目安は「一画面(スクロールなし)で関数全体が見渡せる」くらい。それ以上長い関数だけを対象にすれば十分です。
分けるのがこわい・時間がないなら、無理に切り出さず、関数の中に「// ここから集計」のような見出しコメントを置くだけでも、読むときの負担はぐっと減ります。切り出しは手段で、目的は「どこで何をしているか追えること」。手段が重い日は、軽いほうで目的だけ取りにいけば構いません。差分を伴う分割の確認は、AIリファクタリングの差分レビューの手順があわせて効きます。
手順3:コードに書かれていない「暗黙の前提」を言葉にする

ここが、あとで一番効いてくる手直しです。 「動くけど読めない」の正体は、多くの場合「なぜこう書いたか」がどこにも残っていないことです。AIは前提を頭の中(モデルの内部)で処理してしまい、コードには結果しか出しません。
言葉にして残したい「暗黙の前提」の例:
- 入力の前提:「この配列はソート済みである前提」「ここに来る時点で null チェック済み」
- なぜこの書き方か:「素直に書くと遅いのであえてこうしている」「外部APIの仕様に合わせた変換」
- 触ると危ない理由:「この順番を入れ替えると二重登録が起きる」
- マジックナンバーの意味:
* 1.1が何なのか(消費税?手数料?)、86400が「1日の秒数」であること
残し方は2通りです。 まず、名前で語れるものは名前にする(SECONDS_PER_DAY = 86400、TAX_RATE = 0.1)。コメントより名前のほうが嘘になりにくく、確実です。 名前にしきれない「なぜ」は、短いコメントで一行だけ残す。長い解説はいりません。「未来の自分が『なんでこうなってるの?』とつぶやく所」に、その答えを一言置く。それだけで、次に触る人の不安がずいぶん減ります。
手順4:こわい所は、テストで足場を作ってから触る
手順1〜3は動作を変えない範囲でしたが、それでも業務ロジックが濃い箇所を触るのはこわいものです。そこで、手直しの前にテストで足場を作ります。
先に免除ルートを置いておきます。 テストが無い・書きにくいレガシーが多い現場では、「足場を作る」自体が重い作業です。足場が作れない箇所は、無理に手直ししないでください(手順5へ)。 読みにくくても動いているなら、それは今日の事故ではありません。テストが書ける・あるなら、以下を続けます。
やること:
- 手直しする前に、その箇所の「今の振る舞い」を写し取る簡単なテストを1〜2本足す(今の出力を正解として固定する。これを特性テストと呼びます)
- そのうえで、手順1〜3の手直しを行う
- 手直し後に同じテストが緑のままなら、読みやすさだけを変えられた証拠
- テストが落ちたら、手直しで振る舞いを変えてしまったサイン。立ち止まって戻す
ここで大事なのは、「読みやすくする」と「振る舞いを直す」を混ぜないことです。 手直し中に「あ、ここバグってる」と気づくことはよくあります。でも、可読性の手直しとバグ修正を同じコミットでやると、あとで「どの変更で何が変わったか」が追えなくなります。バグを見つけたら、別のコミット・別の作業として切り分ける。足場のテストは、この切り分けを守るための安全網です。テストとAIが同じ思い込みを持たないよう、足場は手直し前の振る舞いを基準にしておきます。
手順5:読めている所・こわい所は、無理に直さない
最後は、あえて「直さない」判断です。可読性の手直しでいちばん多い失敗は、やりすぎて動いていたものを壊すことだからです。
直さないでいい所:
- すでに読めている所:好みに合わないだけなら触らない。「自分ならこう書く」は理由になりません
- 足場が作れないこわい所:テストが書けず、触ると何が壊れるか読めない箇所は、今日は保留
- もうすぐ消す・作り替える所:近く置き換わるコードを磨いても報われません
- 一度に広げすぎる手直し:今日のタスクと関係ないファイルまで直し始めると、レビューも大変になる
判断の軸は、「この手直しは、次に直す人の迷いを減らすか?」の一点です。 減らすならやる。自己満足や見た目だけなら、今日はやらない。読めないコードを全部いっぺんに片付けようとすると、たいてい途中で力尽きるか、別の所を壊します。今日のタスクで触る範囲の、いちばんこわい所だけ——それで十分です。可読性は、一回の大掃除ではなく、通りがかりに少しずつ整える方が続きます。
ありがちな落とし穴と、その回避
手直しでつまずきやすい所を、先に潰しておきます。
- 全部いっぺんに書き直す:動いているコードを捨てると、動作の再現から始まり事故が増える。部分的に手直しするほうが安全。
- 可読性の手直しとバグ修正を混ぜる:あとで差分が読めなくなる。バグを見つけたらコミットを分ける。
- テストなしでこわい所を触る:先に今の振る舞いを写し取るテストを足してから。足場が作れないなら今日は触らない。
- 好みで書き換える:「自分ならこう書く」は直す理由にならない。基準は「次の人の迷いが減るか」。
- 名前を手で一括置換する:別物まで巻き込む。必ずエディタのリネーム機能を使う。
落とし穴の多くは、「きれいにしたい」という気持ちが「動くものを守る」より前に出てしまうことから来ます。 可読性の手直しは、コードを芸術作品にする作業ではありません。次にここを開く人(たいてい自分)を、少し楽にする作業です。目的を見失わなければ、やりすぎずに済みます。
明日からやること(小さく始める3つ)
全部を一度に習慣化しようとすると続きません。まずこの3つから。
- 今日触ったファイルで、悪い名前を3つだけ直す:手順1が片付き、動作を変えずに読みやすさが上がります。リネーム機能を使えば安全です。
- 一番長い関数の先頭に「何を前提にしているか」を1行コメントで書く:手順3の入口。次に開いたときの負担が大きく減ります。
- こわいロジックを触る前に、今の出力を固定するテストを1本足す:手順4の足場ができ、手直しで壊しても気づけます(書けない現場は、その箇所を今日は保留=手順5でOK)。
この3つだけでも、「動くけど読めない」が「動くし、次も読める」に少しずつ変わります。 慣れてきたら、長い塊を分ける手順2や、こわい所の足場作り(手順4)も足していけば十分です。
コピーして使う「手直し優先順位メモ」
読めないコードを前にしたら、関係する行だけ埋めて、どこから手を付けるかを決める足場にしてください。全部やる必要はなく、今日のタスクで触る範囲で十分です。
# 手直し優先順位メモ
## この箇所を、なぜ手直しするか(1行)
- (例:来週も修正が入る予定で、今のままだと危ないから)
## ①名前(動作を変えない・すぐできる)
- 直す悪い名前:
- 嘘をついている名前:
## ②塊を分ける
- 一画面に収まらない長い関数:
- 切り出せる「意味のかたまり」:
## ③暗黙の前提を言葉にする
- 名前にできる定数(マジックナンバー):
- コメントで残す「なぜ」:
## ④足場(こわい所を触る前)
- 今の振る舞いを固定するテスト:
- 足場が作れない→今日は保留にする箇所:
## ⑤触らないと決めた所
- 読めているので触らない:
- こわいので今日は保留:
手直しチェックリスト
手を付ける前・付けたあとに、1項目ずつ「○/要確認」を付けながら使ってください。一度に全部でなく、今日はその箇所に関係する所だけで十分です。各セクションの ★印は「これだけは外せない最低ライン」。忙しい日は★だけ、残りは任意——と読んでください。
①名前を直す
- ★
tmp・data2など意味のない名前を意味のある名前にしたか - 実態と食い違う名前(嘘の名前)を直したか
- リネーム機能を使ったか(手置換で別物を巻き込んでいないか)
②塊を分ける
- 一画面に収まらない関数を、意味のかたまりで分けたか
- 分けすぎて逆に追いにくくなっていないか
- 分けたあとも振る舞いが同じか
③前提を言葉にする
- ★ マジックナンバーを意味のある定数名にしたか
- 「なぜこう書いたか」を短いコメントで残したか
- 入力の前提(ソート済み・null チェック済みなど)を明示したか
④足場を作る(テストが無ければ手順5で保留してよい)
- ★ こわい所は、手直し前に今の振る舞いを固定するテストを足したか
- 手直し後も同じテストが緑のままか
- 可読性の手直しとバグ修正のコミットを分けたか
⑤触らない判断
- すでに読めている所を、好みで書き換えていないか
- 足場が作れないこわい所を、無理に触っていないか
- 今日のタスクの範囲を超えて広げすぎていないか
最後に
AIが書いた「動くけど読めない」コードを手直しするのは、AIの仕事にダメ出しをするためではありません。 そのコードを次に開くのは、たぶん未来の自分だから。今日のうちに、名前をひとつ、コメントを一行、読める形に整えておく——それだけのことです。
動くコードは、それだけで十分えらい成果です。 そこに「次も読める」という安心が少し加わると、AIコーディングは「その場しのぎ」から「積み上げられる資産」に変わっていきます。書かせる前に渡す前提と制約の伝え方や、任せたあとのレビュー・検証チェックリストとあわせて使うと、この積み上げがもっと楽になります。

5つの手順のうち、今日できたのが名前ひとつだけでも、それはもう「動けばいい」で止めなかった確かな一歩です。 未来の自分のための数分を、今日ひとつ、積んでいきましょう。