#
832
どうも、マイクです。おはようございます。
八月三十日、日曜日の朝七時をまわりました。「zenncast」今日も元気にお届けしていきます。

この番組では、開発者向けプラットフォーム Zenn に載っている、いま気になるトレンド記事をラジオ感覚でご紹介していきます。通勤・通学の支度をしながら、あるいはコーヒー飲みながら、ゆるっと聞いていってください。

今日は、全部で五本の記事をピックアップしてご紹介します。フロントエンドのテンプレート作りから、AIエージェントとの協業フロー、CLAUDE.md のお片付けテク、`Ctrl+C` の裏側のしくみ、そして OpenTelemetry でセッションを追跡する話まで、わりとガッツリめのテック特集でお送りします。好きなところだけ拾い聞きしてもらってもオーケーです。

。。。。

まず一つ目は、「フロントエンド開発用のテンプレートリポジトリ、なに入れておく?」という内容の記事です。
筆者の方が、自分で育てているテンプレートリポジトリに、どんな設定やツールを詰め込んでいるのか、かなり具体的に紹介してくれています。

パッケージマネージャーは pnpm を使っていて、`minimumReleaseAge` という機能を活用しています。これは、新しく出たパッケージのバージョンが、リリースされてからある程度時間が経つまで、自動では拾わないようにする仕組みですね。あわせて Dependabot では `cooldown` を使って、依存関係の更新タイミングを少し寝かせる。こうすることで、サプライチェーン攻撃への対策と、依存パッケージ更新の安全性を高めています。「一番新しいバージョンを即入れる」のではなく、「ちょっと様子を見る」という設計をテンプレートの段階から入れておく、という発想です。

さらに `devEngines.runtime` を使って Node.js のバージョンを固定しつつ、pnpm 側に Node を自動ダウンロードさせる構成にしていて、わざわざ nvm とか別のバージョン管理ツールを入れなくても済むようにしています。これも、新しくプロジェクトに参加した人が環境をそろえやすくする工夫ですね。

言語まわりでは TypeScript 七点ゼロの高速コンパイラを採用。未使用のコードを検出するために Knip を入れていて、さらに Oxlint と Oxfmt、それから ls-lint を組み合わせて、コード品質のチェックと自動整形を回しています。いわゆる「いらないコードを放置しない」「フォーマットの揺れをなくす」というところを、ツールに全部任せるイメージです。

CI・CD 周りだと、GitHub Actions のアクションはバージョンをコミットの SHA でガッチリ固定して、pinact というツールで管理しています。そこに Dependabot を組み合わせることで、「どのアクションが、いつ、どう安全に更新されたか」がちゃんと追えるようになっています。
アプリ側のスタックとしては、Next.js 十六、Tailwind CSS、データベースに Turso、それから認証は Better Auth を選定していて、なぜこの組み合わせなのか、という理由もセットで書かれています。Next.js 十六の Cache Components や `typedRoutes` のような新しめの機能を前提にしていたり、E2E テストは Playwright を使ったりと、モダンなフロントの標準セット、という感じですね。

面白いのが、AI の利用を前提にした開発フローもテンプレートに組み込んでいる点です。たとえば AGENTS.md というファイルを置いて、AI エージェントをどういうルールで動かすか、役割分担や制約を書いておく。これによって「AI に丸投げする」ではなく、「AI にどこまでやってもらうか」が明文化されているので、チーム開発に乗せやすくなるんですね。
プロジェクトを始めるたびに同じ設定を書くのがしんどい方や、テンプレをちゃんと整えたいな、と思っている方には参考になりそうな記事でした。

。。。。

続いて二つ目は、その AI エージェントとの「協業フロー」をもっと深掘りしたお話です。
筆者の方が、自分の開発フローを「ループエンジニアリング」という観点から AI に評価させてみたところ、「Automations」、つまり自動で仕事を見つけてそれを進める部分が弱い、と指摘されたんですね。そこから、どうやってその弱点を改善していったかを、かなり細かく検証しています。

もともとのフローだと、人間が Issue を作ったり、レビューの指示を出したりを都度やっていて、しかもどんなタスクでも同じように、人間の承認を毎回待つ、というスタイルでした。そうすると、「仕事を見つけるのは人間の仕事のまま」で、さらにスループットの上限が、人間の確認サイクルに縛られてしまうんですね。

そこでまず、「評価観点」と「評価基準」を分けて、明確な停止条件を定義し直します。Issue やプルリクエストを管理する台帳に、「requires human review」といった状態を追加して、「ここは人が絶対見ないといけない」「ここは機械的なチェックでいい」といった境目を、状態として表現できるようにしたんです。

さらに一歩進めて、タスクの「可逆性」と「影響範囲」でゲートを仕分けます。
たとえば「すぐ戻せて、影響も小さい作業」については、自動実行してしまって、あとから人間がサマリだけ確認する。逆に「戻すのが難しくて、影響も大きい作業」だけ、同期的に人間の承認を残すようにして、人間の介入の濃さにグラデーションをつけました。
加えて、Issue ツリーを自動生成させるなど、「そもそも仕事を発見してくる」部分も、どんどんエージェント側に寄せています。このとき、「検証可能性」と「確信度」を掛け合わせた指標を用意して、その値が高いものは自動採用、低いものは人間確認、というように切り分ける枠組みも導入しています。

この一連の知見をもとに、「このリポジトリにキットを入れるだけで、このフローが回り出す」というハーネスキットも試作しています。ここでは、プロダクトマネージャー、オーケストレータ、デベロッパー、レビュワーといった役割を、それぞれ AI エージェントが持ち回りで担当する構成にしていて、レビュー観点を新しくファイルを追加するだけで拡張できるようになっていたり、台帳から作業状況をダッシュボードで可視化できるようになっていたりします。

ポイントは、エージェントの「自己申告」を信用しすぎないこと。ちゃんと客観的に検証できる基準を用意して、「この条件を満たしたら進めていい」「満たさなければ止まる」という機械的な判断に置き換えているところです。
そして、人間の確認をゼロにするのではなくて、「いつ」「なぜ必要なのか」をちゃんと設計して、そこに濃淡をつける。これがループエンジニアリングの肝だよね、という結論になっています。AI と一緒に開発してみたいけど、レビューとか責任分界をどうしよう、って悩んでいる方には刺さる内容だと思います。

。。。。

三つ目は、CLAUDE.md をどうやって破裂させないか、という運用テクニックの記事です。
Claude を使っていると、だんだん CLAUDE.md にいろんなルールや手順を書き足していきますよね。その一つひとつは、その場では「これも必要だよね」と思って追加しているので、どれも正しい判断に見える。ところが気づくと、行数もファイルサイズも、気持ちよくないくらい膨れ上がってしまう。これが悩みのタネになっている、という話からスタートします。

公式の機能として、ドキュメントを整理してくれるツールや、`/doctor` みたいなコマンドもあるんですが、一度きれいにしても、時間が経つとすぐ元通りになりがち。そこで筆者は、「整理の仕方を工夫する」のではなく、「そもそも膨らむ前に止める仕組み」を作る方向に振り切りました。

具体的には、Claude Code のフック機能を使います。
「ファイルが書き込まれた、その瞬間」にシェルスクリプトを実行して、CLAUDE.md のバイト数を計測します。そして、決めておいた上限を超えたら、警告メッセージを Claude に返すようにしているんですね。つまり「書き込んだ瞬間にアラートが鳴る」仕掛けです。

このスクリプトが賢いのは、「削除しろ」とは言わないところです。代わりに、「削除ではなく、置き場を変えよう」という方針を Claude に伝えます。たとえば、常に読む必要はない手順書なんかは `docs/` ディレクトリに移す。特定の一つのファイルにだけ効くルールは `.claude/rules/` に移動する。もう期限切れで使わないルールは `docs/archive/` に送ってしまう。
そして、CLAUDE.md の本体には、「いつどの文書を開くか」というトリガーの一行だけを残すようにします。
これによって、「知識は消さないけど、CLAUDE.md に全部押し込めない」というバランスがとれるようになっています。

導入前後の数字も出ていて、仕組みを入れる前は七日間で行数が約二・二倍に増えていたのに対して、導入したあとの七日間では、ほぼ横ばいになったそうです。もちろん、導入直後でいったん整理したあとなので、数字は多少バイアスがあるよね、という注釈付きなんですが、それでも「書き込んだ瞬間に注意喚起が出る」ことが、リバウンドを防ぐ予防線としてかなり効いていると分析しています。
CLAUDE.md がパンパンでつらい、という方には、すぐ試せそうなアイデアが詰まった記事になっていました。

。。。。

四つ目は、`Ctrl+C` を押したとき、Linux の中では具体的に何が起きているのか、という低レイヤー寄りの記事です。
普段なんとなく「`Ctrl+C` で止まるよね」と思っているコマンドが、実はどういう流れで止まっているのかを、tty とシグナルのレベルから解きほぐしています。

まず、キーボードで `Ctrl+C` を押すと、ASCII の制御文字である `ゼロエックスゼロスリー`、いわゆる ETX が、tty に届きます。tty の中には行編集の処理をしている部分があって、ここで `termios` の設定を見ています。この設定で `ISIG` というフラグが有効になっていて、なおかつ「割り込み文字」が `キャレットシー` に対応している場合、tty は `ゼロエックスゼロスリー` を普通の入力としては渡さずに、`SIGINT` シグナルに変換します。

この `SIGINT` を、tty はいま前面で動いているプロセスグループ、いわゆるフォアグラウンドプロセスグループの全員に送ります。パイプでつないだ複数のコマンドや、`npm run dev` の裏側で動いている複数のプロセスが、一度にまとめて落ちるのはこのためですね。対して、シェル本体は別のプロセスグループになっているので、基本的には巻き込まれません。

`SIGINT` シグナルは、届いた瞬間に「すぐ効く」わけではなくて、まずは「pending」、保留中のシグナルとしてプロセスに記録されます。その後、カーネルからユーザーモードに戻る直前の共通ルーチンで、この pending を確認して、そこで既定の動作をとるか、ユーザー定義のシグナルハンドラを呼ぶかを決めます。

もしプログラムが `SIGINT` 用のハンドラを自前で登録していない、つまり `SIG_DFL` のままにしている場合、カーネル側ではこれを「致命的なシグナル」とみなして、「プロセス全体を終了させる」というフラグと、終了コードをセットします。`SIGINT` の番号は二番なので、終了コードは二ですね。
各スレッドがユーザーモードに戻ってきたタイミングで、この情報にもとづいて `do_group_exit` や `do_exit` が呼ばれて、プロセス全体が終了する、という流れです。

そのあと、シェルは `wait` 系のシステムコールで、子プロセスがどういう理由で終わったかを受け取ります。ここで「シグナル二番で死んだんだな」と分かるので、そのシグナル番号に百二十八を足して、終了ステータス、つまり `$?` に入れています。なので、`Ctrl+C` でコマンドを止めたあとに `$?` が百三十になっているのは、「カーネルがシグナル二番で終わったことを教えてくれて、それをシェルが百二十八足して百三十にしているから」という説明になります。
ふだん何気なく叩いているキーボード操作の裏側が、ここまできちんと決まった流れで動いているのが分かる、読み応えのある記事でした。

。。。。

最後、五つ目は、OpenTelemetry を使って、フロントエンドから複数のバックエンドまで、ユーザの操作をセッション ID で一気にたどれるようにする方法を紹介した記事です。分散システムで「このユーザの、この一回の操作が、システム全体でどう流れたか」を追いたいときの、お手本みたいな構成になっています。

キーワードは、トレースとスパン、それから「Baggage」と呼ばれる追加情報の仕組みです。これらをコンテキスト伝播と組み合わせることで、「一つの操作に紐づく処理のかたまり」を、サービスをまたいで追いかけられるようにします。

サンプル構成としては、フロントエンドが React、バックエンドが Spring Boot、その先に外部システムがいる、という三層くらいのシステムを想定しています。そこに OTel Collector、Grafana Tempo、Grafana を `docker-compose` で立てて、トレースを可視化します。
ブラウザ側では JavaScript の SDK を使って `fetch` を自動計測しつつ、`session.id` をすべてのスパンと Baggage に載せてバックエンドへと渡していきます。

Spring Boot や外部システム側では、Java Agent を使うことで、HTTP の受信や RestTemplate の呼び出し、`traceparent` と `baggage` ヘッダの付与なんかが自動化されます。そこに少しだけカスタムフィルタを足して、`session.id` をスパンの属性として記録しておく。こうしておくと、Grafana 上でセッション ID をキーに、あるユーザの一回の操作に関わったすべてのサブシステムの処理時間やログを、時系列で一望できるようになります。

筆者が強調しているのは、コード変更ほぼなしで計測を始められる Java Agent の強さです。エージェントを入れて設定するだけで、「とりあえずの見える化」ができてしまう。そこから必要なところだけカスタムしていけばいいので、導入のハードルが思ったより低い。
さらに、フロント側でカスタムスパンを切ることで、「ボタンクリックから処理完了まで」といった、ユーザにとって意味のある単位で可視化できる点もメリットとして挙げています。Baggage にセッション情報を載せておくことで、セッションをまたいだ横断検索もしやすくなり、運用の現場でかなり役立つとのことです。
全体として、OpenTelemetry は「設定する場所が多くて大変そう」というイメージを持ちがちなんですが、実際には思ったより少ない設定で始められるし、分散トレーシングの恩恵も大きいよ、というメッセージになっていました。

。。。。

というわけで、今日の zenncast は五本立てでお届けしてきました。
ざっとおさらいすると──

一つ目は、pnpm や TypeScript 七点ゼロ、Oxlint や Knip、GitHub Actions と Dependabot の組み合わせ、そして Next.js 十六や Turso、Better Auth まで含めた「フロントエンド開発用テンプレリポジトリ」の中身と、その設計思想のお話。
二つ目は、AI エージェントとの開発フローをループエンジニアリングの視点で見直して、Automations を強化しつつ、人間の確認ポイントにグラデーションをつける、という実践的な改善プロセス。
三つ目は、CLAUDE.md が気づくと膨らんでしまう問題に対して、書き込んだ瞬間にバイト数をチェックしてアラートを出し、「削除ではなく移動」でリバウンドを防ぐ運用テクニック。
四つ目は、`Ctrl+C` を押したときに、tty の設定から `SIGINT` に変換されて、プロセスグループ全体がどうやって終了していくのか、そしてなぜ `$?` が百三十になるのか、という Linux の裏側のしくみ。
そして五つ目は、OpenTelemetry と Grafana の組み合わせで、フロントから複数バックエンドまでをセッション ID で一気にたどれるようにする、分散トレーシング入門でした。

気になった記事があれば、詳しい内容やリンクはショーノートにまとめてありますので、そちらから原文もぜひチェックしてみてください。読むとまた、ラジオでは話しきれなかった細かい工夫やコード例がたくさん載っています。

番組の感想や、「こんなテーマを取り上げてほしい」といったリクエストも、いつでもお待ちしています。あなたの開発の現場で今気になっていること、困っていることなんかも、ぜひ教えてください。

それでは、今朝はこのへんで。
お相手はマイクでした。また次回の「zenncast」でお会いしましょう。良い一日をお過ごしください。

Related episodes

内容の近いエピソードを推薦しています