#
840
2026/9/7
今日のトレンド

Terraform管理やAI主体の開発など

どうもマイクです。おはようございます。
九月八日、火曜日の朝七時を回りました。ここからの時間は「zenncast」、今日もZennで話題になっているトレンド記事を、わかりやすく、ゆるっと紹介していきます。

さて、まずはお便りからいきましょう。
ラジオネーム「いつも聞いてるよ」さん。

「たぶん十年分くらいのバッククオートを聞いた気がする」

……いやあ、これはじわじわ来ますねえ。
Terraformとかインフラ系の記事を追ってると、ほんとにバッククオートだらけになりますからね。
でも十年分くらいのバッククオートを聞いたってことは、それだけ技術の濃度が高い回を楽しんでくれてる、ってことと受け取っておきます。ありがとうございます。
この番組もね、なるべく「コードは耳で聞いてもわからないところは飛ばす」「でも中身のエッセンスはちゃんと届ける」っていうバランスを大事にしてるので、これからもいい感じの分量でやっていきます。
また何かあれば、軽い一言でもいいので、お便りお待ちしてます。

さあ、今日は五本の記事を紹介していきます。
インフラ運用の効率化、AI主体の開発フロー、DDDの設計パターン、ルービックキューブを解く小型LLMの実験、そしてテスト戦略としてのスタックドPR、とかなりバラエティ豊かなラインナップです。順番にいきましょう。

まず一つ目。
一つ目は、GitHubのチーム構成とか主要なリポジトリの権限管理を、Terraformでコードとして管理してしまおう、というお話です。
これまでは、Slackで「この人このチームに入れてください」「このリポジトリに権限ください」みたいな連絡が来るたびに、いちいちGitHubの画面を開いて、チームに追加したり、権限を変えたり、っていうのを手作業でやっていたそうなんですね。で、それがもう、つらい、と。

そこで著者の方は、GitHubのチーム構成を `github_team` と `github_team_membership` というTerraformのリソースで表現して、親子チームの関係とかメンバーの所属を全部コードに落とし込んでいます。
GitHubにはサブチームの権限継承みたいな独特の挙動があるので、そこをちゃんと理解したうえで、「どのチームがどこを引き継いでいるのか」を構造的に書けるようにしているのがポイントです。

リポジトリの権限については、`github_team_repository` というリソースを使って、チームごとに「このリポジトリにはプル権限」「このリポジトリにはプッシュ権限」みたいな設定をまとめています。
ここで面白いのが、GitHubで見えている権限名と、Terraformで使う権限名がちょっと違うところで、`pull`、`push`、`triage`、`maintain`、`admin`といったTerraform側の表現にちゃんと対応させてあげる必要がある。ここをミスると「あれ、このチーム管理者のつもりがプルだけだった」みたいなことが起きるので、その辺も含めて運用を整理しています。

さらにCIのところでは、GitHub Appを自前で作っておいて、そのApp用のトークンを `actions/create-github-app-token` で発行して、それを `GITHUB_TOKEN` としてTerraformから使う、というフローを組んでいます。
これによって、権限変更をしたいときは、TerraformのコードをPull Requestにして、レビューしてマージするだけ。マージされたらCIが走って、GitHub Appの権限でTerraformが実行されて、チームやリポジトリの権限が自動で反映される、という仕組みになっています。
Slackで申請して、管理者がブラウザでポチポチやるのではなくて、「申請はPR、管理者はそれをapproveしてマージするだけ」という運用に寄せているわけですね。

一方で、TerraformのGitHub Providerで大量のリソースを扱うと、実行がすごく遅くなる、という問題もあったそうです。
そこで著者は、Providerの設定にある並列リクエスト数とか、書き込みの間隔、リトライの条件といったチューニングポイントに気づいて、`parallel_requests` や `write_delay_ms` などを調整することで処理を高速化しています。
結果として、まずは「頻繁に変わるところ」だけを優先的にコード化していって、そこはもう完全にTerraform経由でしか変えない運用に。そして申請はPR、管理者はapproveだけ。ブラウザでの細かい操作の負担を大きく減らせた、という話になっていました。
運用でしんどいところを、ちゃんと「インフラとしてのコード」に落とし込む、いい事例ですね。

。。.。。.。.

続いて二つ目の記事。
こちらは、サービス紹介と開発手法の話が混ざっているんですが、メインは「AI主体開発をどう運用するか」というノウハウと考え方にフォーカスした、オピニオン寄りの記事です。

著者の方は、HTML社内で使う「Artifact Share」という共有サービスを、ほぼ一人で開発しています。ただ、その開発の仕方が特徴的で、TypeScriptのコードが二十五万行くらいあるにもかかわらず、「人間はほとんどコードを読まない」。
代わりに、AIを中心にして、二重のレビューループを回す「ソフトウェア工場」みたいな体制を作っている、という話なんですね。

立ち上げの時期は、かなり思い切ったやり方をしていて、AIにほぼノーガードでコードを書かせていたそうです。で、当然事故は起こるんですけど、事故が起きたらそれを一個一個Issueにして、またAIに「じゃあこの問題を防ぐにはどうする?」と対策させる。
つまり、最初は危なっかしい状態で走らせつつ、トラブルから逆にガードレールを育てていく、というやり方ですね。

その試行錯誤の結果として、人間がやるのは二カ所だけ、というスタイルに落ち着いたと。
一つ目は「IssueをAIと一緒に言葉で詰める最初のところ」。ここで、何を作りたいのか、何が問題なのかを、人間とAIでちゃんと言語化していきます。
二つ目は、CIが通ったPull Requestを最後にチラッと見て、「タイトルだけ確認してマージするところ」。
その間にある「仕様書ループ」と「実装ループ」、この真ん中のレビューと実装は、丸ごとAIに任せてしまう、という形です。

レビューの運用方針もはっきりしていて、「壊れる具体例があるバグ、つまりブロッカーだけは必ず潰す」。それ以外の「これ直した方がきれいだよね」とか「ここはもっと改善できそう」みたいな提案は、一旦先送りにしてストックしておく。
あとでまとめて「棚卸し」していくことで、過剰なルールやチェックをどんどん捨てていって、最終的には三十七行くらいのシンプルな規則に整理した、と書かれています。

著者は、このやり方を、いきなりチーム開発に丸ごと導入するのは危ない、ともちゃんと言っています。いきなり「人間はコードを読まない」ってやると、特に複数人の現場ではリスクが大きい。
ただ、人間レビューの前に、この二重レビューループを「前処理」として挟むだけでも、かなり効果がある、と。PRレビュー待ちの時間とか、レビュアーの注意力の消耗が、今の開発のボトルネックになっていることが多いので、そこをAIで軽くしてあげられる、と説明しています。

記事全体を通してのメッセージとしては、「問題はコード生成の速さではない」と。
いまの開発でいちばん貴重なのは、人間の注意力であって、その注意力をどう節約するか、そこを中心にAIとワークフローを設計するのが、これからの開発のカギだ、という主張がされています。
AIを「早く書くための道具」と見るんじゃなくて、「人間の集中力を守るための仕組み」としてどう組み込むか、という視点がすごく印象的な記事でした。

。。.。。.。.

三つ目の記事。
こちらはDDD、ドメイン駆動設計の文脈で、「ビジネスロジックをドメイン層に集めたいんだけど、データベースアクセスが絡むときに起きるジレンマ」についての話です。

DDDの理想としては、ビジネス上の判断ロジックは全部domain層に置きたい。
でも実際にやろうとすると、「純粋性」「性能」「完全性」という三つを同時には満たせない、という構造的な問題があると説明されています。

ここでいう「純粋性」は、ドメインの関数やメソッドの引数や戻り値に、エラーとかコンテキストみたいな、外側の事情を持ち込まないこと。
「性能」は、必要以上にデータベースのクエリを出さないこと。
「完全性」は、ビジネスロジックがちゃんとドメイン側に集約されていて、usecaseとかアプリケーション層に逃げていないこと。

ところが、DBから何か取ってこないと判断できないような処理が入ってくると、「ドメインの外で事前に全部取って渡す」のか、「ドメインの中からクエリを呼ぶ」のか、みたいな選択を迫られる。
結果として、多くの現場では、if文とかビジネスルールがどんどんusecase側に逃げていって、ドメインモデルがスカスカになる、いわゆるドメインモデル貧血症に陥りがちだと。
これは怠慢というより、この三つの条件を同時に満たせない構造から自然にそうなってしまう、と位置づけています。

そこで筆者が提案しているのが、「Decision」と呼んでいる型を使ったパターンです。
ドメイン側で「最終的な可否」を返すのではなく、「判断するために何が必要か」を表す状態、つまりDecisionを返すようにする。
たとえば、「閲覧していいかどうか」を決めたいときに、「このユーザーはこの人をフォローしているか」「このユーザーはVIPかどうか」といった、必要な事実を状態として持つDecisionを返すわけですね。

具体的な流れとしては、まずdomain層に一回入って、「いま分かっている情報だけで、どの状態にいるのか」を計算して、そのDecisionをusecaseに返します。
usecase側はそのDecisionを見て、「あ、このパターンだとまだフォロー関係が分かってないから、それをDBから取ってこよう」といった具合に、必要最小限のデータを取得します。
取ってきたデータを付け足して、またdomain側に渡して、もう一度判定してもらう。
この「往復」を通じて、最終的な判定を完了させる、というスタイルです。

こうすることで、ビジネス条件のif文はすべてdomain内に保ちつつ、使わないクエリは打たないで済む。domainの関数は値だけを扱って、DBのやりとりはusecase側に残すので、純粋性もある程度守れる、というバランスの取り方になっています。

さらに、このパターンでは、各状態や状態遷移を型として表現しているので、「まだ書かれていない状態分岐」があれば、静的解析ツールで検出できる前提になっています。
その代わり、コードをパッと眺めただけでは、全体の判定フローがどうなっているかが分かりにくい、という副作用もあるんですが、そこはツールで補っていて、domainのロジックから「決定木」の図を自動生成できるようにしているそうです。
それによって、「この条件のときに、どこまでクエリが飛ぶのか」「どういう枝分かれをしているのか」が可視化できる、と。
DDDの理想と現場の制約を、型と静的解析と可視化ツールでなんとか両立させようとする試み、という感じですね。

。。.。。.。.

四つ目の記事。
ここからちょっと毛色が変わって、ルービックキューブの話です。
内容としては、「ルービックキューブを自力で解く手順は一切教えずに、成功例だけを使った自己学習で、ほぼ必ず一撃でそろえられる小型LLMを育てた」という実験の報告です。

このモデルは、ルービックキューブの五十四個のマスの色を、そのまま文字列として扱うのではなくて、まずState Encoderという仕組みで、一つのベクトルに圧縮してからTransformerに入れています。
で、モデルが出力するトークンは、「キューブをどう回すか」という十八種類の回転手だけ。つまり、「盤面」と「次に回す手」の間の対応を学習させているイメージですね。

学習のやり方も工夫されていて、「Best of eight」という方式を使っています。
ある局面からスタートして、八通りの手順をサンプリングで生成します。その中で、実際に完成までたどり着いた手順があれば、そのうち一番短いものだけを、教師データとして採用する。
これを、まず簡単な局面からスタートして、だんだん深い局面まで広げていくことで、「だんだん難しい状態も解けるようになる」ように訓練していきます。

結果として、深さ一から三十までの全局面に対して、八回サンプリングしたときのうちどれかが正解になる確率、いわゆるpassアットエイトが、なんと百パーセント。
さらに、三万七百二十通りの未知の局面に対して、一回だけサンプリングした結果で、九九点八三パーセントを完成させた、という数字が出ています。
つまり、「一回答えを出したら、ほぼ全部そろえられる」というレベルまで到達しているわけですね。

ここで面白いのが、このモデルが見つけた解法は、人間が目指す「最短手数」ではない、というところです。
平均すると四十手くらいかかっていて、最短解よりは長い。ただ、その代わり、どんなにぐちゃぐちゃに崩れていても、安定して完成させられる戦略を身につけている。
人間向けの定石とか、「こう回すと揃いやすいよ」という知識は一切教えずに、成功例だけから学習データを自分で増やし続けて、ここまでの性能に到達した、というのがポイントです。

これは、強化学習とかゲームプレイAIの、よりシンプルなモデルとしても興味深くて、「報酬設計を細かくしなくても、成功例をうまく選んでやると、かなり強い方策が学べるんじゃないか」という示唆になっています。
小型LLMでも、問題の構造をうまく表現してやれば、ここまで戦略的な動きができる、っていうのは、おもしろい結果ですよね。

。。.。。.。.

最後、五つ目の記事。
これはテストとバグ修正の運用に関する話で、「Red-Green Stacked PR」というプラクティスの提案です。

不具合を直すときに、「このテスト、本当にバグを再現できているの?」っていう問題がありますよね。
通常のPRだと、CIは「直した後のコード」と「テスト」がセットになった状態だけを見ているので、「修正を外したらちゃんと落ちるテストなのかどうか」は、CIの結果からは分からない。
レビュアーがわざわざローカルで修正を外してテストを回して、「ちゃんと赤くなるな」と確認するしかない、というのが現実的な面倒ポイントです。

そこで著者が提案しているのが、「Red-Green Stacked PR」です。
まず最初に、今のコードでは必ず失敗するはずの再現テストだけを追加したPRを一つ作ります。
このとき、テストフレームワークにある「このテストはいまは失敗することが正しいですよ」という印を使います。たとえば、あるテストフレームワークだと `test.fails`、Jestだと `test.failing` みたいな形です。
これで、「いまの本番コードに対して、このテストは落ちるはず」という事実を、CIで保証させる。これがPR一番の「Red」です。

そのうえで、二つ目のPRを「上に積む」かたちで作ります。
今度は、そのテストから `.fails` の印を外して、実際の実装も修正する。つまり、「同じテストが今度は通るようになりましたよ」という状態のPRですね。
この二つ目のPRが「Green」にあたります。

こうやってPRを二段に分けることで、「バグがちゃんと再現されていたこと」と「そのバグが修正されたこと」を、それぞれ独立したCIの履歴として残せるようになります。
コミットを分けるだけだと、CIが中間状態を検証してくれなかったり、最後にsquashマージして履歴がつぶれたりして、「どこで何が起きていたのか」が見えなくなりがちですよね。
PRをスタックにすることで、「Redの状態」「Greenの状態」がそれぞれ別々の検証単位として、ちゃんと残るのがメリットです。

さらに、GitHub CLIの `gh stack` という機能を使うと、この二つのPRを「スタック」としてまとめて作ったり、まとめてマージしたりできるので、「テストだけ追加したPRが本流にだけ残っちゃって、いつまでもテストが失敗してる」みたいな事故を防げます。
特に、重要で複雑なバグ修正のときに、「ちゃんと再現できていたし、そのうえで直っている」という証拠をCIの履歴としてきちんと残せるのは、大きな安心材料になりますよね。

。。.。。.。.

ということで、今日は五本の記事を紹介してきました。
ざっとおさらいすると、まず一つ目は、GitHubのチーム構成とリポジトリ権限をTerraformでコード管理して、GitHub AppとCIを組み合わせて、PRをマージするだけで権限変更が反映される仕組みを作った話。
二つ目は、タイプスクリプト二十五万行のサービスを、AI中心の二重レビューループで回しながら、「人間の注意力を節約する」ことを軸にしたAI主体開発の運用ノウハウ。
三つ目は、DDDにおける「純粋性・性能・完全性」のジレンマに対して、Decisionという型を返すパターンで、ビジネスロジックをdomainに保ちつつ、不要なクエリを避ける設計の提案。
四つ目は、ルービックキューブを、成功例だけの自己学習で「ほぼ一撃でそろえる」小型LLMを育てて、depth三十までpassアットエイト百パーセント、未知局面でも九九点八三パーセントを達成した実験。
そして五つ目が、バグ再現テストと修正を、二段のスタックドPRで「Red」と「Green」として別々にCIで検証・記録できる、「Red-Green Stacked PR」という運用のお話でした。

それぞれの記事の詳しい内容や、今回紹介しきれなかった細かいところは、ショーノートにリンクをまとめておきますので、気になったトピックがあったら、ぜひそちらから飛んで、元記事も読んでみてください。

この「zenncast」では、番組の感想や、「こんなテーマを取り上げてほしい」「こういう現場の悩みがある」といったお便りをいつでも募集しています。
さっきの「十年分のバッククオート」みたいな一言でも大歓迎ですので、気軽に送ってください。

というわけで、そろそろお時間です。
お相手はマイクでした。次回また、この時間にお会いしましょう。
それでは、いってらっしゃい。

Related episodes

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