Go back

エージェントがコードを書く時代に、システムの持ち主が知っておくべきこと

Posted on:

AIエージェントにコードを書かせる時間が増えてから、気になっていることがあります。「自分が書いていないコードが原因で障害が起きたとき、自分は直せるのか」という点です。

この問いに答えようとしている記事を読みました。Adrian Quiroga さんの「Here Be Monsters」です。

元記事は、海底で金を採る「ダイブボット」の比喩で進みます。ダイブボットはAIエージェント、海は自分たちが持つシステムです。海の地図、怪物(危ない箇所)、潜る(深く調べる)は、すべてこの比喩の言葉です。

発端は、見覚えのないコードでCIが落ちたこと

元記事は、書き手のCIが落ちる場面から始まります。テストは通っているのに、静的解析ツールのSonarQubeが App.tsx を「複雑度が高すぎる」と指摘してきました。開いてみると、30行ほどのファイルのうち15行が、コンポーネント丸ごと1行に押し込まれていました。エージェント(Codex)が書いたもので、人間なら読みやすさのために必ず整理するところです。

書き手はフォーマットをかけたうえで中身を読み、ロジックが正しいことと、複雑さが業務要件に見合っていることを確認します。そのうえでエージェントに「SonarQubeを満たすように直して」と頼み、10ファイルに分割されてCIが通りました。

強調されているのは、解決の速さではありません。一度も見たことのないコードだったという点です。もっと悪い結果になる道筋はいくらでもあった、と書いています。

ここから導かれる主張は次のとおりです(意訳です)。

システムを所有することは、手で書いたかどうかにあまり左右されなくなる。大切なのは、何かがおかしいと気づける程度に知っていること、そして必要なときに必要なだけ深く潜れることだ。

「所有する」とは、障害時に呼ばれる人のこと

元記事では「所有(ownership)」を、何かが壊れたときに呼び出される人と定義しています。

従来は、書く・読む・デバッグする・リリースするという経験の積み重ねが、頭の中のシステムのモデルを作ってきました。ところがエージェントは、人間が吸収できる速度を超えてコードを出してきます。昔は、どんなに複雑なシステムでも人間の手を通ったコードだと仮定できました。その仮定は、もう成り立ちません。

元記事は、2つの極端な立場のどちらにも賛成しません。

  • 全行を読み、手でも書けるようにするべきだ
  • コードは見なくていい。何を作るかに集中し、どう作るかはモデルに任せればいい

前者については、若手に何年も「手で書く」練習をさせてくれる会社は少なく、経済的に成り立たないと指摘します。「全行を理解せよ」「シニアとペアを組め」「丁寧にレビューせよ」というよくある助言も、ごく一部の会社でしか実践できない願望だと切っています。

自分も、これには頷くところがあります。レビューが大事なのは確かですが、エージェントの出力量に人間のレビューで追いつけると考えるのは、現実的ではありません。

では後者の「コードは見なくていい」はどうでしょうか。見ないままでは、何かおかしいと気づく手がかりを失います。次の「地図」は、その手がかりを最小限の形で持つ考え方だと受け取りました。

必要なのは「詳細な知識」ではなく「海の地図」

では何を持てばいいのか。元記事では、アーキテクトやCTOの動き方が手がかりにされます。

100万行のレガシーコードで深夜2時に障害が起きたとき、SREに必要なのは全モジュールの知識ではありません。必要なのは、次のものです。

  • システム全体を遠くから見渡した高レベルの地図
  • どこを掘るべきか、怪物がどこにいるかを知っていること
  • 見知らぬコードベースに飛び込み、状況をつかみ、ホットフィックスを当て、インシデントレポートに書けること

ここで2つの状態が分けられます。1つは「モジュールXを自分で書いたので隅々まで知っている」状態です。もう1つは「抽象化の構造を理解していて、どのモジュールが壊れても直せる」状態です。手で書く経験が与えるのは前者です。しかし、障害の連絡を受ける人が必要とするのは後者だ、という整理です。

タイトルの "Here Be Monsters" は、古地図の「ここには怪物がいる」という言い回しを踏まえたものでしょう。地図の精度は粗くていい。ただし、危ない海域だけは分かっている必要がある、ということだと読みました。

所有を支える3本柱

この地図をどう作るのか。元記事は3つの柱を挙げています。

3本柱の図。基礎で気づき、広さで掘る場所を決め、深さで潜って直す。下段にSonarQubeの例を示す

3つは並列の能力ではなく、「気づく」「決める」「潜る」の順に働くもの、と私は読みました。

1. 基礎(Fundamentals)

静かな失敗に気づくための土台です。エラーで落ちるわけではないのに、なんとなく遅い、10回に1回だけ失敗する、といった種類の不具合を指します。

元記事の例えが分かりやすいので借ります。ダイブボットに、浅い所から順に深い所まで金を取りに行かせたところ、戻るまでの時間は次のようになりました。

水深 往復にかかった時間
2m 4秒
4m 16秒
16m 256秒

所要時間が、深さの2乗で増えています。この数字を見て「おかしい」と感じるのに必要なのは、計算量という概念があると知っていることだけです。

データ構造とアルゴリズム、ネットワーク、並行処理、分散システム。大学のCSで教わる内容ですが、独学でも身につけられると書かれています。

2. 広さ(Breadth)

技術でも技術以外でも、幅広い話題について会話できること。専門家である必要はなく、「何かがおかしいときに、何を調べればいいか分かる」程度の知識で十分です。

海図のブイにたとえられています。潜る場所を決める判断材料です。

面白いのは、広さは教えられないと言い切っている点です。「Everything 101」という授業はありません。できるのは、読んで探索すること、奇妙なインシデントを覚えておくこと、日々の経験を仕事とつなげることだけだ、と書いています。この蓄積は複利で効きますが、維持の努力は必要です。

3. ジャストインタイムの深さ(Just-in-Time Depth)

どんな問題にも飛び込み、調べ、解決する意志と能力のことです。未知の領域でも、必要なら潜ります。同時に、自分の手に余る潜水だと判断したら助けを求める謙虚さも含みます。すべての潜水が価値のあるものではない、という一言も添えられています。

元記事の実体験が印象的でした。エージェントのオーケストレーターを作っていて、エージェントやサブエージェントのライフサイクルにまつわるバグが一斉に噴き出しました。ダイブボット自身に何度直させても直りません。

そのとき、何年も前にKubernetesの本で読んだ「レベルトリガーのステートマシン」という言葉を思い出したそうです。これは、「あるべき状態」と「今の状態」を毎回見比べ、差があれば埋める設計のことです。なぜ効いたのか、元記事に詳しい説明はありません。想像ですが、通知を取りこぼしても次の確認で差に気づけるので、落ちやすいエージェントの管理に合ったのでしょう。Quiroga さんは電気工学における「レベルトリガー」の由来まで掘り下げ、エージェントと一緒にコア部分を設計し直しました。それ以来、安定して動いているそうです。

これは、広さ(昔読んだ本の記憶)が、ジャストインタイムの深さ(必要な分だけ掘り下げる)の入口になった例です。柱が独立しているのではなく、つながって働くところが大事だと感じました。

スペシャリストでもジェネラリストでもT字でもない

元記事は、これまでの人材像(スペシャリスト、ジェネラリスト、T字型)のどれとも違う形として「オーナー」を挙げています。T字型は深さが1本に決まっていますが、オーナーは問題に応じて潜る場所が変わります。

知識の形の比較図。スペシャリストは1か所だけ深く、ジェネラリストは広く浅く、T字型は広い土台に深い柱が1本。オーナーは広い土台から深さの違う細い縦穴が何本も伸び、いちばん深い穴の先に潜水艦がある

幅広い知識の上に、深さがばらばらの細い縦穴がいくつも空いている形です。いちばん深い穴の先には潜水艦がいます。図は元記事のイメージをもとに、自分で描き直しました。

この形の人に求められるのは、プレッシャーの下で素早く学ぶ力です。元記事の書き手は、履歴書に「学習が早い」と書く人に、面接で「複雑なシステムを短期間で理解した経験と、そのやり方」を聞くそうです。プレッシャーの下で、実際に怪物と戦いながら学べるか。この問いは、自分にも返ってきます。

自分に引きつけて考えたこと

自分の経験では、個人開発で困ることはあまりありません。作りたいものが自分の中で要求として固まっているので、エージェントが外れたものを出してきても、すぐに気づけるからです。

困るのは仕事です。相手の要求を十分に理解しないまま、エージェントを走らせてしまうことがあります。すると、出てきたものに相手の理解が追いつかず、失敗する印象があります。コードは動いているのに、要求と想像していたものが違う。このずれは、画面の挙動を見ると特に分かりやすく表れます。

「何かおかしい」と感じるきっかけは、コードが臭うときと、要求と想像しているものが違うときの2つが多いです。後者は、コードを読む前に、動かして画面を見た時点で気づけます。

エラーも出ず、どうにも進まないときは、ログを1つずつ絞り込みます。それでも切り分けられないときは、課題を立てて別立てで動かすと、問題の範囲が見えてきました。

知識が足りなくて詰まった経験は、実はほとんどありません。調べるコストが安くなったので、言語の仕様の感覚をつかみやすく、エラーが出ても一次調査はすぐ終わります。元記事の「ジャストインタイムの深さ」は、自分にとってはコストの下がった部分でした。難しくなったのは、その手前の「おかしい」と気づくことです。

1つ目は、気づく仕組みをエージェントの外に置く必要があるという点です。SonarQubeの事例は、検出が人間の勘ではなくCIツールだったから成立しました。記事のコメント欄にも「CIが何も指摘しないまま、コードが静かに腐っていくときのトリガーは何か」という鋭い質問がありました。元記事の言う「静かな失敗」は、まさにそこです。

同じコメント欄では、複雑度の上限やミューテーションテスト(わざとコードを壊してテストが気づくか確かめる手法)を、検知器として使う案も出ていました。エージェントとは独立して持っておくと、気づくきっかけが増えそうです。

2つ目は、育成の問題が解けていないという点です。元記事でも「次世代をどう育てるか」が最大の課題とされていて、答えは出ていません。3本柱のうち基礎は学べ、広さは集められ、深さは練習できる、という見立ては示されています。ただ、その練習の場をどう作るかは、まだ見えていません。自分で試すなら、エージェントに書かせた小さなアプリへ意図的に不具合を仕込み、原因を探す練習が手軽そうです。

3つ目は、「全部読む派」と「何も読まない派」の間に、もう1本道があるという点です。コードを読むか読まないかの二択で議論すると、どうしても疲れます。「どこを読むか決められるだけの地図を持つ」という第三の立場は、現実の運用に近いと感じました。

「自分は直せるのか」という最初の問いには、今のところ直せている、と答えられます。調べるコストが下がったからです。ただ、本当の問いは別にあると気づきました。「おかしい」と気づけるだけの地図を持っているか、です。要求とのずれも、コードの臭いも、気づかなければ潜ることすらできません。こちらなら、日々の積み重ねで答えを変えていけます。

明日からやってみること

  • 最近エージェントが書いたコードのうち、自分が一度も開いていないモジュールを1つ選び、役割と依存先を説明できるか試す
  • CIやlintに、複雑度などの「静かな劣化」を拾う指標が入っているか確認する
  • 障害対応で「あのとき調べたこと」を、後から思い出せる形でメモに残す(広さを維持するため)
  • 自分の「学習が早い」を裏づける具体的なエピソードを、1つ言語化しておく

おわりに

エージェントがコードを書く時代でも、システムの持ち主は必要です。ただ、その持ち主に求められるものは、「全部書いた人」から「全体の地図を持ち、必要なときに潜れる人」へ移っていく。元記事はそう考えているようです。

元記事の結びは、古いラジオを分解して直した子どもの話です。仕組みは知らず、ただ音楽を聴きたい一心で直す。組み立て直すとネジが少し余っていた、というところまで書かれています。持ち主になるのはそういう人だろう、という締めでした。

エージェントを使い始めて、手を動かす量が減り、不安になっている人には一読をおすすめします。SonarQubeとオーケストレーターの2つの実例があるので、抽象論に流れず読めます。