AIは私たちに「良いコードを書く」ことを強制しています。

2025/12/30 4:11

AIは私たちに「良いコードを書く」ことを強制しています。

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

Summary

この記事は、自律ソフトウェアエージェントを信頼できるようにするには、厳格なガードレール(特に 100 % テストカバレッジ、明確なファイル構成、および自動化ツール)が必要だと主張しています。

  • テストカバレッジ:エージェントが書くすべての行は二重チェックされるべきであり、未検証の行は明示的な「to‑do」項目となります。これにより、既存のコードか新規追加なのか曖昧さを排除します。
  • 実行可能な例:エージェントは変更ごとに動作するコードを提供せざるを得ず、「これは正しそうだ」という漠然とした回答を排除し、信頼性を段階的に向上させます。
  • ファイルシステム構成:小規模でスコープのはっきりしたファイル(例:
    ./billing/invoices/compute.ts
    )はコンテキスト読み込みを改善し、切断リスクを低減します。
  • 型安全性とツール:自動リンター・フォーマッタおよび TypeScript の重用により不正な状態が排除され、モデルのアクション空間が縮小され、意味的明確さ(例:
    UserId
    などのカスタム型)が提供されます。
  • API コントラクト:OpenAPI スペックは強力に型付けされたクライアントを生成し、PostgreSQL の型システムと Kysely はデータへの型付きアクセスを実現します。サードパーティのクライアントラッパーも整合性のために強力な型を公開します。
  • ガードレール速度:全テストスイートは高い並行度、外部呼び出しのキャッシュ、および強固な隔離で約 1 分で実行され、エージェントの反復中に頻繁に再実行できます。
  • ワークフロー自動化:単一の
    new-feature <name>
    コマンドが git worktree を作成し、非 git 設定をコピーし、依存関係をインストールして面接エージェントを起動します。プロセスは 1–2 秒で開始される必要があり、繰り返し使用を促進します。
  • 並列環境隔離:ユニークなポート、データベース名、キャッシュプレフィックス、または Docker コンテナにより、複数の worktree がクロストークしないようにします。

これら厳格なガードレールを採用することで(ツールとインフラへの前提投資が必要ですが)、チームはエージェント型コーダーの潜在能力を解き放ち、急速開発サイクルで見落とされやすい「良いコード」の基準を確立し、最終的にバグと保守コストを削減できます。

本文

数十年にわたり、私たちは「良いコード」がどのようなものかを知っていました。徹底したテスト、明確なドキュメント、小規模で範囲がはっきりしたモジュール、静的型付け、そして宗教儀式さえなくして起動できる開発環境です。これらの要素は常に任意でしたし、時間圧力がかかると「オプション」が削減されてしまうことも多かったでしょう。しかし、エージェントはこうしたオプションを必要としており、混乱して後から片付けることが苦手です。彼らは犬の糞を転がし回って家中に引きずり込むロボット掃除機になることもあります。

守るべきルールは、あなた自身が設定し強制するものだけです。エージェントの文脈が欠けていてガードレールが不十分だと、苦痛の世界に陥ります¹。しかしガードレールが堅固であれば、LLM は正しい道しか残らないまで疲れ知らずで回り続けることができます。

私たち6人組のチームは、エージェント型コーダーを支援するために数多くの具体的かつ時には物議を醸す投資を行ってきました。ここではあまり表面化しないものについて話しましょう。

1. 最も論争のあるガイドラインこそが最も価値がある

コードカバレッジを100 %にすることを義務付けています²。

これを聞くと多くの人は懐疑的になりますが、実際に一日使ってみると「秘密兵器」のように感じられます。私たちが使用しているカバレッジは、単なるバグ防止ではなく、エージェントが自分で書いたコード行の挙動を二重チェックしたことを保証するものです。

誤解されやすい点として、人々は「100 %カバレッジ=バグゼロ」または「ゲーム可能な指標追求」と考えがちですが、ここではそういう意味ではありません。

なぜ 100 %?

  • 95 % だと「重要かどうか」の判断でテストの欠落を残します。
  • 99.99 % だと、
    ./src/foo.ts
    の未カバー行が新機能作業前に存在したものか分からなくなります。
  • 100 % にすると曖昧さが消え、真のフェーズチェンジが起こります³。

未カバー行は「あなた自身が直近で行ったこと」の証拠です。カバレッジレポートは残すべきテストの簡易タスクリストとなり、エージェントに余計な推論自由度を与えません。100 % のカバレッジでは、モデルがコードを書いたり変更したりすると、その行がどのように振る舞うかを実際に示さざるを得なくなるため、信頼性が飛躍的に向上します。

その他のメリット:

  • 到達不能なコードは削除されます。
  • エッジケースが明確になります。
  • コードレビューが容易になり、システム全体の挙動を具体例で確認できます。

2. ファイルシステムナビゲーション

エージェント型ツールがコードベースを探索する主な手段はファイルシステムです。ディレクトリ一覧・ファイル名読み取り・文字列検索・コンテキストへのファイル挿入といった操作を行います。

./billing/invoices/compute.ts
のように階層的で意味のある命名を用いることで、実際のコードが同一でも情報量が大きく変わります。LLM をサポートするためにも、ファイル構造と名前付けは他のインターフェースと同様に慎重に設計すべきです。

  • 多くの小さなファイルを好む
    小さなファイルはコンテキストへのロードが容易で、エージェントが要約や切り捨てを行うリスクが低減します。完全に読み込めるサイズならモデルは全体を活発に保持できます。実際にはフローの高速化と性能劣化の防止につながります。

3. 開発環境

昔は一つの開発環境で完結していました:完璧なソリューションを作り、調整し、コマンドを走らせ、サーバーを再起動し、徐々に最適解へ収束させる。
エージェントと共に作業する場合は、まるで養蜂のようにプロセス間をオーケストレーションしつつ、各内部状態を把握しないで済む仕組みが必要です。

迅速な自動ガードレール

頻繁に実行できる軽量チェックが必須です。エージェントは「小さな変更 → 確認 → 修正 → 繰り返し」というサイクルを短く保つべきです。これらはエージェントフック、Git フック、または

AGENTS.md
のプロンプトとして実装できますが、いずれの場合もコストが低く、頻繁に走らせても遅延しないようにする必要があります。

当社のセットアップでは

npm test
が新規データベースを作成し、マイグレーションを実行し、全テストスイートを走らせます。
これが可能なのは、各ステージを極めて高速化(高並列・強い隔離・サードパーティ呼び出しのキャッシュ)したからです。10,000+ のアサーションを約1分で完了させています。キャッシュ無しだと20–30分かかり、エージェントがタスクごとに数回テストを走らせると数時間増えることになります。

ワークフロー例

new-feature <name>

このコマンドは新しい Git worktree を作成し、

.env
など git に含めないローカル設定をコピーし、依存関係をインストールしてからエージェントを起動します。プロンプトで PRD の作成を誘導し、機能名が十分に説明的なら「すぐに作業へ」と言われます。

重要なのはスクリプト自体ではなくレイテンシーです。数分かかり手間が多ければ使いません。一コマンドで 1–2 秒で新しい開発環境を整え、エージェントを即座に起動できるなら頻繁に利用します。

さらに同時に複数環境を走らせる必要があります。ワークツリーが多くても、ポート・データベース名・キャッシュ・バックグラウンドジョブなどの競合要素は環境変数で設定可能か、あるいは衝突しない形で割り当てるべきです。Docker を使えば一部自動化できますが、一般的な要求は「同一マシン上で複数の完全に機能する開発環境をクロス・トークなしで実行できる」ことです。

4. 自動化による強制

可能な限りベストプラクティスを自動化し、LLM の自由度を削減します。まだ導入していないなら、自動リンターとフォーマッタから始めてください。モデルがタスク完了時やコミット直前に自動で修正を適用できるよう設定します。

また 型付き言語 を採用することで不合法な状態・遷移の多くを排除できます。型は検索空間を縮小し、各層を通過するデータの種類をドキュメント化してくれます。

当社では TypeScript を徹底的に利用しています。型で表現可能なものはすべて型システムに落とし込み、意味合いを名前に込めることで「これは何か」「どこへ行くのか」を瞬時に把握できます。

UserId
WorkspaceSlug
SignedWebhookPayload
のようなセマンティックネームは意図を即座に伝えます。一方で
T
などの汎用名は小規模アルゴリズムでは有効ですが、実務システム内ではあまり役立ちません。

API 側では OpenAPI を使用し、型安全なクライアントを生成しています。データ側では PostgreSQL の型システムを最大限活用し、列タイプに収まらない不変条件はチェックやトリガーで補完します。PostgreSQL は豊富な型システムを持っていませんが、驚くほど多くの正確性を保証できます。エージェントが無効データを書こうとすると、DB が明確かつ大きくエラーを報告してくれます。Kysely を使えば TypeScript 用に型安全なクライアントを生成できます。

その他サードパーティクライアントは良い型を提供するものもあれば、自前でラップして型を付与します。


エージェントは疲れ知らずかつ時には素晴らしいコーダーですが、彼らの効果は置かれる環境に大きく左右されます。「良いコード」が余計なものではなく不可欠になる瞬間を体感してください。初期投資は税金のように感じられますが、これは長年回避してきた課題です。意図的に負担し、エージェント開発ロードマップに組み込み、エンジニアリングリーダーから資金を確保し、やっと実現したいコードベースを完成させましょう。

同じ日のほかのニュース

一覧に戻る →

2025/12/30 6:46

USPS(米国郵便公社)が切手印日付システムの変更を発表しました。

## Japanese Translation: > **概要:** > USPSは最終規則(FR Doc. 2025‑20740)を発行し、国内郵便マニュアルに「セクション 608.11 —『切手印と郵便保有』」を追加しました。この規則では、切手印の定義が正式に示され、該当する印記がリストアップされています。切手印は印付け日でUSPSがその物件を保有していることを確認しますが、必ずしもアイテムの最初の受理日と同一ではありません。USPSは通常業務で全ての郵便に切手印を貼らないため、切手印が欠落していても、その物件が未処理だったとは限りません。機械による自動切手印は、施設内で最初に行われた自動処理操作の日付(「date of the first automated processing operation」)を表示し、投函日ではなく、地域輸送最適化(RTO)や路線ベースのサービス基準により受理日より遅くなることがあります。切手印は小売ユニットからの輸送後やカレンダー日がまたがる場合に付けられることが多いため、郵送日を示す信頼できる指標ではありません。同一日の切手印を確保するには、小売窓口で手動(ローカル)切手印を依頼できます。小売窓口で料金を支払うと「Postage Validation Imprint(PVI)」が付与され、受理日が記録されます。また、郵便証明書、登録メール、または認定メールは提示日を裏付ける領収書として機能します。この規則の影響は税務申告において重要です。IRC §7502 は、文書が期限までに物理的に届けられなかった場合に、提出の適時性を判断する際に切手印の日付を使用しています。

2025/12/30 1:07

**Zig における静的割り当て** Zig のコンパイル時メモリ管理を使えば、実行時ではなくコンパイル時にストレージを確保できます。データ構造のサイズが事前に分かっている場合やヒープ割り当てを避けたいときに便利です。 ### 重要概念 - **コンパイル時定数** `const` や `comptime` の値を使い、コンパイラがコンパイル中に評価できるサイズを記述します。 - **固定長配列** リテラルサイズで配列を宣言します。 ```zig const buf = [_]u8{0} ** 128; // 128 バイト、すべてゼロ初期化 ``` - **静的フィールドを持つ構造体** 固定長配列やその他コンパイル時に決まる型を含む構造体を定義します。 ### 例 ```zig const std = @import("std"); // 静的サイズのバッファを持つ構造体 pub const Message = struct { id: u32, payload: [256]u8, // 256 バイト、コンパイル時に確保 }; // 静的割り当てを使う関数 fn process(msg: *Message) void { // ヒープ割り当ては不要;msg はスタック上またはグローバルに存在 std.debug.print("ID: {d}\n", .{msg.id}); } pub fn main() !void { var msg = Message{ .id = 42, .payload = [_]u8{0} ** 256, // すべてのバイトをゼロで初期化 }; process(&msg); } ``` ### 利点 - **決定的なメモリ使用量** – サイズはコンパイル時に分かる - **実行時割り当てオーバーヘッドがゼロ** – ヒープアロケータ呼び出しなし - **安全性** – コンパイラが境界と寿命を検証できる ### 使うべき場面 - 固定長バッファ(例:ネットワークパケット、ファイルヘッダー) - 短時間しか存続しない小規模補助データ構造 - 性能や決定的な動作が重要な状況 --- コンパイル時定数・固定配列・構造体定義を活用することで、Zig は最小限のボイラープレートで最大の安全性を保ちつつメモリを静的に割り当てることができます。

## Japanese Translation: > **概要:** > このプロジェクトは、Zigで書かれた軽量Redis互換のキー/バリューサーバー「kv」を構築し、最小限のコマンドセットで本番環境に適した設計を目指しています。コアデザインでは起動時にすべてのメモリを確保することで、実行中にダイナミックヒープを使用せず、レイテンシスパイクやユース・アフター・フリー(use‑after‑free)バグを回避します。接続は`io_uring`で非同期に処理され、システムは3つのプール(Connection、受信バッファプール、送信バッファプール)を事前確保し、デフォルトでは約1000件までの同時接続数をサポートします。各接続は設定パラメータから派生した固定サイズの受信/送信バッファを使用します。 > コマンド解析はRedisのRESPプロトコルのサブセットに従い、Zigの`std.heap.FixedBufferAllocator`を用いてゼロコピーで解析し、各リクエスト後にアロケータをリセットします。バッファサイズは`list_length_max`と`val_size_max`に依存します。 > ストレージは未管理型の`StringHashMapUnmanaged(Value)`を使用し、初期化時に`ensureTotalCapacity`で容量を確保します。キーと値は共有`ByteArrayPool`に格納され、マップはポインタのみを保持します。削除操作では墓石(tombstone)が残り、墓石数が増えると再ハッシュが必要になる場合があります。 > 設定構造体(`Config`)は `connections_max`、`key_count`、`key_size_max`、`val_size_max`、`list_length_max` などのフィールドを公開し、派生アロケーションで接続ごとのバッファサイズを決定します。デフォルト設定(総計約748 MB、2048エントリ)では `val_size_max` または `list_length_max` を倍増すると、割り当て量が約2.8 GBに上昇する可能性があります。 > 今後の作業としては、カスタム静的コンテキストマップ実装の改善、より良いメモリ利用を実現する代替アロケータの探索、境界検査(fuzz)テストの追加による限界確認、および墓石再ハッシュ処理への対応が挙げられます。

2025/12/27 20:30

**フレームグラフ 対 ツリーマップ 対 サンバースト(2017)**

## Japanese Translation: **概要:** Flame グラフ(SVG)はディスク使用量を高レベルで明確に示します。たとえば、Linux 4.9‑rc5 では `drivers` ディレクトリが全容量の50%以上を占め、`drivers/net` サブディレクトリは約15%です。Tree マップ(macOS の GrandPerspective、Linux の Baobab)は非常に大きなファイルを素早く検出できますが、高レベルのラベルが欠けています;Baobab のツリー表示では各ディレクトリの横にミニバーグラフが表示されます。Sunburst(Baobab の極座標図)は視覚的に印象的ですが、角度で大きさを判断するため長さや面積よりも誤解しやすいです。他のツール―`ncdu` の ASCII バーと `du -hs * | sort -hr` ―はテキストベースで迅速なサマリーを提供しますが、同時に一階層のみ表示されます。 提案されたユーティリティは、これら三つの可視化(Flame グラフ(デフォルト)、Tree マップ、Sunburst)すべてを組み合わせるものです。Flame グラフは読みやすさ・印刷性・最小スペース使用量が優れているため、多数のサンプルファイルシステムでテストした後にデフォルトとして採用されます。このアプローチは、ディスク使用量を簡潔かつ印刷可能なスナップショットとして提供し、ユーザーや開発者がスペースを占有する項目をより効率的に検出できるよう支援します。アイデアは ACMQ の「The Flame Graph」記事と「A Tour through the Visualization Zoo」に引用された既存の研究に基づいています。 **反映された主なポイント:** flame グラフの高レベルビュー、Tree マップの大きなファイルを素早く検出できるがラベルが欠けている点、Sunburst の視覚的魅力とサイズ認識の問題、他ツールの制限、および提案ツールの三つのビュー(デフォルトは flame グラフ)と引用元への参照。