Antigravityが書いたコードを初めて見たとき、「正しいけれど、自分のものではない」という感覚がありました。
バグはありません。動く。でも、なにかが違う。
個人でアプリを作り続けて十年以上になります。ほぼ毎日コードと向き合ってきたことで、自分なりのリズムや判断軸が体に染みついていました。その感覚が、AIの生成物とぶつかることになるとは正直思っていませんでした。
Antigravityのコードが「よそよそしく感じた」理由
Antigravityが生成するコードは、概ね良質です。命名規則も整っていて、適切にコメントが入っていて、ロジックも明快。でも、長年積み上げたコードベースを持つ目で見ると、どこか「教科書から切り取ってきたような」印象を受けることがありました。
たとえば、エラーハンドリングの粒度。私のコードは「このエラーは絶対に起きないが、もし起きたときはこう記録しておく」という判断を、経験から直感的に行っています。でもAntigravityは、ベストプラクティスに従い、すべてのエラーケースを均等に処理しようとします。結果として生成されるコードは冗長で、自分のコードベースに組み込んだとき、浮きました。
よそよそしさの正体は、判断の文脈がないことでした。コードは同じことをしているのに、そこに至る理由が見えてきません。
「判断の文脈」がコードに宿るということ
同じ処理でも、「なぜこの設計なのか」という背景を持って書かれたコードは、読み返したときに意図が伝わります。それは、書き手の判断がコードに宿っているからです。半年前に自分が書いたコードでも、設計の理由まで思い出せるのは、書いた時点でその理由が一緒に刻まれているからだと思います。
Antigravityにはその判断の文脈がありません。正確に言えば、自分の文脈を与えていなかった、というのが後から気づいたことでした。生成AIは設計の意図を推測してはくれますが、推測は当てずっぽうになりがちです。文脈は、推測させるのではなく、こちらから渡すものだと考えるようになりました。
最初にぶつかった壁 — 「正しいが、自分のものではない」
最初の数週間、私がAntigravityに指示していたのは「何をするか」だけでした。
「壁紙アプリのお気に入り機能にバリデーションを追加して」
これに対して返ってきたコードは機能的には問題ありません。でも、自分のプロジェクトにはUserPreferencesという独自クラスがあって、そこに保存ロジックが集約されているのに、Antigravityは別の場所に書いてきました。
指示が不完全だったのは明らかです。「何をするか」しか伝えていないので、「どこに・なぜ・どう」という文脈をAntigravityは持ちようがありません。
// Antigravityが生成した(コンテキストなし指示)
func validateFavorite(item: WallpaperItem) -> Bool {
guard !item.id.isEmpty else { return false }
guard item.category != nil else { return false }
return true
}
// 自分のコードベースでは、バリデーションはUserPreferencesに集約されている
// この関数が別ファイルに置かれると、後のリファクタで必ず迷子になるこの「生成されたコードが自分の設計と噛み合わない」感覚は、指示の文脈不足から来ていました。
折り合いをつけた3つの指示パターン
試行錯誤の末、以下の3つを意識するようになってから生成物が変わりました。
1. 「設計の意図」を先に語る
何をしてほしいかより先に、なぜその設計になっているかを伝えます。
「このプロジェクトでは、永続化に関わるロジックは全て
UserPreferences クラスに集約しています(過去に
分散していたことで保守が困難になった経験から)。
このバリデーション機能も、その設計に沿って実装してください」
こう伝えると、Antigravityは既存のクラス構造を尊重した上でコードを生成します。「なぜ」を持っているから、適切な「どこに」が選べるようになります。
2. 「このプロジェクトでは〜しない」を明示する
肯定の指示だけでなく、「やらないこと」を言語化します。
個人開発で積み上げたコードには、意図的に省いている処理があります。「このアプリのユーザーはほぼ全員日本在住なので、タイムゾーン処理は最小限でいい」「AdMob のSDKバージョンは意図的に固定している」といった判断。これを伝えないと、Antigravityは汎用的な実装を提案してきます。
「このアプリはAdMob 21.x系を固定で使用しています。
最新バージョンへの移行は意図的に見送り中のため、
依存ライブラリの更新提案は不要です」
制約と理由を明示すると、提案の的外れ感が大きく減ります。
3. 生成されたコードに「自分の文脈コメント」を足す
完成したコードを、そのままコミットしない習慣をつけました。Antigravityが生成した後に、自分の判断を一行足します。
// TODO(masaki): 2026年のASO改善と合わせて再設計予定
// AdMob配置はこのまま。UIリニューアル後に見直す
func setupBannerAd() { ... }コードに「なぜ今こうなっているか」が残ると、半年後の自分が迷いません。AIが書いたコードであっても、この一行があるだけで、後から読む自分にとっての意味がまるで変わります。
それでも噛み合わなかったケース
3つの指示を徹底しても、文脈を渡しきれない場面はありました。正直に書いておきます。
最も苦戦したのは、複数ファイルにまたがる設計判断です。たとえば「画面遷移の状態管理を、画面ごとのViewModelに持たせるか、アプリ全体で一元管理するか」という方針は、一つのファイルを見ても伝わりません。Antigravityに単一のタスクとして渡すと、その場では妥当でも、アプリ全体の方針からは外れたコードが返ってきました。
// 単一ファイルへの指示では拾いきれなかった方針
// 「このアプリは画面間で状態を共有しないことを原則とする」
// → AGENTS.md に1行書いても、個別タスクの文脈には届きにくい
対策として、横断的な設計方針は AGENTS.md に書くだけでなく、影響範囲の大きい変更では「この変更は◯◯という全体方針に従っているか」を生成後に自分で確認する工程を挟むようにしました。文脈を渡す努力と、最後に人間が方針との整合を確かめる工程は、今のところ両方必要だと感じています。
もう一つは、過去の自分の「気まぐれ」な実装です。当時の締め切りや気分で例外的に書いた処理には、後付けできる合理的な理由がありません。こういうコードは、Antigravityに説明しようとして初めて「なぜこう書いたのか自分でも分からない」と気づきます。皮肉なことに、AIへの説明を試みる過程が、自分のコードの棚卸しになりました。
今の折り合い — AIの速度と個人の声の両立
3つを意識するようになって、生成物の「よそよそしさ」は随分と減りました。完全になくなったわけではありませんが、今は「出てきたコードが自分のスタイルに合わない場合は、指示の文脈が不足している」と捉えられるようになっています。
個人開発では、コードは自分の判断の積み重ねです。その積み重ねを言語化してAntigravityに渡すことで、AIは自分の代わりに実装の手を動かしてくれる存在になります。手を動かす部分を任せられるからこそ、自分は「なぜこう作るのか」という判断に集中できる。そう思えるようになってから、Antigravityとの距離が変わりました。
生成AIのコードが「自分のものではない」と感じているなら、指示の文脈がまだ足りていないサインかもしれません。コードより先に、設計の意図を渡してみてください。
エージェントへの委任で失敗した経験については、AIに任せた、そして後悔した — 個人開発者が気づいたエージェント委任の境界線も参考になると思います。