世界を動かす技術を、日本語で。

手書きでコードを書くことに戻ります

概要

  • AIによるコーディング体験 と、その限界についての実録
  • AIは特徴的な機能実装には強い が、アーキテクチャ設計は不得手
  • 「god-object」問題 や設計上の落とし穴の具体例
  • 人間による介入と設計指針 の重要性
  • AI活用時の実践的な教訓 を抽出

AIコーディング実録と「god-object」の罠

  • HN(Hacker News)で注目 を集めたdev-logの要点
  • 「自分を完全にループから外して」AIにソフトウェア構築を任せた 実験記録
  • 結論:人間の介入なしでは意味のあるものは作れない 現状
  • k10sプロジェクト (GPU対応Kubernetesダッシュボード)の開発経緯
    • Go言語とBubble Tea で実装
    • NVIDIAクラスタ運用者向け、GPU使用率やDCGMメトリクスの可視化
  • 約30週末・234コミット、全てAI(Claude)との「vibe-coding」で構築
  • TUIツールとして一旦アーカイブ、再設計を決意

AIコーディングの初期体験

  • AIへのプロンプトで爆速開発、初期は10倍速に感じた
  • Podsビューやリソースフィルタ、ライブアップデート等 が短時間で実装可能
  • プロジェクトが小さいうちはAIが全体を把握でき、破綻しにくい 状況

破綻の始まり:「god-object」現象

  • GPUフリートビュー実装後、他ビューが壊れる問題発生
    • 全てを1つの巨大なstruct(Model)で管理 し、状態管理が破綻
    • Update()関数が500行超・switch/case 110分岐 の巨大関数化
  • 「vibe-coding」ではAIが都度最短経路で実装し、設計劣化に気づけない
  • 人間がコード全体を一読し、初めて問題を認識

5つの教訓(Tenets)

  • Tenet 1: AIは機能追加に強いが、アーキテクチャ設計は不得意
    • 各機能が「今だけ動けば良い」実装になり、全体の整合性が崩壊
    • view間の状態分離がなく、バグやデータリークの温床
    • 対策:設計ルール(インターフェースや所有権)を明文化し、AIに常に読ませる
  • Tenet 2: 「god-object」がAIのデフォルト生成物
    • 単一巨大structに全状態を詰め込みがち
    • キー操作や状態管理が分岐だらけになり、保守不能
    • 対策:viewごとにstructを分離、キー操作も各viewで管理
  • Tenet 3: 開発速度の錯覚でスコープが膨張
    • AIによる高速実装が「ついで機能追加」を誘発し、プロジェクトが肥大化
    • 本来の目的(GPU特化)から逸脱しやすい

具体的な設計指針例(CLAUDE.md抜粋)

  • 各viewはViewトレイトを実装、他viewのstateへアクセス禁止
  • 非同期データはAppMsg経由のみで到達、直接フィールド変更禁止
  • 新規view追加時、既存viewの修正不要であること
  • App structはナビゲーションとディスパッチのみ担当
  • view固有のstateやキー操作は各view内で管理

まとめ

  • AIは「特徴的な機能」の一発実装には有効 だが、 設計や保守性は人間の責任範囲
  • 設計ルールを明文化し、AIにガードレールを設けることが重要
  • AIの「最短経路」志向を活かしつつ、破綻しない設計基盤を人間が用意する必要性

AI開発の現状と今後の展望

  • 現状(2026年5月時点)では人間の介入が不可欠
  • AIのアウトプットを鵜呑みにせず、設計・アーキテクチャは自ら主導するべき
  • 「vibe-coding」の高揚感に惑わされず、設計原則を守る重要性

参考リンク

  • k10sリポジトリ(アーカイブ版) https://github.com/shvbsle/k10s/tree/archive/go-v0.4.0

  • Hacker Newsスレッド [HN Thread]

Hackerたちの意見

つまり、君が言いたいのは、ランダムなものじゃなくて、ちゃんと考えたアーキテクチャを作るために、もっと詳しいスキルファイルを作るってことだよね?

その通りだけど、順番が大事なんだ。CLAUDE.mdの制約は、最初にアーキテクチャを設計した場合にだけ機能するんだよ。それはAIに伝えるための方法に過ぎない。俺が犯した間違いは、悪いスキルファイルを書くことじゃなくて、何も設計せずにAIに30セッションも一貫した構造的な決定を期待したことなんだ。リライトは、コードが存在する前に、真っ白なドキュメントでボックスを描くことから始まるんだ。それからCLAUDE.mdが、俺がすでに決めたことを強制するんだ。プロジェクトが成長するにつれてそれが実際に機能するかどうかは、正直まだわからない。

大きなファイルを小さなファイルに分けて、コードの動きも説明してもらうようにAIに頼めばいいんじゃない?ゼロからやり直す必要はないと思うけど。

実はそれが最初に試したことなんだ。コードベースの混乱とアーキテクチャを説明するのはうまくやってくれたよ。それから3〜4回リファクタリングを試みたけど、どれも元の混乱よりデバッグが難しい方法で壊れちゃった。ゴッドオブジェクトには暗黙の依存関係が多すぎて、一つのスレッドを引っ張ると別の何かがほどけちゃうんだ。そして、リファクタリングが安定する前に、毎日のClaudeの使用制限を使い果たしちゃった。リライトは全く違う教訓を教えてくれると思うけど…。

新しいアーキテクチャプランに従ったリライトは、元のものをプロトタイプとして扱えば、かなり早く終わるかもしれないね。

コードベースが「理解できない」って言われるとき、誇張じゃないこともあるよね。時には、アーキテクチャが本当に分割できなかったり、理解できなかったりすることもあるんだ。

今、大規模なリファクタリングの発見フェーズに取り組んでるんだけど、AIがルールを明確にプログラム的にエンコードしても、意外と役に立たないことが多いって気づいたんだ。例えば、特定のフォルダの外にある特定のテーブルに対してKyselyクエリを禁止するリントルールを考えてみて。特定のドメインの読み書きを一箇所にまとめるために、こんなルールを書いて、リント違反をAIエージェントに渡せば、必要に応じてクエリをサービスコールに分けてくれるだろうと思ってたんだ。最初は「うまくいった!」って感じるんだけど、出力をじっくり見始めると、ちょっとした不一致が出てきてね(プライマリとレプリカの呼び出しを区別しなかったり、特定のLIMITやORDER BY句のポイントを見逃したり、条件やSELECTを適切に書き換えなかったり)。何度かレビューエージェントにかけてみるけど、努力が完全に無駄だって気づくんだ。レビューエージェントが10個や20個、30個の問題を修正しても、出力を完全には信頼できないから。AIが登場する前にこういうことをやってた経験があるから、昔のやり方に戻ったよ。コーデモッドを使って、自動的にコードを書き換えるルールのシリーズを使うって感じ。AIがコーデモッドを書くのはできるし、結果を評価するのも手伝ってくれるけど、数百の変更を自動で適用することで、出力を信頼する能力が失われちゃった。しばらくはこれが続くと思う。この業界には「検証レイヤー」が必要だけど、今のところはまだないみたい。誰かがこのコメントに反例を返してくれることを密かに願ってる。そうすれば、すごく助かるんだけど。

じゃあ、実際には手でコードを書いてないの?タイトルと結論の違いにすごく混乱してるんだけど。

要は、HNが食いつくようなセンセーショナルな見出しを考えて、投稿がフロントページに飛ぶってことだね。

これ、LLMが生成したみたいに読めるな。確実ではないけど、短くてキザな知ったかぶりのLLMの書き方にはアレルギー反応が出るんだよね。

うん、俺もLLMのセンサーが反応したよ。

手でコードを書くけど、ブログ記事はLLMが書くの?

タイトルには「手でコードを書くに戻る」って書いてあるけど、実際にやってるのは「コードを書く前に、自分で手で__デザイン作業__をしている」ってことなんだよね。つまり、Claudeはまだコードを生成してるってこと?それにしても、彼らが自分たちの雰囲気で作ったプロジェクトがうまくいくと思って、7ヶ月も生成されたソースコードを一度も見ずにドメインを買ったなんて、全然理解できないんだけど。

アイデアが浮かんでから数分後にプロジェクトのドメインを買ったよ。サイドプロジェクトならコードを見ないのもそんなに変じゃないと思うし、差分を見ながら徐々に進めていくのもアリだと思う。確かに違った働き方だけど、そんなにクレイジーじゃないよ。

他の変更はもっとシンプルだよ。コードを書く前に、自分で手作業でデザイン作業をしてる。あいまいなドキュメントじゃなくて、具体的なインターフェース、メッセージタイプ、所有権ルール。これがコーディングの難しい部分なんだ。アーキテクチャがあれば、コードを書くのは簡単。コードを書いていないと、nullを許可するAPIを設計したのに、データベースがそれを許可していないことに気づかないかもしれない。あるいは、許可しているけど、考慮していなかった小さな問題に気づくこともある。この記事を書いて、AIが問題だって気づかないのはどうしてなんだろう。AIにアーキテクチャを任せるんじゃなくて、AIがやること全てに注意を払っていないからだよ。AIはただのコード生成器なんだから。やっていることを全部チェックする必要がある。ソフトウェアエンジニアリングの難しい部分は、決してコードを書くことじゃなかった。ジュニア開発者はコードを書く方法を知っている。難しいのはそれ以外の全てなんだ。

やっていることを全部チェックする必要がある。これが多くの人に失われているように思う。比較的コード経験が少ない自分でも、結果をチェックして、何がうまくいったか、何がダメだったかを学ぶことで、今まで以上に学んでいると感じる。だから、すぐに良くなるとは思えないんだ。多くの人が「どうやってそんなに良い出力を得てるの?」って聞いてくるけど、答えはいつも「注意を払って問題を見つけて、修正を頼んだ」ってこと。ほんとにそれだけのシンプルなことなんだけど、みんなの目がすでにうつろになってるのが見える。Googleが情報を見つけるのを簡単にしたように、質の良い情報と悪い情報を見分ける人間の要素は解決されていないんだ。

君の言ってることには同意するけど、今は定義の問題があって、超充電されたタブ補完を使ってる人や、チャットボットを並行して動かしてる人がたくさんいるけど、明らかに全てをレビューしている。一方で、スティーブ・イェッジが全く新しいエディタを提案していて、君がコードを読むことはほとんどないのに、12人以上のエージェントをオーケストレーションすることができるっていう状況がある。最初のグループは、デザインやインターフェース、データ構造についてかなり深く考えていて、その分野でしっかりとレビューを行っている。第二のグループはそうじゃなくて、そっちの方がちょっと心配だな。

他の部分に慣れてくると、コードを書くのが一番楽しいことに気づくよね。多くの場合、トレードオフをバランスさせたり、前回のバランスで見逃した要因を調べたりしている。コードを書くときは、問題を十分に理解しているからこそ、可能な解決策を試すことができるっていう安堵のため息が出る。計画に数時間かける代わりに、数週間のコーディングに置き換えることもできるけど、それはちょっとしたリスクを伴うよね。

バイブコーディングは、無限の実装予算があるように感じさせる。でも、実際にはそうじゃない。無限の行予算(AIは好きなだけコードを生成できる)を持っているだけ。だけど、いつも通り有限の複雑さの予算は変わらない。これは、僕が苦しんでいる一般的な根本的なポイントの特別なケースなんだ。AIがコードの限界コストをゼロにしたと仮定しよう。そうすると、コードの供給は無限になる。一方で、他の重要な要素は依然として有限:1日の時間、注意、興味、善意、支払ってくれる顧客、お金、エネルギー。じゃあ、何を作るかをどうやって選ぶの?ジーニーのように、ツールは私たちに何でも求める力を与えてくれる。でも、ジーニーのように、実際には私たちが本当に欲しいものがわからないことが多いんだ。

これがClaudeの問題なんだ。GPT-5.5と比べると、Claude Codeはショートカットを好む。codexappのGPT-5.5とClaude Code opus4.7で同じことを試してみたけど、GPT-5.5の要件に従うと、Claude Codeのタスク実行時間が5分から40分に伸びるんだ。マクロアーキテクチャの問題を解決するために、Lispを使ってプログラム全体のフレームワークを書くことにしてる。Lispはアーキテクチャ文書の代わりになると思うし、意味密度が高くて、構文制約やチェック機能があるから助かる。これで、少なくとも何もやり直す必要がなくなった。これを使って20以上のプロジェクトをリファクタリングしたよ。

コーディングエージェントと作業するためのルールをいくつか決めたんだ:1. コーディングエージェントを使ってコードを生成する場合、自分が絶対に正しくコーディングできる自信があるものに限る(銃を突きつけられたテスト)。2. そうでない場合は、生成されたものを完全に理解するまで先に進めない。自分で再現できるレベルまで理解する必要がある。3. ルール2を破ることで負債(これを認知的負債って呼ぶみたい)を作ることができるけど、プロジェクトを完了と宣言するためには全額返済しないといけない。負債が蓄積すると、その後生成するコードの質が下がる可能性が高くなるし、負債が複利で増えていく感じもする。これらのルールが本格的なプロジェクトにどうスケールするかはあまり分からないけど、今のところは個人プロジェクトにだけ適用してる。このやり方でエージェントを使うのは本当に楽しいよ。たくさん学べて、自分が理解できるレベルのコードベースができあがるんだ。

ここでの答えは、バブルティーと一緒にClaudeを使わないことだと思う。俺も同じことを試したけど、同じ結果になった。でも、それは特定のフレームワークに限られてるみたいで、SolidJSでは全然同じことをしないのがすごく得意なんだよね。