どうも、マイクでーす。おはようございます。
二千二十六年八月二十五日、火曜日の朝七時を回りました。
ここからの時間は「zenncast」、きょうもZennで話題になっているトレンド記事を、ゆるっと楽しくご紹介していきます。
きょうは全部で五本、ご紹介していきます。技術スタックがっつりの話から、AIエージェントの実践記まで、結構バラエティ豊かなラインナップになってますので、気になるところだけつまみ聞きでもオーケーです。通勤・通学のお供にどうぞ。
まず一本目。
フロントエンド開発用のテンプレートリポジトリなんですが、「依存関係のサプライチェーン攻撃への対策」をかなり厚めに盛り込んでいる、というのがポイントの記事です。
パッケージマネージャーはピ―エヌピーエムを使っていて、`minimumReleaseAge` という設定で、新しく出たバージョンをすぐには採用せず、数日寝かせてから取り込むようにしているんですね。あわせて、Dependabot 側も `cooldown` で同じくクールダウン期間を設けて、怪しいリリースをつかまないようにしていると。
とはいえ、どうしてもすぐにアップデートしたい依存もあるので、そういう例外は `minimumReleaseAgeExclude` で個別指定できるようになっています。
GitHub Actions もセキュリティ意識高めで、アクションはコミットのシャー、つまりコミットのハッシュ値でバージョン固定。さらに pinact というツールで、その固定されたシャーを自動更新する運用にしていて、「最新すぎず・古すぎず」を仕組みで担保しているのが特徴です。
コード品質まわりもかなりストイックで、TypeScript セブンに加えて追加のオプションをガッツリ有効にして、Rust 製の Oxlint と Oxfmt、それからファイル名やディレクトリ構造をチェックする ls-lint、未使用コード検出の Knip まで入っています。
Oxfmt は、インポートの順番や Tailwind CSS のクラスの並び、さらには package.json の項目の順番まで自動整形してくれる前提で設計されていて、Knip が定期的に「使ってないコード」や「使われていない依存関係」を掃除する、という運用を見据えたテンプレートになっています。
Node.js や pnpm のバージョン管理も一工夫されていて、必要なバージョンは package.json に集約して記述します。で、pnpm の `devEngines` 機能を使って、必要なバージョンを自動ダウンロードして合わせる仕組み。
CI もその定義を参照することで、mise や Volta といった専用ツールを入れていなくても、「pnpm run 経由で実行すれば、みんな同じ環境で動く」という設計にしています。
フレームワークは Next.js で、App Router を前提にしつつ、Cache Components と呼ばれる、「use cache」や `cacheLife`、`cacheTag`、`updateTag` といった新しいキャッシュ関連の機能を積極的に採用しています。
あとは `proxy.ts` を使った API 呼び出しの集約、URL を型安全に扱える `typedRoutes` なんかも組み込まれていて、今っぽい Next.js のベストプラクティスをそのままテンプレート化したような内容です。
テストは Playwright を使っていて、ブラウザはクロミウムだけに絞った構成。並列実行を前提にして、ローカルと CI で `webServer` の起動方法を切り替えるなど、開発環境と自動テスト環境の違いもきちんと吸収するように作られています。
バックエンドまで TypeScript で書ききる前提のスタックもセットアップ済みで、Intent UI と Tailwind の組み合わせ、あるいは CSS Modules に Stylelint、データベースは Turso と Drizzle、認証は Better Auth、環境変数は t3-env と Zod でスキーマ化、といった構成になっています。ただ、これらはあくまで「一例」として入れてあって、プロジェクトごとに `.claude/skills/` ディレクトリから、必要なスタックに差し替える前提になっているのが面白いところです。
開発体験の面では、VS Code 用の設定も同梱されていて、Oxfmt と Oxlint をエディタと連携させたり、「page.tsx があちこちにあってどれがどれだか分からない問題」を解消するために、タブ名の表示をカスタマイズする設定も入っています。
Git hooks は Lefthook でまとめていて、コミット前に `lint:fix` と `format:fix`、それから ls-lint を走らせて、自動修正された内容をそのままステージし直す、という運用を想定しています。
さらにユニークなのが AI まわりで、AI エージェント用の使用ルールが `AGENTS.md` に整理されていて、Claude 向けにはシンボリックリンクで共有。MCP サーバー、たとえば deepwiki や context7、Playwright MCP なんかもあらかじめ設定してあって、エージェントからすぐ使える状態になっています。
npx で起動する MCP ツールについても、ちゃんとバージョンを固定していて、「AI がコードを書く量が増えるほど、ツールと設定の重要度はどんどん上がる」という前提で作り込まれているんですね。著者自身、急速に変化するフロントエンドのツールチェーンに追随しながら、安全対策もテンプレートに継続的に取り込んでいく姿勢をはっきり打ち出しているのが印象的な記事でした。
。。。。
続いて二本目。
こちらはがっつり Linux の世界、「Ctrl+C を押したら中で何が起きているのか」を、カーネルレベルまで追いかけて説明している記事です。オピニオンというより、仕組みを解説する Tips 寄りの内容ですね。
まず、キーボードから実際に送られているのは、ゼロエックスゼロスリー、十六進数でゼロスリーの一バイトの制御文字、これは ETX、End of Text と呼ばれるものです。
この制御文字を受け取るのが、ターミナルデバイスの「ラインディシプリン」と呼ばれる層で、ここが `termios` の設定、具体的には `ISIG` と `VINTR` の設定に従って、このゼロエックスゼロスリーを `SIGINT` シグナルに変換します。
おもしろいのは、このシグナルは「一個のプロセス」にだけ飛んでいるわけではなくて、「フォアグラウンドプロセスグループ」全体に送られるということ。
たとえば、コマンドをパイプでつないでいるとき、その一連のパイプライン全体が一つのプロセスグループとして扱われていて、Ctrl+C を押すと、そのグループ全体がまとめて止まります。一方で、シェル自身は別のプロセスグループになっていて、なおかつ独自のシグナルハンドラを持っているので、Ctrl+C では終了しない、という仕掛けになっているんですね。
`SIGINT` が届いたからといって、すぐにプロセスが止まるわけでもありません。各スレッドがカーネルモードからユーザーモードに戻る直前、具体的には `exit_to_user_mode_loop` から `get_signal` に処理が進むタイミングで、「pending なシグナル」として処理されます。
ここで、そのシグナルに対してユーザー側でハンドラが登録されていなければ、`sig_fatal` という処理に回されて、「これは致命的なシグナルだ」と判定される、という流れです。
致命的だと判断された時点で、`complete_signal` という関数が `SIGNAL_GROUP_EXIT` というフラグを立てます。これによって、プロセス内の全スレッドに `SIGKILL` が積まれていって、「プロセス全体を終了させる準備」を、シグナルを送った側で一気に始める形になります。
その後、`do_group_exit` から `do_exit` へと処理が進んで、個々のスレッドとプロセス全体が終了し、終了コードとしてはシグナル番号、つまり二番が残る、というわけです。
そしてシェル側では、`wait` 系のシステムコールを使って子プロセスを待ち受けていて、「あ、このプロセスはシグナルで終わったな」と認識すると、「シグナル番号エヌに百二十八を足した値を終了ステータスにする」という慣習に従います。
そのため、`SIGINT` の場合はシグナル番号が二なので、百三十という値になって、`$?` に百三十が入る、というおなじみの挙動になるんですね。普段なんとなく押している Ctrl+C の裏側で、ここまできっちりした仕組みが動いているのか、というのが分かる、読み応えのある記事でした。
。。。。
三本目は、プログラミング言語の話題。
テーマは「PHP の参照渡し」と「Go のポインタ」。仕組みとしてはぜんぜん別物なんだけれども、どちらも「関数の外側にある状態を書き換えられる」という点で共通していて、その副作用への警戒心こそが、著者が感じていた抵抗感の正体だったのでは、という整理をしている記事です。
Go では、引数はすべて値渡しだ、というのが仕様上の建付けになっています。ポインタを渡しているときも、「アドレスという値のコピー」を渡しているに過ぎないんですね。
ただ、そのアドレスを通じて `*p` のように参照先のデータを書き換えることができてしまうので、結果として「関数呼び出しの外側の状態が変わる」という意味では、PHP の参照渡しとかなり似た副作用が生まれうる、という指摘です。
ここで著者が強調しているのは、「危険なのは言語機能そのものではない」ということ。
本質的に怖いのは、複数の場所から共有している状態を、意図せず変更してしまうことなんだ、と。なので、「ポインタだから危ない」という単純な話ではなく、そのポインタ経由で「どの状態が、どこから書き換わりうるのか」をきちんと理解したうえで使うべきだ、と整理しています。
そして、いまは AI がコードを自動生成してくれる時代になりつつありますが、それでも、「このコードにはどんな副作用があるのか」「どこまでが安全に書き換えられる範囲なのか」を見抜くには、やっぱり言語の仕組みそのものを理解している必要がある、と。
自分でゼロからコードを書く量は減っていくかもしれないけれど、他人や AI が書いたコードを読み、挙動を判断する力、つまり「読む力」の重要性は変わらない、というメッセージで締めくくられています。ポインタや参照渡しにモヤっとしている人に、けっこう刺さる内容じゃないかなと思いました。
。。。。
四本目は、少しオピニオン寄りの事例紹介。
テーマは「複数のプラットフォームや計測サービスに散らばったイベント定義を、どう管理するか」という問題に対して、AI を使ってコードを読み、イベントカタログを自動生成する仕組みを作った話です。
いまどきのプロダクトって、ウェブ、モバイルアプリ、サーバーサイド、それぞれでイベントを送っていて、さらに計測サービスも複数使っていたりしますよね。
そうすると、「どこでどんなイベントが送られているのか」という一覧を、人手でちゃんと最新に保つのはほぼ不可能に近い。そこで筆者は、AI にコードを読ませてイベントカタログを作らせる、というアプローチを取っています。
ただし、ここで強調されているのが、「プロンプトをいじって AI の出力品質を上げるだけではぜんぜん足りない」ということ。大事なのは、生成した後にどう検証するか、その「検証構造」を設計することが本質だ、という主張です。
具体的には、品質を担保するために四つのレイヤーを用意しています。
まず一つ目は、シンボル名やファイルパスなど、「あとでコードと機械的に突き合わせられる情報」を必須にしたスキーマを決めること。これによって、「人間しか分からない曖昧な説明」ではなく、あとで機械的にチェックできる形でイベント情報を持てるようにしています。
二つ目は、grep 的な決定論的スクリプトで、「本当にそのシンボルやパスがコード上に存在するのか」をチェックする仕組み。ここは純粋にツールでの存在確認なので、AI の気まぐれに左右されない、堅い検証レイヤーになります。
三つ目は、「生成と独立した検証エージェント」を用意すること。これはコード側からイベントを列挙させて、AI が作ったカタログと突き合わせることで、漏れがないか、あるいは AI が勝手に作ったハルシネーションが混ざっていないか、というのを両側からチェックする役割を担っています。
四つ目は、用語対応表を使った説明文の意味チェックです。ドメイン固有の用語が正しく使われているか、イベントの説明文が仕様とズレていないか、というところを、自動的に検査していくイメージですね。
このプロセスを回していく中で、面白いのは、「AI の間違い」だけじゃなくて、人間が書いた実装や設定のバグまで炙り出せた、というところです。
たとえば、同じイベントが二重に送られていたり、設定されているけれど実際にはどこからも呼ばれていないトリガーが見つかったり。結果的に、「正確なイベントドキュメントを作る」という作業そのものが、実装の健康診断になった、と総括しています。
筆者が最後に強調しているのは、イベントログに限らず、「コードの中にしかない一覧情報」を AI で扱うときの設計のポイントです。
AI に任せる範囲をどんどん広げていきながらも、「いつでも AI をやめられるようにしておく」こと。そのために、中間フォーマットと検証レイヤーをきちんと分離しておくことが重要だ、と。AI に全部おまかせ、ではなく、AI と決定論的なチェックを組み合わせることで、安心して自動化していくための知見がまとまった記事になっています。
。。。。
そして最後、五本目。
こちらは AI エージェント開発に「ループエンジニアリング」という考え方を持ち込んだ実践記です。筆者自身のワークフローの甘いところを、Claude Code に洗い出してもらいながら、その改善プロセスを整理していった内容になっています。
従来のフローでは、人間が毎回、Issue を起票したり、レビュー依頼を出したりと、細かい指示を手動で行っていて、自動化、いわゆる Automations がほとんどなかったそうです。
「新しい仕事を見つけてくる」のも、「タスクが完了したかどうかを判断する」のも、ほぼ人間任せで、エージェントは指示されたことをこなすだけ、という状態だったと。
これに対して筆者は、まず「評価観点」と「合否の条件」をきちんと分けて定義し、明確な評価基準と停止条件を用意します。
そのうえで、客観的に判定できる状態遷移とタスク台帳を整備して、人間が必ず見なければならない確認ポイントを最小限に絞り込んでいく、という再設計を進めていきます。
さらに、「間違えてもちゃんと戻せるかどうか」と「影響範囲がどこまで広がるか」という二つの軸で、人間が必ず承認すべき作業と、エージェントに任せてもよい作業を仕分けしています。
Issue を新しく作る、いわゆる「仕事の発見」の部分についても、その結果がどれだけ検証可能か、AI の確信度はどのくらいか、といった観点で、「自動的に採用する」か「人手で確認してから通す」かを切り分ける設計になっています。
最終的には、この一連の設計をすぐに使い回せるようにする「ハーネスキット」を作成しています。
進捗を見える化するダッシュボードや、プロジェクトごとにカスタマイズ可能なレビュー観点なども備えていて、「ちゃんとループを設計されたエージェント運用」をテンプレ化しようとしているんですね。
一方で、まだ稼働状況の監視が十分ではなくて、「完全な自律運転」というところまでは到達していない、と自己評価していて、今後の発展余地についても正直に触れられています。AI エージェントを実運用に乗せたい人にとって、具体的なヒントが多い記事でした。
。。。。
ということで、きょうの「zenncast」は、全部で五本ご紹介しました。
サプライチェーン攻撃対策や AI 連携まで込み込みのフロントエンド用テンプレートリポジトリの話。
Ctrl+C の裏側で、Linux カーネルがどうやって `SIGINT` を扱っているのか、という低レイヤー解説。
PHP の参照渡しと Go のポインタをきっかけに、「副作用」と「コードを読む力」に向き合う記事。
AI でイベントカタログを自動生成しつつ、四層の検証構造で品質を担保する事例紹介。
そして最後に、ループエンジニアリングの考え方で AI エージェントのワークフローを再設計していく実践記。
気になるトピックはありましたでしょうか。
それぞれの記事の詳しい内容や、気になった用語なんかは、番組のショーノートにもまとめてありますので、あとでゆっくりチェックしてみてください。
この「zenncast」では、番組の感想や、「こんなテーマを取り上げてほしい」といったリクエストもいつでも募集中です。日常の開発でモヤっとしていることなんかも、ぜひ気軽に送ってください。
というわけで、そろそろお別れの時間です。
きょうも最後までお付き合いいただき、ありがとうございました。
次回の配信でまたお会いしましょう。マイクでした。