綴Photo の勉強ノートに戻る
開発記録2026.05.15

コードレビューで誤認されないコメントの書き方 — AI が自分のコードを『バグ』と誤認したケース

コードレビューコメント設計AI協働Dart綴Photo

綴Photo の修正中、面白いことが起きた。Claude Code(自分の AI 開発パートナー)が、自分が読んでる関数を「バグ」と誤認した。コードに問題があったわけじゃない。問題は コメントに何が書かれてなかったか だった。

その経験から「AI レビューに通す前のセルフチェック観点」として整理した3点ルールの話を書く。


何が起きたか

期間スキャンのパフォーマンスを上げる修正をしてた。対象は scanEmptyMonthsInYear という関数で、「写真のない月の一覧を返す」もの。

Claude Code がコードを読んで、こう言った。

エミュレーターで全写真が EXIF なし(撮影日時不明)の場合、この関数は全月を「写真なし」として返してしまう。結果として全月が completed 扱いになり、UI から全部消える。これはバグ。

自分は「あれ、それバグじゃなくて仕様だよ」と気づいた。写真なし月を隠す という機能で、ユーザーがボタンを押したときに「写真がない月は綴る対象にならない」という意図的な挙動。

Claude Code は呼び出し側のコードを読んでなくて、関数単体だけ見て「自動で全消えする関数」と誤認したのだった。

空月の一覧はメモリの返り値で、保存しない。消える印は端末 SQLite の PeriodVisitStatus に残る。画面写真なし月を隠すボタンを押したときだけ自動では走らない押すメモリ空月の年月ペア返り値・保存しない閉じたら消える書く端末 SQLitePeriodVisitStatuscompleted を書く閉じても残る読む月一覧その月は出さない読むだけ関数は隠さないAI が読んだのは空月の返り値だけ。消える印は SQLite 側にある。ボタン以外からは走らない。関数は月を隠さない。

なぜ誤認したか

当時のコメントはこれだけ:

dart
/// 指定年の未完了月のうち、写真のない月の年月ペアを返す。

これだけ読むと、関数が 「何をするか」 は分かります。でも、

  • いつ呼ばれるか(自動? ボタン?)
  • 返り値がどう使われるか(completed にする? 単に表示する?)
  • 写真がない年では全月が返る挙動は意図的か、それともバグか

が、全部 コードからは読み取れません。AI は呼び出し側を別途読まないと意図を再構成できなくて、その手前で「これバグじゃない?」と早合点した。

自分自身、その後コードを見直すために呼び出し側を読みに行って、初めて意図を把握した。コメントが薄いと、書いた本人ですら半年後には誤読します。


3点ルール

ここから整理した「公開関数の docコメントに最低限書くべき3点」がこれ。

左はコードで足りる。右へ行くほどコードに無い。docコメントに書くのは右の3つ。コード何をするか空月の年月ペアを返すコメント無しでも読める呼び出し文脈いつ・結果の行き先ボタンからだけ1行誤認されやすい仕様バグに見えるが意図「これは仕様」と書く1行経緯なぜ今の形か別実装からの切り替え1段落公開関数の看板に書くのは右の3つ。左は名前と本文で足りる。

① 呼び出し文脈

「どこから呼ばれて、結果が何に使われるか」を1行。

dart
/// **呼び出し文脈**: period_select_page._bulkScanYear(「写真なし月を隠す」
/// ボタン)からのみ呼ばれる。返り値は markMultipleCompleted に渡され、
/// 該当月が一覧から非表示になる。

これを書いておくと、レビュアー(人も AI も)は 呼び出し側を読まなくても全体像が見えます。

② 誤認されやすい仕様

「バグと取り違えられそうな意図的な挙動」を「これは仕様」と明記して残します。

dart
/// **誤認されやすい仕様**: 写真が1枚もない年では、endMonth まで全月が返る
/// (=全月 completed になり一覧から消える)。これはバグではなく
/// 「綴る対象がない月は非表示にする」意図的な仕様。

これがあると、レビュアーは「これバグじゃない?」と思った瞬間にコメントで「いや、仕様だよ」と返してもらえます。未来の自分や AI の早合点を、コメント1個で止められます。

③ 経緯

「過去に別実装から切り替えた理由」を1段落。

dart
/// **経緯**: 初期実装は画面表示時に自動スキャンしていたが、写真数が多いと
/// 時間がかかりすぎたため、ユーザー操作(ボタン)起点に変更した。
/// 「自動スキャンに戻せば UX 良くなる」と思ったら、まずこの経緯を疑うこと。

これが一番強いです。コードを見るだけでは絶対に分からない情報。「自動スキャンに戻そう」と思った半年後の誰か(自分含む)が、過去の失敗を繰り返さずに済みます。


テストとの使い分け

「仕様をテストで固める」アプローチもあって、これも有効です。ただ、コメントとテストでは役割が違います。

コメント テスト
得意なこと なぜそうなってるか(意図・背景) こう動く(具体的な値での挙動)
何を防ぐか レビュアーがバグと誤認するのを防ぐ 後の改修で挙動が変わるのを防ぐ
弱点 コードが変わって古びるリスク 「なぜそれが正しいか」は書きにくい

要は コメントは "WHY"、テストは "WHAT"。今回みたいに「これってバグじゃない?」と疑われそうな仕様には コメントが先に効きます。テストは回帰防止の保険で、書けるなら書きます。


プロジェクト規約にも入れた

書きっぱなしだと再発するので、プロジェクトの規約ファイル(CLAUDE.md = AI が読む規約)にルールとして残した。

公開関数の docコメントには、該当する範囲で以下を書く:

  • 呼び出し文脈: どこから呼ばれ、結果が何に使われるか(1行)
  • 誤認されやすい仕様: バグと取り違えられそうな意図的な挙動(1行+「これは仕様」明記)
  • 経緯: 過去に別実装から切り替えた場合の「初期実装はこうだったが…のため変えた」(1段落)

AI レビューに投げる前に「この関数、呼び出し側を読まないと意図が分からないか?」と自問する。Yes なら docコメントが足りていない。

これで次回以降、AI が同じ誤認をしたら「コメント不足」として検知できます。


学んだこと

  • コメントは "AI レビューを通すための事前準備" でもあります。コードに書かれてない意図を読み取らせるのは無理筋なので、書いておくしかありません
  • コメント vs テスト は対立じゃなくて役割分担。コメント=意図、テスト=値
  • 書いた本人ですら半年後には誤読します。だから「自分のために書く」のが正解

おわりに

「コメントは書かない方が良い」という流派もあります。確かに「何をしてるか」を実況中継するコメントは要りません(コード読めば分かるからです)。

でも 「なぜそうなってるか」は、コード読んでも分かりません。そこを書かないと、未来の自分も AI も呼び出し側を彷徨うことになります。

レビューに通す前に、関数1つずつ「これ呼び出し側を読まないと意図が分からないか?」と自問する習慣をつけたい。Yes なら、まだ docコメントが足りていません。

この記事は2026年5月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。