どうも、マイクです。おはようございます。
九月二十八日、月曜日の朝七時になりました。
ここからの時間は「zenncast」、きょうもZennのトレンドから気になる記事を、わいわい紹介していきますよ。
さて、きょう紹介する記事はぜんぶで五本です。
個人サイトの検索から、RustとCのガチ連携、HTTPスリーとQUIC、Gitのちょっとマニアックなブランチの話、そしてAIで開発スタイルをどう変えていくか、というところまで幅広くいきます。それぞれかなり実戦的な内容なので、気になったものがあったらあとでショーノートもチェックしてみてください。
では、一つ目。
まずは、個人サイトのページ内検索を、Cloudflareと「Jev」プラスベクトル検索で、ほぼゼロ円運用しつつ高品質にする、というTips系の記事です。
この「Jev」っていうのがポイントで、いわゆる文章をべらべら生成するタイプのモデルじゃなくて、「これ関連してる?」「これ本当に正しい?」みたいなことを数値で返してくれる、判定専用のLLMなんですね。速くて安くて、しかも教師データなしでそのまま使える、というのが売りになっています。
記事の構成としては、まずCloudflare Workers AI の「ビー・ジー・イー・エム・スリー」というモデルで、記事本文をベクトル化して、それを Cloudflare Vectorize に保存します。で、検索のときは「ベクトル検索でだいたい二十件くらいに候補を絞る → その二十件を、Jev の Noul 形式で関連度を再判定してリランク → 閾値、いき値をゼロ点二以上にして、その中からスコア順に返す」という三段構成になってるんですね。
おもしろいのがコストで、検索一回あたり、約ゼロ点ゼロゼロゼロ二ドル。日本円にすると、もう月に数円レベルで運用できちゃう。個人サイトでもぜんぜん現実的な価格ですし、TypeSafe AI の無料クレジットがあるあいだは、完全に無料運用もできてしまう、と。
具体例として、「Go Proposal」というサイトの検索で、「ジェネリクス」のように背景知識が必要なクエリを投げたときに、Google のサイト内検索よりも関連度の高い結果が出ている、という検証もされています。単に文字列を拾ってくるだけじゃなくて、そのドメインの知識を踏まえた検索ができている、というのがちゃんと確認されているんですね。
一方で課題もあって、レイテンシ、つまりレスポンスの速さのところでは、Jev のサーバーが海外にあって、さらに Cloudflare の AI Gateway との接続維持の問題もあって、リクエストの間隔があいちゃうと、一秒以上かかることがあるそうです。なので、レスポンスの速さがクリティカルなサービスで使うときは、この構成でいいのかどうか、ちょっと注意が必要だよ、という話もされていました。
全体としては、Cloudflare のスタック、Workers と Workers AI、Vectorize、それから AI Gateway に Jev を組み合わせることで、昔だったら「LIKE検索でがんばるか、Elasticsearch立てるか」みたいな規模のサイトでも、機械学習ベースの、いわゆる「賢い検索」を、すごく安く組み込める、というのをデモしている記事になっています。個人ブログに検索機能をちゃんと入れたい人には、かなり刺さる内容じゃないかなと思いました。.. ..
さあ、二つ目の記事は、Rust と C 言語の世界をぐっと近づける、ちょっと攻めたライブラリ「cinrs」の紹介です。
このライブラリ、なにがすごいかというと、Rust のコードの中に、C 言語のコードをそのまま直接書けちゃうんですね。「シー・ナインティナイン・びっくりマーク」みたいなマクロの中に C のコードを書いておくと、内部でその C を解析して、同じ意味を持つ Rust のコードを自動生成してくれる。つまり、完全な C コンパイラが中に内蔵されている、というかなり野心的な仕組みになっています。
対応範囲も広くて、C の `struct` だったりビットフィールドだったり、プリプロセッサ、標準ヘッダ、システムヘッダまで面倒を見てくれる。なので、単純なサンプルコードだけじゃなくて、リアルなCコードもかなりのところまでRustに変換できるようになっています。
生成される関数は、基本的には `unsafe` なんですけれども、特別なアトリビュートをつけて「これは安全な関数ですよ」と注釈しておくと、Rust側では「safeな関数」として扱えるようになります。このときの安全性のチェックは、Rustの型システムがちゃんと担当してくれるので、「FFIでつなぐより、少しは安心して使えるようにしよう」という方向の設計になっています。
ユースケースとしては、`bindgen` のようにヘッダファイルから FFI を作る用途とか、既存の C プログラムを段階的に Rust に移植していきたいときとか、「一部だけどうしても C で書きたい」みたいな場面、あるいは C コードを miri で検証してみたい、といったときに、「いままで既存ツールだといろいろ面倒だったことを、もっとシンプルにできるよ」というのが売りになっています。
対応しているCのバージョンも幅広くて、Cエイティナインから、最新のCトゥエンティスリー、それからGNU拡張の多くもカバーしているそうです。ベンチマークでも、gcc や clang とほぼ同等の性能が出ているということで、「変換してRustにしたら遅くなるんじゃないの?」という心配も、かなり小さいレベルに抑えられています。
とはいえ、なんでもかんでもOKというわけではなくて、`setjmp` と `longjmp` のような高度な機能とか、スタック上の可変長配列、それから可変長引数の完全な対応あたりは、Rust側の仕組みがまだ追いついていない部分もあって、制限があります。このあたりは、Rust の C 連携機能がもっと進めば、将来的に改善されていくだろう、という期待も込めて書かれていました。CからRustに移行したいチームには、なかなか夢のあるライブラリですね。.. ..
続いて三つ目。
ここからはプロトコルの世界にいきましょう。HTTPスリーと QUIC の解説、それから Docker を使った検証手順をまとめた、こちらもTips系の記事です。
HTTPスリーって、ついつい「HTTPツーの次なんでしょ?」くらいに思いがちなんですけれども、この記事では、「いやいや、単なるバージョンアップじゃないんだよ」というところを丁寧に説明してくれています。何が変わったかというと、なんと、三十年以上使われてきた TCP をやめて、UDP の上に新しいプロトコル「QUIC」を載せる、という大きな土台替えをやっているんですね。
これによって、たとえば「一個のパケットロスで、関係ない通信まで全部足止めされちゃう」とか、「Wi‑Fi からモバイル回線に切り替わると接続そのものが切れる」とか、TCP が避けようのなかった根本問題を、なんとかしようとしているわけです。
QUICでは、通信を「ストリーム」と呼ばれる単位に分けて、それぞれ独立して順序を管理します。これによって、あるストリームでパケットロスが起きても、別のストリームは止まらない、いわゆる Head-of-Line ブロッキングを避ける設計になっています。さらに、接続をIPアドレスやポート番号ではなく、「コネクションID」という識別子で管理するので、途中で経路が変わっても、同じ接続として通信を続けられるんですね。
暗号化のところも筋がよくて、TLSワン・ドット・スリーを内蔵していて、往復一回で暗号化済みの接続を張れるようになっています。その結果、HTTPスリーには、平文通信というものが存在しない。最初から「HTTPS前提」な世界になっているわけです。
クライアント側の挙動もおもしろくて、ブラウザや curl は、最初からいきなり HTTPスリーでつなぎにいくわけではありません。まずはTCP、つまり多くの場合はHTTPツーで接続して、サーバから送られてくる `Alt-Svc` ヘッダで「ここはエイチ・スリーも使えるよ」と教えてもらって、次回以降のアクセスでHTTPスリーに切り替える、という流れになっています。
ここでハマりポイントになるのが curl で、`--alt-svc` オプションでキャッシュファイルを指定しない限り、この Alt-Svc を無視しちゃうんですね。なので、なにも設定しないで curl を叩いていると、「あれ、ずっとHTTPツーのままなんだけど?」ということになります。この挙動をちゃんと理解しておくのが大事だよ、という注意が書かれていました。
記事では、Docker 上に Caddy サーバーと curl クライアントのコンテナを立てて、実際に動作を検証しています。その結果として、「ふつうにアクセスすると最初はHTTPツーになる」「Alt-Svc を保存して、二回目以降のアクセスになると、HTTPスリーに切り替わる」という挙動が、きれいに確認できたそうです。
さらに、NATで途中の送信元ポートを変えるような状況を作ってみると、HTTPスリーはコネクションIDのおかげで、転送を最後まで完走できる一方、HTTPツーは「別の接続だ」とみなされて途中で中断してしまう、という違いも観察されています。「理論上こうなるはず」が、Docker環境でもちゃんと再現できた、というのが分かりやすくまとまっていました。.. ..
四つ目は、Git のちょっと通な使い方、過去の履歴を引き継がない新しいブランチ、「オーファンブランチ」の作り方を、三つのコマンド別に紹介している記事です。
オーファンブランチで作る最初のコミットは、親を持たない「ルートコミット」となって、既存の履歴から完全に独立したタイムラインになります。「このリポジトリの中に、まったく別プロジェクトみたいな履歴をもうひとつ作りたい」とか、「公開用だけ履歴をきれいにしたい」といったときに使えるテクニックですね。
まずひとつ目のやり方が、`git checkout --orphan <new-branch> [<start-point>]`。
これは、既存のコミットを起点に、いわゆる「まだ一度もコミットしていないブランチ」、unbornブランチを作るコマンドです。デフォルトだと、今のHEADの内容がそのまま作業ツリーとインデックスにコピーされます。そこから不要なファイルを消したり、いったん `git rm -rf .` で全部空っぽにしてから、必要なものだけを追加して、「別履歴として再スタートする」という使い方ができます。
二つ目が、`git switch --orphan <new-branch>`。
こちらは、最初から作業ツリーもインデックスも空の状態で、unbornブランチを作ります。さっきの checkout 版と違って、どのコミットを起点にするか、`<start-point>` は指定できないんですけれども、「とにかくまっさらに始めたい」という場合には、こっちの方がシンプルで分かりやすいです。
そして三つ目が、`git worktree add --orphan <path>`。
これは、新しい作業ディレクトリを丸ごと追加して、その中でオーファンブランチを始める、という形になります。`git switch --orphan` と同じく、空の状態からスタートできるんですが、別ディレクトリで平行作業したいときに、とても便利です。`-b` オプションを付けてあげると、ブランチ名をパスとは別に指定できますので、「ディレクトリ名とブランチ名は変えたい」という人にも対応しています。
「履歴は分けたいけど、同じリポジトリで管理しておきたい」というときに、知っておくと役に立つテクニックが、かなり整理されて紹介されていました。.. ..
さあ、最後、五つ目の記事です。
ここでは、AIを使って開発効率を上げるための考え方と、具体的なやり方を、オピニオンとTipsのあいだくらいのスタイルで解説しています。
まず、なぜ「AIにコードを書かせているのに、ぜんぜん速くならないのか」という問題から入っていて、その原因は、人間がAIを「ちょっと賢いエディタの延長」として扱ってしまっているところにある、と指摘しています。つまり、AIを完全に手足扱いして、前提を毎回説明して、出てきたものを人間が全部判断しているので、前提説明の時間と、やり直しの時間がボトルネックになってしまっている、というわけですね。
それに対して筆者が提案しているのは、「AIを部下だと思って、仕事を任せる」というスタイルです。目的と、完了条件と、守ってほしい条件、それから関連する資料をちゃんとまとめて渡して、実装そのものはAIにやってもらう。そのうえで、「仕様の判断」や「マージするかどうか」といった、責任が発生する箇所だけ、人間が決める。そういう半自動のループを、最初から設計しよう、という話になっています。
そのための仕組みとして、チケット本文と設計書をきちんと分離して、設計書のほうに「ドラフト」「アプルーブド」みたいな状態と、承認履歴を持たせます。そして、その設計書が「アプルーブド」、つまり承認状態になるまで、実装はさせない、というルールにする。まず仕様を固めてからAIに投げるので、手戻りを減らす、という考え方です。
さらに、Claude Code の「スキル」機能を、AI向けの手順書として使っています。タスクを「起票」「実装」「プルリクの検証」「オーケストレータ」という四つの役割に分けて、それぞれのやり方をスキルとして定義し、タスク管理ツール、たとえば Asana などと連携させることで、一つのチケットがプルリクになって、マージされるところまでを、AI主体で回せるフローを作っている、という紹介でした。
人間が最後まで握っておくべき判断ポイントも、きちんと五つに整理されています。
ひとつめが「目的と完了条件を決める」。
ふたつめが「設計書の承認」。
みっつめが「仕様が分岐して、どちらに進むか決めないといけない場面」。
よっつめが「破壊的変更や、高リスクな変更」。
そして、いつつめが「最終確認とマージ」。
それ以外のところ、たとえば調査とか、実装とか、テストとかは、できるだけAIに回してしまう。そうすることで、仕様の食い違いによる作り直しや、確認漏れを減らしつつ、「人間は判断に集中して、AIは手と足と目として動き回る」という開発スタイルに移行できる、と説明していました。単に「AIで楽をする」というより、「チームの仕事の流れそのものをAI前提で再設計する」という視点が、すごく印象的な記事でしたね。
ということで、きょうの「zenncast」、駆け足でおさらいしていきましょう。
まず、一本目は、Cloudflare と Jev を組み合わせて、個人サイトでも月数円レベルで「賢い検索」を実現するベクトル検索+リランク構成のお話。
二本目は、Rust の中に直接 C コードを書き込めて、内部でRustコードを自動生成してくれる、cinrs という攻めたライブラリの紹介。
三本目は、HTTPスリーとQUICの基本から、DockerでCaddyとcurlを使って検証する手順までをまとめたTips。
四本目は、履歴を引き継がないオーファンブランチを、`checkout`、`switch`、`worktree` の三つのアプローチで作るGitテクニック。
そして最後、五本目は、AIを「部下」として扱い、チケットと設計書、スキルとツール連携を組み合わせて、人間は判断に集中する開発スタイルへ移行していこう、というオピニオン+Tipsの記事でした。
気になったトピックがあれば、詳しい内容や元の記事へのリンクは、ショーノートにまとめてありますので、そちらからぜひチェックしてみてください。
この番組「zenncast」では、みなさんからの感想や、「こんなテーマを扱ってほしい」「ここが分からなかった」などのフィードバックもお待ちしています。日々の開発での発見や、Zennで見つけた面白い記事なんかも、ぜひ教えてください。
それでは、そろそろお別れの時間です。
月曜日の朝、いいスタートダッシュが切れますように。
お相手はマイクでした。また次回の「zenncast」でお会いしましょう。では、いってらっしゃい。