どうも、マイクです。おはようございます。
九月二十三日、水曜日の朝七時を回りました。今日も zenncast、元気にお届けしていきます。
この時間は、技術情報共有プラットフォーム「Zenn」で、いまホットなトレンド記事を、ラジオ感覚でゆるっとキャッチアップしていくコーナーです。

さて今日は、お便り紹介はお休みで、そのぶんガッツリ記事を紹介していきたいと思います。
きょうピックアップする記事は、ぜんぶで五本です。Rust と C のハイブリッドなお話から、AI に優しいフロントエンド、Web API の設計、Nextcloud のチューニング、そしてブラウザ拡張とAIの境界線まで、盛りだくさんでいきます。

まず一つ目。
Rust のコードの中に、なんとそのまま C 言語を書けちゃう、ちょっとワクワクするライブラリ「cinrs(シーインアールエス)」の紹介記事です。

この cinrs の一番の特徴は、バッククオートで書くマクロ、たとえばシー九九ティナイン、`c99!` みたいなマクロで C のコードを囲んであげると、その C コードをその場で Rust のコードにコンパイルして埋め込んでくれる、というところなんですね。
普通、Rust から C を呼ぶときって、別でヘッダーファイルを用意したり、bindgen を走らせたり、とにかく「言語の壁」をいろいろ超えていく必要があるんですが、この cinrs を使うと「ここに C 書いちゃえ!」って感じで、関数や struct、ビットフィールド、それから `#include` みたいなプリプロセッサまで、ほぼそのまま Rust コードの中に置けちゃう。

生成される関数は、基本的にはアンセーフ、`unsafe` な関数になるんですが、そこに「この関数は安全ですよ」という印をつけるための属性、たとえばダブルブラケットで書く `[[cinrs_safe]]` のような属性をつけておくと、Rust 側の型チェックがちゃんと働いてくれて、安全かどうかをコンパイル時に検証してくれます。そこで問題があれば、コンパイルエラーになって落としてくれる、という仕組みになっています。

中身では、自前の C コンパイラを持っていて、外部の C コンパイラとか libclang に依存しない構成になっているのも面白いところですね。サポートしている範囲もけっこう広くて、シーはちじゅうきゅうからシーにじゅうさんまで、いわゆる C89 から C23 の規格、それに GNU 拡張のかなり広い部分をカバーしながら Rust へ変換してくれます。
エラーメッセージもちゃんとしていて、エラーになった場所が、元の C コードの何行目なのかに対応して表示されるので、C 側の修正もしやすい。さらに Rust のナイトリーバージョン限定の機能を使うと、もっと精密なエラーレポートもできるようになっているそうです。

気になる性能面ですが、ベンチマークの結果だと、gcc や clang とほぼ同じくらいの実行速度で動くということで、特に `goto` がたくさん出てくるような C コードを除けば、性能差はかなり小さい、という話になっています。

どんな用途が想定されているかというと、たとえば、既存の C プログラムをまるっとマクロの中に貼り付けて、そのまま Rust プロジェクトの中で動かしつつ、少しずつ Rust らしいコードへ書き換えていく「段階的移植」に使えます。
あるいは、bindgen を使わずに、`#include` でヘッダを取り込むだけで C ライブラリを呼び出してしまう、とか。
それから、C でしか表現しづらかったビットフィールドの定義を、そのまま Rust の型として扱えるようにする、といった使い方も想定されています。
さらに面白いのが、cinrs が生成した Rust コードを miri で実行してあげることで、もともとの C コードが持っていた「未定義動作」を検出する、なんていうデバッグ的な用途もあり得る、という点ですね。C の世界と Rust の世界をつなぐ、かなり攻めたツールの紹介でした。

。。。。

続いて二つ目。
こちらは「WebMCP」という仕組みを使って、ブラウザ上の Web ページを AI に操作させやすくする話題です。

WebMCP は簡単にいうと、Web アプリのフロントエンド側に「AI が直接呼び出せるツール」を公開するための仕組みです。
やり方は二通りあって、一つはフォームの属性として、「このボタンはこういうツールだよ」と宣言的に書くスタイル。もう一つは、JavaScript のコードの中で、「この関数をツールとして登録します」という命令型のスタイルです。

筆者の方は、ご自身の会社の CMS に入っている、React 製のデザインエディターに、この WebMCP を命令型スタイルで組み込んでいます。そこで AI が使えるツールとして、ブロック一覧を取得する、ブロックを追加する、内容を更新する、順番を動かす、といった一連の操作をまとめて登録しているわけですね。

実験として、「あるページとまったく同じレイアウトを再現しなさい」というタスクを、WebMCP ありとなしで比較しています。
まず WebMCP なしの場合、つまり AI がただの GUI として画面を操作するだけの状態だと、人間と同じように、ボタンをクリックしてメニューを開いて、ブロックを一個ずつ追加して…とやっていくので、作業時間は五分五十二秒かかりました。
一方で、WebMCP を入れた状態だと、AI は GUI のボタンをポチポチしなくても、ページの状態を一気に読み取って、必要なブロック構造を「ツール呼び出し」でドンと構築してしまえます。この場合は、なんと三分九秒で作業が完了した、という結果が出ています。

フォーム入力みたいな単純作業であれば、ここまでの仕組みは必須ではないんですが、複雑な CMS の管理画面とか、ブロックエディターのような UI になってくると、「人間が触りやすい UI」と「AI が触りやすいインターフェース」はけっこう違ってくるんですよね。
筆者はこの実験を通じて、「人間向けの Web アプリであっても、将来を見据えると、AI 操作用のインターフェースをあらかじめ組み込んでおくことが、フロントエンド実装の新しい標準になっていくんじゃないか」と感じた、とまとめています。
今後、AI に操作してもらう前提でボタンやフォームを設計する、という発想は、かなり増えてきそうです。

。。。。

三つ目。
こちらは、Web API の設計で「リクエストを受け取ったときに、User みたいな Domain Object をどこで生成するのがいいのか?」という、ドメイン駆動設計好きにはたまらないテーマの記事です。結論としては、「基本的には UseCase 側で生成するのがよい」という整理になっています。

まず、一つの選択肢として、HTTP の Handler 側で User を生成してしまう、というやり方があります。これだと、UseCase は「すでにできあがった User を引数でもらうだけ」になるので、ユースケースのコードはすっきりします。
ただこのやり方だと、Handler がドメインオブジェクトを直接扱うことになってしまうので、たとえば「モバイル用の shortName を入れておいてほしい」とか、「外の世界の都合」がどんどん User に入り込みがちなんですよね。
そうなると、Handler と Domain の結びつきが強くなってしまって、本来はユースケース側の責任であるべき判断が、外側の層に漏れてしまう、という問題が出てきます。

そこで筆者が推しているのが、「UseCase 側で、プリミティブな値から User を生成する」というスタイルです。
Handler はあくまでも、「外部から来た Request の形式が壊れていないかどうか」をチェックする役割に留めます。たとえばメールアドレスの形式がおかしくないか、とか、必須項目が抜けていないか、とか、そのレベルのバリデーションですね。
で、形式面をクリアしたうえで、UseCase に、メールアドレスや名前、パスワードなどのプリミティブな値を渡す。
UseCase はその値から User を生成しにいく中で、「このメールアドレスはすでに登録済みだから、業務的にこれは失敗だよね」といったドメインの失敗を判断していきます。こうすると、ドメインのルールが外側に漏れず、ユースケースの中にきれいに閉じ込められる、というわけです。

さらに、HTTP の Request 構造そのものに UseCase が引きずられないように、「UseCase 専用の Params 構造体」を定義してあげる、という話も出てきます。
つまり、Handler の中で「Request から Params へ詰め替える」一手間をかけることで、「外部から入ってくるデータの形」と「ユースケースが本当に必要としている入力の形」を、ちゃんと分けておくんですね。型がある言語なら、ここはかなり気持ちよく表現できます。

とはいえ現実的には、たとえばスクリプト言語で型がほとんどないとか、そもそも明確な Domain をあまり必要としない「Hub API」のような場面では、「もう Handler でそのまま変換しちゃっていいよね」という割り切りもあり得ます。
記事では、そのあたりの理想と現実のバランスにも触れつつ、「基本線は UseCase で Domain Object を生成する」「ただし状況によっては例外もあるよ」という、落としどころが整理されていました。

。。。。

四つ目は、Nextcloud を大量の写真や動画で使っていると「なんか重い…」となりがちな問題に対して、「どこが遅いのかを細かく分解して、それぞれに対処するのが大事だよ」というチューニング記事です。

まずストレージ周り。
筆者は、実データ、つまり元の写真や動画ファイルはコストの安い HDD に置きつつ、サムネイルみたいに「もし消えても再生成できるプレビュー」だけを SSD に逃がす、という構成にしています。
さらに HDD を選ぶときには、記録方式として CMR を選ぶようにしていて、SMR みたいなランダムアクセスに弱い方式は避けるようにしている。
マウントオプションでは `noatime` を使って、アクセス時刻をいちいち書き換えないようにしたり、read-ahead の設定を調整して、連続読み出しが得意になるよう最適化したり、といった工夫もしているそうです。

メモリについては、データベース、ここでは MariaDB のバッファをむやみに大きくしすぎず、OS のページキャッシュをうまく生かせるように、sysctl の設定を調整しています。
クエリキャッシュに関しては、Nextcloud の更新頻度や挙動を考えると、あまり効果が出にくい、むしろ足を引っ張る場面もあるということで、無効化している、という姿勢ですね。

Web / PHP 側では、Nginx のアップロードバッファや、静的ファイルのキャッシュ設定をしっかり調整しています。
PHP-FPM のワーカー数と OPcache の容量もチューニングしていて、「PHP まで到達しなくていいものは、できるだけ Nginx で返してしまう」という方針で、PHP の負荷自体を減らす方向に持っていっています。

Nextcloud のアプリも、なんでもかんでも入れるのではなくて「必要最小限」。
特に Activity みたいに DB をどんどん肥大化させてしまうものは、機能を無効化したり、保持期間を短くしたりして、データが積み上がりすぎないように気をつけているそうです。
「高速化系アプリ」とラベルが付いているものも、自分の環境のボトルネックに本当に効くのかどうかを検証してから使うべきで、とりあえず入れておけば速くなる、というほど単純ではない、という指摘もされています。

そして最後に効いてくるのが、監視とログ収集。
CPU・メモリ・ストレージ、それに PHP と SQL のどこで遅くなっているのかを可視化して、「Nextcloud 全体が遅い」のではなく、「このあたりがボトルネックだね」と切り分けていくことが重要だとまとめています。
さらに、用途によっては、たとえば漫画ビューアなら Kavita、写真・動画の管理なら Immich といった専用ソフトに分担させることで、「なんでも Nextcloud に任せない」設計にする。結果的にそれが大きな高速化につながる、というのが記事のメッセージでした。
オールインワンを目指しつつも、役割分担をちゃんと考えるのがポイント、という感じですね。

。。。。

そして五つ目。
最後は少しオピニオン寄りの体験記で、「AI がブラウザや拡張機能をどこまで操作できるのか?」を実際に試してみたレポートです。

きっかけは、ChatGPT のデスクトップアプリが、Chrome 拡張に対応した、というニュース。
筆者は、日本株のバックテストができる自作の Web アプリ「Zephris」と、自作の Chrome 拡張を用意して、「AI 操作でここまで動かせるのか?」を検証しています。

通常の Chrome を経由した場合、拡張機能は問題なく検出されて、サンプル戦略の実行結果も、AI の内蔵ブラウザで見たものと一致したそうです。
一方で、ChatGPT の内蔵ブラウザ環境になると、挙動にちょっとした境界線が見えてきた。
具体的には、拡張のインストール確認ダイアログみたいな、「拡張機能そのものに直接触る操作」になると、AI がそこで止まってしまう。一方で、Web ページ上の UI を通じて、拡張にメッセージを送るような処理は普通に実行できる。
つまり、「ブラウザの深いところ」に近い操作は制限されているけれど、「Web 画面経由で拡張にお願いする」レベルなら動ける、という境界が見えてきた、というわけです。

もう一つ大事な論点として出てくるのが、プライバシーと利用規約の話です。
AI に画面を読ませるということは、バックテストの結果の数値とか、銘柄の情報とか、そういったデータが AI サービス側に送信される、ということでもあります。
今回でいうと、株価データの提供元である J-Quants の利用条件を守れているかどうかとか、「学習に使われない」設定になっているかどうか、といった点を、ユーザー自身が確認しておく必要があるよね、という指摘がされています。

筆者の拡張機能では、API キーの入力を「拡張のポップアップ内だけに限定する」という設計にしていて、「Web ページ側からはキーを触らせない」工夫をしています。
それでも、ユーザーが自分で「この画面を AI に読ませる」という操作をしてしまえば、その数値や結果はサービス側に渡ってしまうので、そこまでは制御できない。
だからこそ、今後は「Web 画面から拡張に何をさせる設計にするか」を、AI による操作の可能性も踏まえながら見直していく必要があるのでは…という問題提起で締めくくられています。
AI とブラウザ拡張の関係が、これからますます密になる中で、技術とルールの両方を考える必要があるよね、というお話でした。

。。。。

ということで、きょうの zenncast は、
Rust の中に C をそのまま埋め込める「cinrs」の話、
WebMCP で AI に優しいフロントエンドを用意する話、
Web API で Domain Object をどこで作るか、という設計の話、
Nextcloud をボトルネックごとにチューニングする話、
そして AI がブラウザ拡張をどこまで操作できるのか、という体験記まで、五本立てでお届けしました。

気になる記事があった方は、詳しい内容や元記事へのリンクはショーノートにまとめてありますので、そちらからじっくり読んでみてください。
番組の感想や、「こんなテーマを取り上げてほしい!」といったリクエストも、どしどしお待ちしています。

それでは、きょうも良い一日をお過ごしください。
お相手はマイクでした。また次回の zenncast でお会いしましょう。

Related episodes

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