#
781
どうもおはようございます。マイクです。
今日も始まりました「ぜんキャスト」、二千二十六年七月十一日、土曜日の朝七時をちょっと回ったところです。
この時間は、技術記事投稿プラットフォーム「Zenn」から、いまホットなトピックをピックアップしてご紹介していきます。

今日はリスナーのみなさんからのお便りはお休み、ということで、そのぶんガッツリと記事を紹介していきますね。

さて、今日ご紹介する記事は、全部で五本あります。
Cloudflare のメールのお話、関数と冪等性の話、ミューテーションテスト、AIのセカンドオピニオン、そしてデータベースのコスト削減事例まで、幅広くカバーしていきます。

まず、一本目。
個人開発とか副業のプロジェクトをやっている方には、かなり刺さりそうな内容です。
テーマは、「独自ドメインのメール運用を Cloudflare だけで完結させちゃおう」という話。

これまで Cloudflare には Email Routing っていう機能があって、「受信」はできていたんですね。
たとえば `info@自分のドメイン` に届いたメールを、自分の Gmail に転送するとか、そういう用途です。
でも、「送信」に使える SMTP サーバーが用意されていなかったので、結局どこか別のメールサービスを契約したり、Gmail の SMTP を使ったりする必要があったんです。

そこに、この二千二十六年になって、Cloudflare Email Service に「Email Sending」という送信機能が追加されて、しかも SMTP に対応しました。
これによって、Gmail の「他のメールアドレスから送信」という機能に、Cloudflare の SMTP をそのまま設定できるようになったんですね。

仕組みとしては、独自ドメイン宛てのメールは、Email Routing で Gmail に転送して受信。
返信したり、新規メールを送ったりする時は、Gmail の画面から打つんだけど、裏側では Cloudflare の SMTP を経由して送るので、「独自ドメインのメールアドレスから送信した」っていう形になります。
これによって、相手の画面に Gmail アドレスが「代理送信」として見えちゃう、あのちょっと気まずい問題を避けられるのが、すごくうれしいポイントです。

料金面だと、Cloudflare Workers の有料プラン、月五ドルの Workers Paid プランに入る必要があるんですが、その中で月三千通までは追加料金なしで送信できる仕組み。
すでに Workers を使っている人にとっては、実質的な追加コストなしで、独自ドメインメールの送信もまとめて面倒見てもらえる、っていう感じですね。

そしてなにより、「DNS は Cloudflare、でもメールは別サービス」という、あのよくある構成をガッと一本化できる。
DNS とメール周りを Cloudflare に寄せてスッキリさせたい人には、かなり実務的にありがたいアップデートを紹介している記事でした。

。。。。

続いて二本目。
ここからはプログラミングのちょっと概念寄りのお話で、「純関数」「参照透過性」「冪等性」って、似ているようで実は別物だよ、という整理をしてくれている記事です。

まず、「純関数」。
これは「同じ入力なら必ず同じ出力を返す」「外部の状態を読んだり書き換えたりしない」関数のことです。
純関数で書かれた関数呼び出しの式っていうのは、必ず参照透過になります。

次に、「参照透過性」。
こちらは、関数そのものじゃなくて「式」に注目した概念です。
ある式について、それを評価した結果の値で置き換えても、プログラム全体の振る舞いが変わらない、という性質のこと。
たとえば、`一足す一` という式が、どこに書いてあっても「二」に置き換えても意味が変わらないなら、その式は参照透過、というイメージですね。

そして三つ目が「冪等性」。
これは、システムに対する「操作」に注目する概念で、「同じ操作を何回繰り返しても、一回目を実行した後とシステム全体の状態が変わらない」という性質のことです。
ここでは、「決定論的かどうか」は問わない、というのがミソです。

記事では、具体例として `updateUserName` みたいな、データベースのユーザー名を更新する関数を挙げています。
これは外部の状態であるデータベースを書き換えるので、純関数ではないし、参照透過でもありません。
でも、同じ更新内容を何回やっても、最終的にデータベースに入っているユーザー名は同じなので、「冪等」なんですね。

一方で、`エックスに一を足す` みたいなシンプルな関数は、外の状態に触れないし、同じ入力なら同じ結果なので、純関数であり参照透過です。
ただし、これを何度も繰り返すと値はどんどん変わっていくので、「冪等」ではありません。

こうした例から、「冪等だけど純関数ではないケース」と、「純関数だけど冪等ではないケース」がちゃんと存在するよ、というのを丁寧に説明してくれています。

応用の話としては、関数型プログラミングの世界では、純関数と参照透過性が重要視されるよ、という話。
一方で、REST API や分散システムの設計では、リトライに強い仕組みにするために冪等性がすごく大切になります。

React の話も出てきていて、コンポーネント本体はできるだけ純関数的な形に保つ。
一方で、副作用を扱う `useEffect` みたいなところでは、再実行されても壊れないように、「冪等性」を意識して書くのが重要だよ、というまとめになっていました。

。。。。

三本目は、テストの話です。
いまの時代、AI が大量にコードもテストも自動生成してくれるようになってきましたが、その結果として「テストは通るんだけど、実際にはバグをぜんぜん捕まえられていない、中身のないテスト」が増えやすい、という問題を取り上げています。

よく使われるテスト指標として行カバレッジがありますが、これは「どの行が通ったか」を示しているだけで、「ちゃんと意味のあるアサーションができているか」「大事な条件分岐を本当に検証できているか」までは見てくれないんですよね。
AI にテストを書かせると、見た目は立派なテストが増える一方で、緩いアサーションのままだったり、大事なケースを見落としていたりしても、なかなか気づきにくい。

そこで筆者が推しているのが、「ミューテーションテスト」という手法です。
これは、本番コードにあえて小さな「変異」を入れて、その変更によってテストが落ちるかどうかを確かめる、というもの。
もしコードを壊しているのにテストが落ちない場合、それは「偽陰性」が起きているということで、「このテストはバグを捕まえられていないかもしれない」と気づくことができます。

人間のコードレビューだけでは、テストの網羅性とかアサーションの妥当性って、どうしても見落としが出てきますが、ミューテーションテストを回すことで、そのあたりを機械的に補ってくれるのが利点です。

一方で、「見た目はコードが変わっているけれど、振る舞いはまったく変わらない」っていう、いわゆる「等価ミュータント」が一定数は必ず出てきます。
これらをすべて検出して「ミューテーションスコア百分の百」を目指すのは、原理的に不可能に近いので、そこをゴールに据えるべきではない、という指摘もされています。

そのため、現実的な運用としては、CI にミューテーションテストを組み込んで、「このプロジェクトでは、だいたいこのくらいのスコアを維持しよう」という、ほどよい閾値を決めて回していくのがいいよ、という結論になっています。
AI がテストを書いてくれる時代だからこそ、そのテストが本当に役に立っているのかを、別の角度から検証する仕組みが必要だ、という問題意識がよく伝わる記事でした。

。。。。

四本目は、また AI の話なんですが、今度は「設計判断のセカンドオピニオン」をどうやって取るか、というお話です。

最近は、AI が大量のコードをバンバン吐き出してくれるようになって、開発者側としては「この判断、本当にこれで大丈夫なのかな?」って不安になる場面、増えていると思います。
筆者が着目しているのは、AI が一度出した自分の結論を、あとから無意識に正当化してしまう、いわば「自己正当化バイアス」です。

そこで記事では、最初に出た AI の結論をあえて隠した状態で、より上位のモデルである Fable Five に、同じ問題を解かせて「セカンドオピニオン」をもらう、という Skill を、Claude Code 上に実装した事例を紹介しています。

この Skill では、まず「いつ発動するか」をけっこう細かく決めています。
たとえば、大きな設計判断をした直後とか、人間のユーザーが「本当にそう?」と疑問を持ったときなど、重要な場面で動くようにしている。

そして、Fable Five に渡す情報も工夫されています。
元の AI の結論や提案そのものは渡さずに、「証拠」や「前提条件」だけを、できるだけ中立的なかたちで渡します。
こうすることで、あとから呼び出した Fable Five が、最初の回答に引きずられない、独立した見解を出しやすくなるんですね。

結果として、AI 同士が同じ答えをなぞるだけではなくて、「こういう別案もあります」とか、「この前提条件にはこういうリスクがあります」といった視点を出してくれるようになり、AI の自己正当化バイアスを和らげる効果がある、と。

最終的な判断者はあくまで人間のテックリードで、「最初の AI の答え」と「Fable Five のセカンドオピニオン」、この二つを見比べながら意思決定をする形になります。
AI が相棒として働く場面が増える中で、AI にも「セカンドオピニオン」をちゃんと用意してあげよう、という、ちょっと面白いアプローチが紹介されていました。

。。。。

そして最後、五本目。
これはかなり生々しいインフラのコスト削減事例で、「データベースに溜まり続けていたジョブ実行ログを整理して、約四億件のログを削除し、九テラバイトのストレージと、月額八十万円超のコストを削減した」というお話です。

まずそもそもとして、ジョブ実行ログの「どれくらいの期間残しておくか」という保存ポリシーがなかったことが、負担の原因になっていました。
ログはとりあえず全部残しておこう、という運用を続けていた結果、気がついたらデータベースの容量を圧迫して、コストも跳ね上がっていた、という状況ですね。

そこで筆者たちは社内で調整を行って、「ジョブ実行から一年が経ったら、そのログはデータベース上から消す」という方針を決めました。
ただ、利用企業によっては、もっと長期にログを残したいニーズもあるので、そういうユーザー向けには「Sスリーへのログエクスポート機能」を用意して、長く持ちたい人はそちらで保管できるようにしています。

削除の実作業としては、Rails の Rake タスクを使って、ログ用のカラムをヌルとか空文字に更新していく、という方法をとりました。
本番環境の負荷を上げすぎないように、一秒あたり百件くらいのペースに抑えるように調整しながら、数ヶ月かけてじわじわと実行していったそうです。

ここでポイントなのが、「値を消しただけではディスクの空き容量は増えない」というところ。
InnoDB のテーブルって、行のデータを消しても、すぐには物理的なファイルサイズが小さくならないんですよね。

そこで、Aurora MySQL の Blue/Green Deployment 機能を使って、別のクラスター側で `OPTIMIZE TABLE` を実行し、テーブルの最適化を行うことで物理容量をギュッと縮めました。
これによって、実際にストレージの使用量が減っていきます。

ただし、この最適化の過程で、ログテーブルがあまりにも大きかったせいで、インデックス再構築のためのバッファが足りずにエラーが発生する、というトラブルもあったとのこと。
そこは、`innodb_online_alter_log_max_size` という設定値を、一時的に百五十ギガバイトまで引き上げることで対応しています。

最終的には、約四億件のログ削除によって、九テラバイトぶんのストレージが空いて、月あたり八十万円を超えるコスト削減につながった、という、非常にインパクトのある事例でした。
「ログ、なんとなく溜めっぱなしになってない?」と、自分たちのシステムを振り返りたくなる内容ですね。

。。。。

というわけで、今日の「ぜんキャスト」でご紹介した記事を、最後に駆け足でおさらいしておきます。

まず一本目は、Cloudflare の Email Sending 機能が SMTP に対応したことで、Email Routing と組み合わせれば、独自ドメインメールの送受信を Cloudflare だけで完結できるようになった、という話。
二本目は、「純関数」「参照透過性」「冪等性」という似て非なる三つの概念を整理して、実務でどう使い分けるかを解説した記事。
三本目は、AI が生成した「中身のないテスト」をあぶり出すために、ミューテーションテストを使って、テストの質を機械的にチェックしていこう、という提案。
四本目は、AI の自己正当化バイアスを避けるために、Fable Five を使ったセカンドオピニオン用 Skill を作って、テックリードが二つの意見を見比べながら判断しやすくした、という事例。
そして五本目は、ジョブ実行ログの保存ポリシーを見直して、四億件のログ削除とテーブル最適化を行い、九テラバイトのストレージと月八十万円超のコストを削減した、というインフラ改善のストーリーでした。

気になった記事があれば、詳しい内容は番組のショーノートから、元の記事もチェックしてみてください。
この番組への感想や、「こんなテーマを取り上げてほしい」といったリクエストも、ぜひぜひお待ちしています。

それでは、そろそろお時間です。
お相手はマイクでした。また次回の「ぜんキャスト」でお会いしましょう。
今日もよい一日をお過ごしください。

Related episodes

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