じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

おい、方法を学べ

はじめに

エディタを開いたまま、手が止まっていた。

書くことは決まっている。決まっているのに、最初の一行が出てこない。内容が自分の中でまだ言葉になっていない。その感覚だけがある。カーソルが点滅している。点滅を眺めていた。

「課題から入れ」という原則がある。手段から入るな、何を解くべきかを先に考えよ。正しいと思う。長い間、信じてきた。信じてきたのだが、ずっと聞きたかったことがある。

課題って、どうやって見つけるんですか。

誰にも聞けなかった。正確に言えば、聞いたことはある。返ってきたのは「現場を見ろ」「ユーザーの声を聞け」だった。目の前には日常があり、業務があり、なんとなく回っている世界がある。その中から「これが課題だ」と名指しすることが、そもそもできない。見つけ方がわからないまま、ただ座っていた。座っている自分に苛立っていた。苛立っていることにも苛立っていた。

後になって気づいた。「課題から入れ」と言える人は、自分の中で自動的に動いている診断プロセスを省略している。「どこを見るか」「何を測るか」「どの違和感を拾うか」が内面化されていて、課題が「見える」のであって「見つける」ものではない。だから見つけ方を聞かれても言語化できない。この原則が有効なのは、すでにその領域の語彙と観測手段を持っている人——つまり方法を持っている人——だけだ。方法を持たない人にとっては、「課題から入れ」は呪いになる。課題が見えないとき、人は自分の能力を疑う。怠惰だから見えないのだ、センスがないのだ、と。

能力の問題ではなかった。視点の問題だった。と、今なら書ける。当時はそれすらわからなかった。わかりたくなかったのかもしれない。わからないことにしておいた方が、楽だったのかもしれない。

このブログが良ければ読者になったりnwiizoXGithubをフォローしてくれると嬉しいです。

この記事における「方法」の定義

「方法を学べ」と言いたい。しかし、「方法」が曖昧なまま語ると、読む人によって受け取り方がバラバラになる。過去に何度かそういう失敗をした。だから先に言葉を定義しておく。この記事で「方法」と呼ぶものは、問題を分解し、解決するための体系化された知識とアプローチだ。

3つに分けて考えている。

  • 操作の知識: 道具をどう動かすか
  • 構造化の知識: 問題をどう分解するか
  • 文脈の知識: 何が重要かをどう判断するか

言い換えれば、実行・分解・判断だ。

「実行」は、手を動かして何かを作る能力だ。Pythonを書ける。Kubernetesを操作できる。プログラミング言語フレームワーク、ツールの操作がここに入る。

「分解」は、複雑な問題を扱える単位に切り分ける能力だ。「この問題はボトルネックの問題だ」「これはフィードバックループの問題だ」と構造を見抜ける。スクラム、リーン、アジャイル、システム思考といった方法論がここに入る。

「判断」は、「この文脈では何が重要で何が重要でないか」を見極める能力だ。同じ技術でも、金融とゲームでは優先順位が違う。その違いを知っている。特定分野の概念、パターン、ベストプラクティスがここに入る。

なぜ3つか。正直、2つでも4つでもよかった。ただ、「実行できるか」「分解できるか」「判断できるか」と自分に聞いてみたとき、この3つの問いで知識の穴を点検できた。それだけの話だ。

3層の間には、依存関係がある。

判断は、分解を前提とする。「何が重要か」を判断するには、まず問題を分解して構造を見る必要がある。構造が見えないまま「これが重要だ」と言っても、それは直感であって判断ではない。

分解は、操作を前提とする。Kubernetesの問題を分解するには、Kubernetesを触った経験が必要だ。触ったことがないものを、構造的に分解することはできない。

つまり、操作→分解→判断という順序がある。

ただし、この順序は「学ぶ順序」ではない。「依存関係」だ。判断を学ぶためには、分解ができる必要がある。分解を学ぶためには、操作ができる必要がある。しかし、操作だけを完璧にしてから分解に進む必要はない。私自身、Terraformの操作コマンドを先に覚えてから設計原理を学ぼうとして、半年間terraform applyの繰り返しで過ごしたことがある。操作はできる。しかし、「なぜこのモジュール構成なのか」を分解できない。操作の習熟を待っていたら、分解の学びが永遠に始まらなかった。操作しながら分解を学び、分解しながら判断を学ぶ。3層は並行して育つ。待っていても、次の層は始まらない。

「方法を学べ」と言うとき、私はこの3つすべてを含めている。どれか1つではない。技術スキルだけあっても方法論がなければ使いこなせない。方法論だけあっても領域知識がなければ適用できない。3つは相互に補完し合う。

「3つで足りるのか」と聞かれるかもしれない。正直に言えば、「判断」の中には、純粋な技術知識では収まらないものがある。組織の力学、ステークホルダーの価値観、倫理的な判断。「技術的に正しい」と「組織として採用できる」は別の問いだ。セキュリティ上最適な設計が、ビジネスの速度を殺すことがある。アーキテクチャとして理想的な分割が、チームの政治的な境界と衝突することがある。この記事では「方法」を技術的な問題解決の文脈に限定して書いている。しかし、現場では判断の上にさらに「交渉」と「妥協」の層がある。それは技術の方法論ではなく、人間の方法論だ。3層で足りるかと問われれば、足りない。足りないことを知った上で、この記事では技術の話に集中する。

3層それぞれの到達度は、こう測れる。操作は「説明できるか」ではなく「手が動くか」だ。分解は「構造を描けるか」だ。判断は「トレードオフを言えるか」だ。Rustを「知っている」と「Rustで考えられる」は違う。前者は操作の入口、後者は分解と判断を含んでいる。もっと言えば、「説明できる」「再現できる」「即応できる」の3段階がある。本を読んで説明できる段階は、まだ「情報」だ。手を動かして再現できる段階で「知識」になる。考えなくても即応できる段階で、ようやく「方法」になる。

なぜこの定義が重要か。「方法」が曖昧だと、「方法を学ぶ」も曖昧になるからだ。「Pythonを勉強しました」と「システム思考を学びました」では、学んだ後の視野の広がり方がまったく異なる。前者は操作の知識、後者は構造化の知識だ。何を学ぶかによって、何が見えるようになるかが変わる。

自分の知識を点検するとき、「操作できるか」「分解できるか」「判断できるか」と問うといい。3つすべてにYesと言えるなら、その領域の「方法」を持っている。どれかがNoなら、そこに学ぶべきものがある。

だから「方法を学べ」と言うとき、私が意味しているのは「情報を集めろ」ではない。「考えなくても使えるレベルまで落とし込め」だ。Goを説明できることと、Goで考えなくてもコードが書けることは違う。後者にならなければ、言語の上にアーキテクチャや設計の思考を積むことができない。文法を考えている間は、アーキテクチャを考える余裕がない。考えなくていいことが増えると、考えるべきことに集中できる。

では、この「方法の知識」がないとき、実際に何が起きるのか。

障害の名前を知らなければ、落ちた理由がわからない

本番障害が起きた。APIのレスポンスタイムが急激に悪化し、タイムアウトが連鎖して、最終的にサービス全体が応答不能になった。

何かがまずかったのはわかる。でも、何がまずかったのかわからない。リクエストが多すぎたのか、サーバーのスペックが足りなかったのか、そもそもアーキテクチャが間違っていたのか。漠然とした「やられた」感だけがある。

私は駆け出しだった頃、その違和感を言語化できなかった。「なんか落ちた」のまま、モヤモヤが残った。胃のあたりに不快感がある。何かが間違っている気がする。でも、何が間違っているのか指させない。ログを開く。全行が等しく意味不明に見える。どこが重要でどこが無関係なのか、判断する基準がない。Slackで「障害です」と報告する。「で、原因は?」と聞かれる。固まる。「課題が見えない」とは、こういう状態だ。怠惰ではない。目の前に情報はある。しかし、情報を「手がかり」に変換するフィルタがない。全部見えているのに、何も見えていない。

当時の上司は「もっとちゃんと調べろ」と言った。「ちゃんと」が何を意味するかはわからなかった。端から端まで読んだ。読んだが、どの行が重要なのか判断できなかった。「課題が見えない」を「怠惰」や「能力不足」と誤認するのは、見えている側が陥る典型的な誤りだ。見える人にとっては「見ればわかる」。見えない人にとっては「見ても何もわからない」。同じログを見ていても、使っている眼鏡が違う。

熟練のSREは違う。同じ障害を見ても、同じログを見ても、見ている場所が違う。まずエラーレートの変化点を見る。次にレイテンシの分布——平均ではなくP99を見る。「いつから」「どのエンドポイントで」「どのくらいの割合で」。数字を3つ確認した時点で、仮説が立っている。「キャッシュの有効期限が同時に切れて、バックエンドにリクエストが集中した。典型的なサンダリングハード問題だ」と言える。障害の瞬間を特定し、構造的に捉えられる。

分散システムの障害には、パターンに名前がついている。キャッシュが一斉に失効してリクエストが殺到する「サンダリングハード」。障害が連鎖してコンポーネントが次々と倒れる「カスケード障害」。名前があると、対策の候補が自動的に浮かぶ。サンダリングハードならジッター(タイミングをランダムにずらすこと)やキャッシュウォーミング。カスケード障害ならサーキットブレーカーやタイムアウト設計。名前は、仮説→対策→再発防止という変換パイプラインのショートカットキーだ。

障害パターンの名前を知らない私も「落ちた」ことは感じている。 しかし、それを「課題」として認識できない。これは能力の差ではない。語彙の差だ。

ただし、語彙があれば万能かというと、そうでもない。名前を知っていても、目の前の障害がそのパターンかどうかを判別するには、観測の手段と経験が必要だ。語彙は必要条件であって十分条件ではない。逆に、語彙がなくても課題を当てられる人がいる。触れた回数が多い人だ。直感に見えるが、実態は暗黙のパターンマッチングだ。ただし、名前がないとチームに共有できない。語彙を増やす最短ルートは、本を読むこと、障害報告書を読むこと、他人の失敗を追体験すること。自分で全部失敗するには人生が短すぎる。

しかし、名前が害になる場面もある。名前をつけた瞬間に、わかった気になる。目の前の障害が本当にそのパターンなのか、別の要因が重なっていないか。名前はショートカットであって、ゴールではない。名前に飛びつくと、名前に合わない症状を無視する。名前を知っていることと、名前に頼りすぎないことは、同時に必要だ。

名前をつけるとは、違和感と課題認識の間にある溝を越える操作だ。3つのことが同時に起きる。第一に、バラバラだった症状が1つの構造として圧縮される。第二に、その構造を他の場面でも検索できるようになる。第三に、対策の候補が構造に紐づいて出てくる。1つの障害から学んだことが、10の障害に適用できる。それは名前という圧縮を経由しているからだ。

ここにもう1つ、見過ごされがちな問題がある。名前を知らないということは、その方向に道が存在すること自体を知らないということだ。 AIに聞けば対策は教えてくれる。しかし、AIに聞くためには「キャッシュが同時に切れてリクエストが集中する現象は何ですか」と問う必要がある。この問いを立てるには、少なくとも「キャッシュの同時失効」が原因である可能性に気づいている必要がある。道の存在すら知らなければ、歩き出すことも、誰かに道を聞くこともできない。

つまり、方法を知らない人間には、課題が見えない。見えないものを「解くべきだ」と言われても、困る。

違和感の正体が見えない

「違和感はあるのに、課題として認識できない」——これは障害対応に限った話ではない。日常の仕事でも頻繁に起こる。

あるプロジェクトで、半年間「なんとなくうまくいかない」と感じていた。みんな忙しそうにしている。会議も多い。Slackは常に未読がある。でも、なんとなく進んでいない。違和感はある。ただ、何が問題なのかわからない。

私は「コミュニケーションが足りないんじゃないか」と言った。なんとなくそれっぽかった。会議を増やした。Slackのチャンネルを増やした。改善しなかった。「コミュニケーション不足」は、catch (Exception e) {} だ。 エラーは握りつぶされる。原因はそのまま残る。

TOC(制約理論——「全体の成果はもっとも弱い環が決める」という考え方)を学んだ後、同じ状況を見直した。ボトルネックが見えた。フロントエンドの実装が週に5件来るのに、デザインレビューは週1回。3日待ちが常態化していた。開発者は待っている間に別のタスクに手を出し、コンテキストスイッチが積み上がり、全体の生産性が下がっていた。これは「コミュニケーション不足」ではなく「フローの制約の問題」だった。

制約理論を知らなかった半年間、私は会議を増やすことで問題を悪化させていた。会議が増えれば、デザイナーの時間はさらに減る。レビューの頻度はさらに下がる。「コミュニケーションを増やす」が「ボトルネックを悪化させる」に直結していたのに、構造が見えていなかった。

なぜ人は構造ではなくラベルに逃げるのか。構造を見るには知識が要り、指摘すると責任が生じる。「デザインレビューが週1回しかない」と言えば「じゃあお前が変えろ」と返ってくる。「コミュニケーション不足ですね」なら、誰の問題でもない。ラベルは3秒で出せるが、構造の分析には時間がかかる。

ラベルを構造に戻すには、具体的な問いを使う。「待ち時間はどのくらいか」「同時進行のタスクはいくつあるか」「どこで止まっているか」「誰が制約になっているか」。この4つを聞くだけで、「コミュニケーション不足」は分解される。

ただし、正直に書く。「会議を増やす」が正解のケースもある。情報の非対称性が問題の本質であるとき、共有の場を増やすことは直接的な解になる。ラベルが正しいこともある。問題は、ラベルが正しいかどうかを検証せずに貼ることだ。

同じ「なんとなくうまくいっていない」を感じていても、持っている方法の知識によって、見える課題がまったく異なる。

方法が課題を照らす

障害対応とプロジェクト運営の例を見てきた。どちらも、方法を知らなければ課題が見えなかった。ここで馬車と蒸気機関の話をしたくなる。「方法を知らなければ、馬をもっと速く走らせることしか考えられない」。よくある例だ。しかし、借り物の例は使わない。もう1つ、自分の経験で語る。

インフラの監視を設計していたとき、「もっと見やすいダッシュボードを作ろう」が課題だと思っていた。Grafanaのパネルを増やし、配色を工夫し、アラートの閾値を調整した。「監視を改善する=見せ方を良くする」だと思っていた。

具体的に言う。あるAPIのレスポンスタイムが遅かった。Grafanaのダッシュボードには、平均レスポンスタイムのグラフが表示されている。「平均300ms」。遅い。しかし、「どこが遅いのか」はわからない。データベースのクエリが遅いのか、外部APIの呼び出しが詰まっているのか、単にネットワークのレイテンシが高いのか。ダッシュボードは集約された数値を見せてくれるが、数値の内訳は見えない。

私はダッシュボードのパネルを増やした。CPU使用率、メモリ使用率、ディスクI/O、ネットワーク帯域。パネルが増えるたびに、何かがわかった気がした。実際には、何もわかっていなかった。見せるデータを増やしただけで、リクエストが「どこを通って、どこで詰まっているか」という根本的な問いには一切答えていなかった。

ダッシュボードの配色に悩んでいた。正常は緑、警告は黄色、異常は赤。閾値をいくつにするか。300msで黄色にするか、500msにするか。今思えば、問いの立て方がそもそも間違っていた。「見せ方」のレイヤーで課題をいじっていた。計測していないものは、見せようがない。当たり前のことだが、当時の私にはその当たり前が見えていなかった。

OpenTelemetry(システムの動作を計測・追跡するための標準規格)を学んだ後、課題設定が根本から変わった。分散トレーシングという概念を知った。1つのリクエストがシステムの中をどう流れ、どこで何ミリ秒かかっているかを、リクエスト単位で追跡できる。トレースを入れてみて初めて、「平均300ms」の内訳が見えた。認証サービスへの呼び出しで120ms、データベースのクエリで80ms、外部決済APIの応答待ちで90ms。残りの10msはネットワークとシリアライゼーション。

ボトルネックは外部決済APIだった。しかもリトライが走っていた。私がダッシュボードの配色に悩んでいた間、答えはリクエストの中に隠れていた。必要だったのは「見せ方を工夫する」ことではなく、「見えていなかったものを見えるようにする」ことだった。計装(instrumentation)という発想がなければ、この課題設定にたどり着けない。

この経験で学んだのは、課題が「どのレイヤーにあるか」を見誤ると、いくら努力しても解決しないということだ。私は表示のレイヤーで課題をいじっていた。本当の課題は計測のレイヤーにあった。計測のレイヤーの存在自体を知らなかったから、表示のレイヤーで頑張るしかなかった。

知らない方法で解ける課題は、課題として認識できない。「そういうものだ」と受け入れてしまう。私にとって「平均レスポンスタイムしか見えない」は、監視とはそういうものだ、と思い込んでいた状態だった。

方法の解像度が、課題の解像度を決める。 そして、自分の課題認識が「どのレイヤー」にあるかを見抜くこと自体が、方法の知識を必要とする。

ここで1つ、疑問が浮かぶ。方法を学んだから課題が見えたのか。それとも、課題に困っていたから方法を学べたのか。

正直に言えば、両方だ。OpenTelemetryを学んだのは、「平均レスポンスタイムしか見えない」という不満があったからだ。しかし、その不満を「これは計装の問題だ」と名づけられたのは、OpenTelemetryを知った後だ。鶏と卵に見えるが、実際には螺旋だ。違和感が方法を引き寄せ、方法が違和感を課題に変換し、課題が次の違和感を生む。

そして、方法が照らすのは課題だけではない。「何が重要か」「何がリスクか」「何を先にやるべきか」優先順位の判断も、方法の知識で変わる。制約理論を知っていれば、「全体のスループットを最も制約しているのは何か」という問いが立つ。この問いがなければ、目についた問題から手当たり次第に着手する。忙しいが、成果が出ない。

ただし、見えるようになった人が次に陥る罠がある。すべてが課題に見えてしまうことだ。方法の知識が増えると、今まで気にならなかったことが全部「改善すべき点」に見える。コードの結合度、デプロイパイプラインの無駄、チーム間のハンドオフの遅延。全部見える。全部直したくなる。しかし、全部直す時間はない。見えることと、今やるべきことは別だ。課題が見えすぎる人間は、改善中毒に陥る。これも、方法の目的化の一種かもしれない。

そしてここに、もう1つの構造がある。

ここまでの話を振り返ると、私がやっていることには共通のパターンがある。具体的な障害を経験する。そこからパターンの名前を知る。名前の背後にある構造を取り出す。すると、まったく別の場面でも同じ構造が見える。サンダリングハードの経験から「同時に多数のリクエストが1点に集中する」という構造を取り出した。すると、年末のセール開始時刻にアクセスが殺到する現象も、CI/CDパイプラインで全チームのビルドが同時にキューに入る問題も、同じ構造として見えるようになった。具体的な見た目はまったく違う。しかし、構造は同じだ。

この運動を言語化するとこうなる。具体的な経験から、抽象的な構造を取り出す。取り出した構造で、別の具体を照らす。 制約理論を学んだときも同じ運動が起きた。「デザインレビューが週1回でボトルネックになっている」という具体から、「全体のスループットは最も制約された工程で決まる」という構造を取り出した。すると、別のプロジェクトで「QAチームのキャパシティが全体のリリース速度を制約している」と見えた。具体的な文脈はまったく異なる。しかし、構造を一度取り出してしまえば、それは1つの場面に留まらない。

たとえば、「持ち家か賃貸か」という議論がある。不動産の話だ。しかし、一歩引いて考えると、これは「所有か利用か」という構造の問題だ。その構造が見えた瞬間、サーバーを自前で持つかクラウドを使うか、ライブラリを自作するかOSSを使うか、人を雇うか外注するか——まったく異なる文脈に同じ構造が適用できる。片方の文脈で得た判断基準が、もう片方でも使える。

これが「1つを学んで10に適用する」のメカニズムだ。しかし、この変換は自動的には起きない。具体的な方法を学んだとき、そこから抽象的な構造を取り出すのは、自分自身だ。 本が教えてくれるのは具体的な事例とメカニズムだ。構造を見出すのは読者の仕事だ。USEメソッドを知った。「Utilization・Saturation・Errorsの順に点検する」——これは具体的な手順だ。ここから「問題を複数の独立した観点で順序立てて点検する」という構造を取り出さなければ、USEメソッドはパフォーマンス分析でしか使えない「手順書」のままだ。構造を取り出した人間は、障害対応でも、コードレビューでも、プロジェクトの健康診断でも、同じ型で思考できる。

同じ本を読んでも、得られるものが10倍違う人がいる。違いは記憶力ではない。具体から構造を取り出し、別の具体に適用する往復運動を、意識的にやっているかどうかだ。私のやり方はこうだ。本を読んだあと、「この本が教えた手法を、一言で言うと何か」と自分に問う。一言にできたら、「同じ構造を持つ、まったく別の場面は何か」と考える。2つ目が見つかったとき、その手法は「手順書」から「思考の型」に昇格する。見つからなければ、まだ構造が取り出せていない。

そしてここに、一方通行の性質がある。構造を取り出せる側にいる人間には、具体の世界も見える。しかし、具体しか見えない側にいる人間には、構造の世界は見えない。一度構造が見えてしまうと、「あのとき、なぜ気づかなかったのか」がわかる。しかし、構造が見える前の自分は、「何が見えていないか」すらわからなかった。だから「構造を取り出せ」と言われても、取り出した経験がない人には、何を言っているかわからない。「課題から入れ」と同じ構造がここにもある。見えている側が、見えていない側に「見ろ」と言っている。

では、この一方通行をどう越えるか。1つだけ確実に効く方法がある。異なる文脈で同じ壁にぶつかることだ。Rustでデータ競合にぶつかる。Goでも似たようなバグに遭遇する。Pythonでもリストの共有状態で事故を起こす。3回目あたりで、「これは言語の問題ではなく、共有状態へのアクセス制御の問題だ」と気づく。具体的な失敗を3回繰り返すと、共通する構造が浮かび上がる。失敗は、構造を取り出すもっとも確実な教師だ。

結局のところ、方法の知識が課題の解像度を決める。「遅いから、もっと頑張る」と「デザインレビューが週1回で3日待ちが発生しているから、非同期レビューを導入する」では、解像度がまるで違う。高解像度な課題認識を持つ人は、低解像度な課題も見える。逆は成り立たない。これは能力の問題ではない。道具の問題だ。

本を読んで、問題が見えるようになった

道具の話を続ける。というか、知識そのものが道具だと思っている。プログラミング言語フレームワークだけが道具ではない。概念、分析手法、設計原理。頭の中にある知識が、目の前の問題を切り分ける刃物になる。

パフォーマンス分析の本を読んだことがある。Brendan Greggの『詳解 システム・パフォーマンス』だ。読む前と後で、同じシステムが違うものに見えた。

読む前の私は、パフォーマンス問題が起きたとき「遅い」しか言えなかった。「遅い」の内訳がわからなかった。CPUが飽和しているのか、I/Oで待っているのか、ロックの競合が起きているのか。どこを見ればいいのか、そもそも何を計測すべきなのかがわかっていなかった。「遅い」の前で立ち尽くしていた。

この本が教えたのは、ツールの使い方ではなかった。問いの立て方だった。USEメソッドという手法がある。Utilization(使用率)、Saturation(飽和度)、Errors(エラー)この3つの観点で、すべてのリソースを順番に点検する。手順としてはシンプルだ。しかし、この「順番に点検する」という発想が、私にはなかった。「遅い」から「なんとなくCPUが高い気がする」に飛んでいた。途中のステップを全部飛ばしていた。飛ばしていることにすら気づいていなかった。

なぜ飛ばしてしまうのか。問題を分解する語彙がなかったからだ。 「遅い」を分解するには、「遅い」がどのリソースの、どの指標に現れているかを特定する必要がある。CPUの使用率が高いのと、CPUのランキューが飽和しているのは、まったく異なる問題だ。前者はCPUを多く使っているだけで、まだ余裕があるかもしれない。後者はCPUの処理待ち行列(ランキュー)にタスクが溜まりすぎている。対処が違う。しかし、この区別は「飽和度」という概念を知らなければ、そもそも見えない。

読んだ後、「遅い」の解像度が変わった。「遅い」が「ディスクI/Oの飽和度が90%を超えている」になった。「レイテンシが高い」が「カーネルのスケジューラがCPUの処理待ち行列に積まれたタスクを処理しきれていない」になった。同じシステムを見ているのに、見える景色がまったく違う。

分散システムの設計原理を扱ったMartin Kleppmannの『データ指向アプリケーションデザイン』でも、同じことが起きた。読む前、私はデータベースの選定を「MySQLPostgreSQLか」で考えていた。スケーリングは「サーバーを増やせばいい」くらいの解像度だった。

(※原著の第2版が出て全員が喜んでいる。)

learning.oreilly.com

この本を読んで気づいたのは、私が「スケーリング」と呼んでいたものの中に、互いに矛盾する複数の問題が隠れていたということだ。レプリケーションの一貫性とレイテンシはトレードオフの関係にある。パーティショニングの戦略次第で、ある種のクエリは高速になり、別のクエリは破滅的に遅くなる。「サーバーを増やす」の一言で済むはずがなかった。しかし、私はそのことを知らなかった。知らなかったから、「増やせばいい」で止まっていた。

ソフトウェア設計の結合について書かれたVlad Khononovの『ソフトウェア設計の結合バランス』でも、同じパターンを経験した。読む前の私は、「疎結合にしておけば正しい」と思っていた。コードレビューで「ここ、結合が強くないですか」と言えば、それだけで設計の指摘として成立した。冒頭で書いた「コミュニケーション不足」と同じ構造だ。何も言っていないのに、言った気になれる万能ラベル。

この本が教えたのは、結合には強度・距離・変動性という3つの次元があり、それらのバランスで評価すべきだということだ。強い結合でも、距離が近く変動性が低ければ問題にならない。弱い結合でも、距離が遠く変動性が高ければ厄介になる。「疎結合にしろ」の一言では、この判断ができない。私がレビューで「結合が強い」と指摘していたとき、強度の話をしているのか、距離の話をしているのか、変動性の話をしているのか、自分でも区別できていなかった。区別する語彙がなかったからだ。

もう1冊——これは私自身が翻訳に関わった本だ。Nick Tuneの『アーキテクチャモダナイゼーション』。アーキテクチャの刷新は技術の問題ではなく、組織とビジネスと技術の三位一体の変革だと主張する本だ。翻訳の過程で560ページを何度も読み返した。読み返すたびに、自分がアーキテクチャを「技術の構造設計」としか見ていなかったことに気づかされた。チーム構造がアーキテクチャの不可分な一部であること、コンウェイの法則を観察ではなく設計ツールとして使うこと、モダナイゼーションの成功指標が「新しいシステムが動くかどうか」ではなく「ビジネスアウトカム」であること——技術書を翻訳しているはずなのに、組織論と戦略論を学んでいた。

しかし、この本もすべての問題を完璧に解決する銀の弾丸ではない。翻訳者として断言する。どんなに優れた方法論も、組織と個人にそれを受け入れる準備と継続する体力がなければ機能しない。本が提案する「独立バリューストリーム」も「AMET(イネーブリングチーム)」も、体力がない組織ではただの用語に終わる。体力がない組織は「この本の通りにやったのにうまくいかない」と言い、本のせいにする。本は地図であって、歩く脚力ではない。これは、先に挙げた3冊すべてに言えることだ。

4冊に共通する経験がある。「読む前は、自分が問題を抱えていることすら知らなかった」。

パフォーマンス分析の体系を知らないこと自体が問題だと、読む前の私は思っていなかった。分散データの一貫性モデルを知らないことが設計上の盲点になっていることに、読む前の私は気づいていなかった。結合を1次元でしか評価できていないことに、読む前の私は疑問すら持っていなかった。アーキテクチャを技術だけで語れると思い込んでいたことに、翻訳するまで気づかなかった。問題の存在を知らなかったから、解決しようとも思わなかった。

道具について詳しく知らなければ、目の前の問題が「解決できる問題」なのか「原理的に解決不可能な問題」なのかすら判断できない。

「遅い」が「体系的な手法で5分で原因を特定できる問題」なのか、「アーキテクチャを根本から見直さないと解決しない問題」なのか。この見極めは、方法を知らなければ不可能だ。そして、見極められない人はどちらのケースでも同じ反応をする。「遅いですね、まあ仕方ないですね」。

これが一番怖い。解決できる問題を「仕方ない」で片付けている。解決の入口はすぐそこにあるのに、入口が見えていない。同じ問題を前にして、片方は手も足も出ず、片方は鼻歌を歌いながら直している。違いは才能ではない。「問いの立て方」を知っているかどうかだ。

ソフトウェアの世界では「銀の弾丸はない」とよく言われる。魔法のように問題を解決する単一の技術は存在しない、と。Fred Brooksが1986年に書いたことだ。

しかし、私はこの言い方に違和感がある。

USEメソッドは、パフォーマンス問題に対する銀の弾丸だった。少なくとも私にとっては。「遅い」という怪物に対して、それまでの私は素手で立ち向かっていた。USEメソッドという弾を手に入れた瞬間、怪物は倒せるようになった。OpenTelemetryも、制約理論も、結合の3次元モデルも、社会技術的整合の視点も、Rustの所有権モデルも、それぞれの領域で怪物を殺す弾だった。

銀の弾丸はある。 ただし、万能の一発ではない。特定の怪物を殺す特定の弾だ。問題は「銀の弾丸が存在しない」ことではなく、どの弾がどの怪物を殺すかを知らないことだ。弾を持っていないのではない。弾の存在を知らない。だから素手で戦っている。

しかし、もっと厄介な問題がある。銀の弾丸を「求める」こと自体が、病理だ。

「学んで損したくない」「タイパが悪い」こう言い始めた瞬間、人は新しい弾丸を手に取らなくなる。学ぶコストを「損」と捉えると、今持っている弾丸でなんとかしようとする。そして、自分が持っている弾丸が「すべての怪物を、すべての状態で殺せる万能の一発だ」と思い込む。Kubernetesですべてのインフラ問題が解ける。スクラムですべてのプロジェクトがうまくいく。Rustですべてのソフトウェアが安全になる。ありえない。しかし、新しい弾丸を手に入れるコストを「損」だと思っているから、既存の弾丸の適用範囲を無限に広げようとする。

これが「銀の弾丸はない」の真の意味だと私は思っている。銀の弾丸が存在しないのではない。1つの弾丸で全部解決したいという欲望が、方法の目的化を引き起こすのだ。体力がないのではない。体力を分散させたくないのだ。1冊の本で、1つのフレームワークで、1つの言語で、全部なんとかしたい。その気持ちはわかる。しかし、怪物は1種類ではない。

ちなみに、これは技術の話に限らない。「コミュニケーションが銀の弾丸だ」と主張するオジサンもいる。「社内政治をうまくやれば技術の問題は些末だ」と言う人もいる。しかし、コミュニケーションも社内政治も銀の弾丸ではない。同じ構造だ。コミュニケーションで解ける問題はある。社内政治で通せる案件もある。しかし、それぞれが特定の怪物に対する特定の弾であって、万能ではない。コミュニケーションで解決するのはコミュニケーション不足が原因の問題だけだし、社内政治で通せるのは政治が障壁になっている案件だけだ。技術的に破綻しているアーキテクチャを、いくらコミュニケーションしても直らない。政治力で通したプロジェクトも、技術的な裏付けがなければ崩壊する。

と書いて、立ち止まる。「本を読めば解像度が上がる」。それはそうだ。しかし、読んだだけで上がるのか。

正直に言えば、『詳解 システム・パフォーマンス』を読んだ直後に、USEメソッドを使いこなせたかといえば、使いこなせなかった。本に書いてある通りに手を動かしてみたが、「この数値が高いのは問題なのか正常なのか」の判断ができなかった。正常値の感覚がなかったからだ。本は分解の語彙を教えてくれた。しかし、語彙を持っているだけでは足りない。その語彙を使って実際のシステムを何度も見て、「この数値はこのワークロードなら正常」「この数値は明らかに異常」という感覚を養う必要があった。

本は地図を与える。しかし、地図を読む力は、歩かなければ身につかない。

Rustを触って見えてきたもの

「道具」と言った。では、その道具を手に入れることで、実際に何が変わるのか。私自身の経験を書く。

Rustを学び始めたとき、最初は「速くて安全な言語」くらいの認識だった。C++の代替。メモリ安全。その程度の理解で、チュートリアルを写経していた。

しかし、写経だけでは理解できなかった。私がRustの設計思想を理解できたのは、最初に「遊び」から入ったからだ。

Rustを触り始めたとき、私は何の目的も持っていなかった。「何ができるんだろう」という純粋な興味だけがあった。課題を解こうとしていなかった。ただ遊んでいた。

コンパイラに怒られた。Vec<String>を関数に渡した後で使おうとして、「value used here after move」と言われた。意味がわからなかった。「渡しただけなのに、なぜ使えなくなるんだ」と画面に向かって言った。所有権を無視したコードを書いて、なぜ通らないかを考えた。何の成果も出なかった。

しかし、その「遊び」の時間がなければ、今の理解はなかった。遊びの中で、Rustの輪郭が見えてきた。何を許し、何を許さないか。どこで厳しく、どこで柔軟か。目的を持って触っていたら、目的の範囲内でしか見えなかっただろう。

遊びは効率が悪い。成果が出ない。何をやっているか説明できない。だから、大人になると遊ばなくなる。すべてに目的を求める。

しかし、目的を持つ前に遊んでおかないと、目的自体が貧しくなる。遊びの中で見つけた「面白い」が、後から課題認識の種になる。

なぜ「遊び」が有効なのか、構造を言語化してみる。

目的を持って触ると、「目的に関係するか否か」というフィルタが働く。Rustを「Webサーバーを書くため」に学んだら、所有権はHTTPハンドラの文脈でしか理解しない。しかし、遊びにはフィルタがない。所有権がなぜ存在するかを、用途を限定せずに考えられる。結果として、「この概念はHTTPに限らず、並行処理全般に適用できる」という広い理解に到達する。

つまり、遊びの正体はフィルタなしの探索だ。効率は悪い。成果の予測ができない。しかし、目的というフィルタの外側にあるものを拾える。目的を設定した瞬間に見えなくなるものが、遊びの中では見える。

しかし、これは「遊びを正当化する理論」になっていないか。3ヶ月遊んで何も身につかなかった経験もある。Haskellを触っていた時期だ。モナドが面白くて圏論の本まで買った。3ヶ月後、業務で使える場面は1つもなく、モナドの定義を聞かれても正確に答えられなかった。「フィルタなしの探索」は聞こえがいいが、フィルタがないまま3ヶ月歩いて、元の場所に戻っていることもある。遊びが実を結ぶかどうかは、事前にはわからない。

それでも、遊ぶ。目的の枠内だけで学び続けた人間は、目的の枠を超えた発想ができない。撃ってみれば、案外簡単に怪物が倒せるかもしれない。 弾を込める前から「当たらないだろう」と言って撃たないのが、一番もったいない。遊びは、まだ名前のない怪物に向けて撃つ弾だ。外れるかもしれない。でも、撃たなければ当たりもしない。

「遊び」と「無目的な浪費」の境界はどこか。この問いには答えを持っている。遊びの中で「おや?」と思った瞬間を記録しているかどうかだ。遊んでいて何かに引っかかる。引っかかりを言葉にしてメモする。なぜ引っかかったのかを考える。このループが回っているなら、遊びは探索として機能している。ループが回っていないならただ触って、ただ忘れるならそれは浪費だ。

では、読者が「遊びから入る」を再現するにはどうすればいいか。私のやり方を書く。週に数時間、目的を決めずに技術を触る時間を確保する。そこでやることは、「業務で使う予定のないもの」を触ることだ。業務で使うものを触ったら、それは遊びではなく学習だ。遊びの条件は「役に立つかどうかわからないまま触る」ことだ。そして、触った後に「何が面白かったか」「何に驚いたか」を3行だけ書く。3行でいい。この3行が、半年後に「あのとき触った概念がここで効く」と気づく入口になる。

そうして遊びながら書き込むうちに、Rustの設計思想が見えてきた。所有権、借用、ライフタイム。「データは誰かが所有し、借りるときは明示的に許可を得る」という世界観。最初は制約に感じた。慣れると、制約ではなく設計指針だと気づいた。

すると、過去に書いたコードが違って見えてきた

「あのGoのコード、データ競合を起こしていなかったか」複数のgoroutineから同じデータに同時にアクセスしていた。動いていた。テストも通っていた。しかし、Rustの視点で見ると、あれは「たまたま動いていた」だけだ。タイミング次第でデータ競合を起こし、クラッシュする爆弾を抱えていた。

「あのPythonスクリプト、なぜ本番で落ちたのか」リストを関数に渡して、関数内で変更していた。呼び出し元は変更を想定していなかった。Rustなら、&mutを要求するか、所有権を移動するかを明示する。意図しない変更は、コンパイル時に弾かれる。

「あのC++メモリリーク、なぜ気づかなかったのか」newしたオブジェクトをdeleteし忘れていた。コードレビューでも見落とした。Rustなら、所有者がスコープを抜けた時点で自動的に解放される。忘れようがない。

Rustという方法を知る前は、これは「課題」ではなかった。「そういうものだ」と思っていた。方法を知ったことで、初めて「これは課題だったのだ」と気づいた。

知らなかったときは、違和感すらなかった。動いていたから。テストが通っていたから。「動いているコード」は「正しいコード」だと思っていた。

動くコードは正しい。しかし、正しくないコードも動く。

方法の目的化と、方法を極めることは違う

Rustの例を書いた。「方法を知ることで課題が見える」。ここまでは良い。しかし、この主張をすると、必ず出てくる誤解がある。

「方法を極めろ」と言うと、「方法の目的化」と混同される。でも、両者はまったく異なる。

方法の目的化は、方法を使うこと自体が目的になっている状態だ。「Rustを導入した」ということに価値を見出し、それで何を解決するかを考えない。導入実績を作ることがゴールになる。「うちもRust使ってます」と言いたいだけ。技術ブログを書きたいだけ。

私自身、この罠にハマったことがある。Kubernetesを導入したとき、「クラウドネイティブにした」こと自体に達成感を覚えていた。チームに導入を提案し、半年かけて移行した。技術ブログも書いた。しかし、Kubernetesで何を解決するかが曖昧だった。デプロイ頻度は週1回のまま変わらなかった。スケーリングが必要な負荷もなかった。私は「導入した」という実績を作っただけだった。

本当にそうだろうか。あの導入がなければ、コンテナオーケストレーションの設計思想を学ぶ機会はなかった。結果として、その後のプロジェクトで活きた知識は多い。「目的化だった」と断じるのは、後知恵かもしれない。しかし、当時の私に「何の課題を解くために導入するのか」と問えば、答えに詰まったはずだ。目的化と極めることの境界は、後から振り返って初めて見える。渦中にいるときは、区別がつかない。

区別がつかないなら、早期警戒サインを作るしかない。私が自分に課しているチェックリストがある。「導入すること」を誰かに報告したくなっているか。「この技術で何を解決したか」を聞かれたとき、具体的な数字で答えられるか。「別の方法でも同じ結果が出せたか」を検討したか。この3つのうち1つでもNoなら、目的化の兆候がある。Kubernetesのときは、3つともNoだった。

「導入した」が将来の資産になるか自己満足で終わるかの分かれ目は、そこで学んだ知識が「その技術固有の知識」か「転用可能な原理」かにある。Kubernetesの場合、宣言的な構成管理の思想、reconciliation loopの設計パターン、自己修復するシステムの考え方これらはKubernetesを離れても使える知識だった。だから結果として資産になった。しかし、当時の私がそこまで意識していたかと問われれば、していなかった。結果オーライだ。

方法の限界を学ぶには、その方法で失敗するしかない。Rustの限界は、Rustで書くべきでないものをRustで書いたときに見える。Kubernetesの限界は、Kubernetesで解けない問題にKubernetesを適用したときに見える。本を読んでも限界はわからない。限界は、壁にぶつかって初めて見える。だから、失敗事例を集める。自分の失敗、他人の失敗、撤退戦の記録。比較実験——同じ問題を別の方法で解いてみる——も有効だが、時間がかかる。失敗事例の方が効率がいい。他人の失敗は、最もコストの低い学習教材だ。

方法を極めるとは、「この方法では解けない」と言えるようになることだ。「Rustでできること、できないこと」を肌感覚で知る。その知識によって、課題の認識範囲を広げる。方法はあくまで方法であり続ける。目的は課題解決のままだ。

方法の目的化は視野を狭める。「Rustで解決できそうな課題」ばかりを探すようになる。自分の得意技で解ける問題だけが「問題」に見えてくる。

方法を極めることは視野を広げる。「Rustでは解決できない課題」と「Rustで解決できる課題」の両方が見えるようになる。ハンマーの適用範囲を知っているから、釘でないものに無理にハンマーを振らない。

同じ「学び」でも、到達点は正反対だ。

複数の方法を知る意味。ただし、効果は線形ではない

だから、方法は複数知っている方がいい。

1つの方法しか知らないと、その方法で解決できる課題しか見えない。ハンマーしか持っていなければ、すべてが釘に見える。これは有名な認知バイアスだ。「道具の法則」と呼ばれることもある。

でも、ハンマーもドライバーもレンチも知っていれば、「この課題はハンマー向きだ」「これはレンチの方がいい」「これはどの道具でも解けない、道具を作るところからだ」と判断できる。

「複数知っている方がいい」と書いた。しかし、ここに罠がある。

10個のフレームワークを表面的になぞるより、まず1つの本質を骨まで理解する方が、結果的に多くの応用が効く。

なぜか。1つを深く知ると、「なぜそう設計されているか」が見えるからだ。設計の意図がわかると、別のフレームワークを見たとき、「ああ、これは同じ問題を別の方法で解こうとしているのか」と理解できる。

表面的に10個知っていたときには、それぞれが独立した「覚えるべきもの」だった。1つを深く知った後は、10個が「1つの問題空間の異なる解」として見える。構造が見える。

これが「深さが広さを生む」ということだ。深く知らないと、広くも知れない。

しかし、見えるのは設計の意図だけではない。もう少し踏み込む。深く知ることで見えるのは、構造だ。

Kubernetesを深く知ると、「宣言的な状態管理」「自己修復するフィードバックループ」という構造が見える。この構造は、Kubernetesだけのものではない。Terraformの設計にも同じ構造がある。Gitの設計にも近い思想がある。生物の恒常性維持にもフィードバックループはある。深く掘った人間は、ここで面白いことをする。Kubernetesで学んだ「自己修復」の構造を、まったく別の文脈に持ち込む。組織のインシデント対応プロセスに「宣言的な状態定義と差分検知と自動修復」の発想を適用する。一見まったく関係がない。しかし、構造が同じだから、機能する。

つまり、深く掘るほど、遠いところから借りてこられるようになる。 具体的なレベルで借りると模倣だが、構造のレベルで借りると独自の解が生まれる。回転寿司がビール工場のベルトコンベヤーから着想を得たように、借り元が遠ければ遠いほど、生まれる発想は独自性を帯びる。深さは、隣接領域を広げるだけでなく、遠い領域への跳躍を可能にする。

「広く浅く知っておけ」長い間、これが能力の理想像として語られてきた。多くの領域を浅く押さえておき、1つだけ深く持つ。私自身もそう信じていた時期がある。しかし、実際に深く掘る経験を積んだ後で振り返ると、このモデルには見落としがある。3つ書く。

第一に、「広さ」と「深さ」を独立した軸として扱っている。

あたかも、広さを先に確保してから深さを足せるかのように。しかし、実際に何かを深く掘った人間なら知っている。深さと広さは分離できない。

バックエンドを深く掘ろうとした。するとDB設計が要る。パフォーマンスチューニングが要る。セキュリティの知識が要る。インフラの理解が要る。深く掘れば掘るほど、裾野が勝手に広がっていく。「幅」は意図して作るものではなかった。「深さ」の必然的な副産物だった。

この構造を図形で表すなら、三角形だ。 深さが増すほど底辺が広がる山型。深く掘るから、隣接領域を避けて通れなくなる。避けて通れないから、広がる。この「避けて通れない」が重要だ。意図して広げたのではない。掘っていたら、そこにあったのだ。

第二に、深さから生まれた広さと、表面をなぞった広さを同一視している。

バックエンドを深く掘る過程で身につけたDB設計の知識は、「DBの種類を5つ言える」という知識とは質がまったく異なる。「このクエリがなぜ遅いのか、インデックスの構造から説明できる」隣接領域に必要に迫られて踏み込んだから、実践と結びついている。動機が伴っているから、定着する。表面をなぞっただけの知識は、実践と切り離されている。説明はできるが、使えない。使えない知識は、AIに聞くのと変わらない。

逆に言えば、「幅が広い」のに「深さがない」人は、実はどこも掘っていないだけだ。表面を横にスライドしているだけで、どこにも根を張っていない。

ここまでは「広く浅く」モデルの論理的な誤りを指摘した。しかし、もう1つ、時代の文脈がある。

第三に、このモデルは「情報が希少な時代」の産物だ。

何がどこにあるかを知っているだけで価値があった時代には、浅く広い知識に意味があった。会議で「それ、聞いたことがあります」と言えるだけで、情報のハブとして機能できた。

今は違う。情報は溢れている。AIが整理してくれる。ツールの使い方、言語の文法、フレームワークの設定表面的な知識はAIに聞けば数秒で返ってくる。「広く浅く知っている」は、もはや人間が抱えておく価値がない。

人間のボトルネックは「知っているかどうか」から「理解しているかどうか」に移った。そして「理解」は、深さからしか生まれない。深く掘った人間だけが違和感を持てる。表面をなぞった人間には、違和感すら生まれない。

だから、「まず広く浅く学んでから深掘りしよう」という順序は逆だ。興味のある1点からまず掘る。掘っていくうちに、隣接領域が「必要だから」広がる。動機が伴うから、学習が定着する。

「広く浅く」から入ると、どこにも三角形が立ち上がらない。平らな線が引かれるだけだ。AI時代に人間に求められるのは、平らな線ではない。どこかに深く根を張った三角形だ。

と書いたが、1つ正直に告白する。

「広く浅く」が役に立った場面がある。障害対応で、直接の原因はバックエンドにあったが、フロントエンドのキャッシュの挙動を薄く知っていたから、「これ、フロントのキャッシュが古いレスポンスを返し続けているのでは」と仮説を立てられたことがあった。深くは知らない。しかし、存在を知っていたから、調べる入口にたどり着けた。

「浅い知識は無価値」と断言するのは、嘘になる。しかし、あの場面で役に立ったのは「フロントのキャッシュがあるらしい」という存在の知識であって、「フロントのキャッシュをどう設計するか」という実践の知識ではない。存在を知っている程度の知識なら、AIに「この症状の原因として考えられるものは?」と聞いても得られる。2026年のいま、「存在を知っている」だけの価値は急速に下がっている。

三角形の話をした。深さが広さを生む、と。では、三角形は1つでいいのか。

1つでは足りない。「深く学ぶ」は「1つだけ学ぶ」ではない。1つを深く学んだ上で、異なる前提を持つ方法を複数知ることで、メタ視点が生まれる。私の経験を書く。

3つ目の方法を学んだとき、世界の見え方は劇的に変わった。1と2の比較ではなく、「方法を比較する」というメタ視点が生まれたからだ。

スクラムウォーターフォールの2つしか知らなかったとき、私は「どちらが正しいか」を考えていた。そこにカンバンという3つ目が加わったとき、「どの状況にどの方法が適するか」という問いに変わった。

しかし、10個目を学んだとき、変化は小さかった。20個目はもっと小さかった。私の中に「方法を比較するフレームワーク」ができてしまえば、新しい方法は既存の棚に分類されるだけだ。劇的な視点の転換は起きにくくなる。

つまり、方法数と課題認識の関係は線形ではない。最初の数個で急激に上がり、その後は緩やかになる。学習曲線の逓減だ。

実感と合う話がある。

人間が同時に頭の中で比較できる選択肢には限界がある。100個の方法を「知っている」としても、課題に直面したときに思い出せるのは、せいぜい数個だ。残りは長期記憶の奥底にあり、意識的に検索しなければ出てこない。

さらに、方法が増えるほど「どれを使うか」の選択コストが上がる。10個の方法から最適なものを選ぶより、3個から選ぶ方が速い。速さは、実践において決定的に重要だ。完璧な方法を選ぶのに3時間かけるより、そこそこの方法で2時間で解決する方が、多くの時は正解だ。

私の実感としては、こうだ。1つの領域で、異なる前提を持つ方法を3つ知っていれば、メタ視点が生まれる。5つを超えると、追加の認識拡張効果は急速に逓減する。 3つ目を手に入れた瞬間の感覚は、今でも覚えている。「あ、これは選べるんだ」と思った。それまでは「どちらが正しいか」だった問いが、「どの状況にどれが合うか」に変わった。景色が変わるというより、自分が立っている場所が高くなった感覚だった。

だとすると、問いは「いくつ学ぶか」ではなく、「どの領域で最初の3つを学ぶか」になる。すでに10個の方法を知っている領域にもう1個追加しても、認識範囲は広がらない。まだ1つしか知らない領域で2つ目を学んだ方が、視野は大きく広がる。

私の場合、インフラの知識があるから「これはアプリケーション層の問題ではなく、ネットワーク層の問題だ」と判断できることがある。プログラミング言語を複数知っているから「この問題はRustで書くべきか、Pythonで書くべきか」という選択ができる。

これは課題を正しく認識するための前提条件だ。方法を1つしか知らない人は、その方法で解けない課題を「課題」として認識できない。見えないのだ。見えないものは、存在しないのと同じだ。

「どの領域で3つを学ぶか」が大事だと書いた。では、新しい領域を学び始めたとき、最初にぶつかる壁は何か。「わからない」が多すぎることだ。

ここで大事になるのが、「わからない」を保留する勇気だ。

新しい領域を学ぶとき、すべてを理解しようとすると詰まる。「これはなぜこうなっているのか」「この部分は何の意味があるのか」。答えが出ないまま先に進めなくなる。

しかし、学びは順序通りに進まない。後で学んだことが、前の疑問を解消することがある。Rustの所有権を最初に読んだとき、私は何もわからなかった。「なぜこんな制約が必要なのか」が見えなかった。ところが、並行処理を学んだ後、「ああ、これはデータ競合を防ぐためだったのか」と腑に落ちた。

最初から全部わかろうとしていたら、所有権の章で止まっていた。「わからないけど、とりあえず進む」という保留ができたから、後で理解できた。

わからないことを「わからないまま抱えておく」のは、気持ち悪い。すっきりしない。しかし、その気持ち悪さに耐えることが、学びの幅を広げる。わからないまま進む勇気が、後で理解する土壌を作る。

私が見落としているもの。そして、見落としに気づいた経験

正直に書く。

Rustの可能性に興奮している。所有権システムで防げるバグの範囲が見えてきた。「これもコンパイル時に防げる」「あれも型で表現できる」と考える時間が増えている。

しかし、その興奮の中で見落としていることがあるはずだ。

量子コンピューティング、バイオテクノロジー、新素材、ロボティクス。これらの分野で何が起きているか、私はほとんど知らない。論文のタイトルは見る。ニュースは読む。でも、手を動かしていない。肌感覚がない。

つまり、それらの領域に関しては、違和感すら持てない状態にいる。

これは仮説ではない。過去に経験している。

コンテナ技術が出てきたとき、私は「仮想マシンで十分だろう」と思っていた。VMwareの知識があった。課題は「いかに効率よくVMを立てるか」だと認識していた。Dockerの記事を読んでも、「軽量な仮想化」程度の理解で止まっていた。

半年後、気づいたら周りはコンテナで動いていた。私だけがVMの最適化を議論していた。「なぜコンテナを使わないのか」と聞かれて初めて、自分が課題を誤認していたと気づいた。問いは「VMをいかに効率化するか」ではなく、「インフラの抽象化レイヤーをどこに置くか」だったのだ。

その半年間で、私は何をしていたか。VMのリソース割り当てを最適化するスクリプトを書いていた。起動時間を30秒短縮するためにブートシーケンスを研究していた。マイグレーションの自動化ツールを設計していた。それ自体は技術的に面白かった。しかし、私は存在しない道路の渋滞を解消していた。

結果として、チームの技術選定に私の意見は反映されなかった。「VMの専門家」としての発言権はあったが、「インフラ戦略」の議論では蚊帳の外だった。半年という時間は、取り戻せない。その間に私が書いたコードは、1行も本番で動いていない。

学んでいれば気づけた。でも学ばなかった。「VMで十分」という認識が、学ぶ動機を奪っていた。課題が見えないから学ばない。学ばないから課題が見えない。悪循環だ。

この悪循環には、もう1つ怖い特徴がある。外から見えないということだ。私は半年間、勤勉に働いていた。コードを書いていた。成果物を出していた。傍から見れば、貢献している。しかし、その貢献先がすでに陳腐化していた。誰も指摘してくれなかった。指摘できなかった。みんな忙しかったし、私の専門領域に口を出すのは気が引けたのだろう。

あの半年の経験があるから、今の自分にも同じことが起きていないか問わずにいられない。

「Rustで解決する」という発想に囚われ、別の方法で解くべき課題を、無理に型システムの問題として設定していないか。Rustで解けない課題を、「課題ではない」と無意識に切り捨てていないか。

私にはわからない。わからないから、怖い。

自分の視野の外側は、見えない。見えないことすら、わからない。これが一番怖い。そして、過去にそれで手遅れになった経験があるから、恐怖は具体的だ。

学び続ける理由

だから、最新技術を触り続ける。

これは「技術が好きだから」ではない。いや、好きではあるのだが、それだけではない。

課題を正しく認識し続けるための、必要な投資だ。

学ぶことをやめた瞬間、課題認識は固定される。世界は変わり続けるのに、自分の課題認識だけが古いままになる。新しい方法で解ける課題が増えているのに、それを「課題」として認識できない。

5年前の方法の知識で、今日の課題を設定しようとする。それは、一度もinvalidateされていないキャッシュを読んでいるようなものだ。値は返ってくる。ただし、現実とは一致していない。

これが一番怖い。だから、学び続ける。

と書いて、立ち止まる。

本当にそうか。学び続ければ、視野は広がり続けるのか。それとも、学ぶことで見えなくなるものもあるのか。新しい方法を知ることで、古い方法の価値を見失っていないか。

この問いに、私なりの答えを書く。

学ぶことで見えなくなるものは、ある。

Rustを深く学んだ結果、私は「シンプルさ」の価値を見失いかけたことがある。「これは型で表現すべきだ」「あれは所有権で制約すべきだ」と考えるうちに、「Pythonで10行で書けるスクリプトに、なぜ100行のRustが必要なのか」という問いを忘れていた。安全性だけを考えれば、すべてをRustで書くべきだ、と当時の私は思い込んでいた。

しかし、それは問いの立て方が間違っていた。

「安全か」ではなく、「この用途に適切か」という軸がある。「正しいか」ではなく、「理解しやすいか」という軸がある。Rustという方法を深く学んだことで、私は安全性の軸ばかりを見るようになっていた。シンプルさや可読性の軸が見えにくくなっていた。

古い方法には、効率以外の価値があることがある。手動デプロイは、CI/CDより非効率だ。しかし、手動でやっていた頃は、デプロイの各ステップが何をしているか全員が理解していた。自動化した途端、パイプラインがブラックボックスになり、壊れたときに誰も直せなくなった。効率を得て、理解を失った。

新しい方法を学ぶと、古い方法が「非効率」に見える。見えた瞬間、古い方法の別の価値、効率では測れない価値が視野から消える。これが、学ぶことで見えなくなるものだ。

だから、学び続けることは万能ではない。学びながら、同時に「この方法では見えないものは何か」を問い続ける必要がある。新しい眼鏡をかけたら、古い眼鏡で見えていたものを意識的に思い出す必要がある。

学び続けるとは、忘れたことを思い出し続けることでもある。

AIが方法を知っている時代に

ここまで「方法を学べ」「学び続けろ」と書いてきた。しかし、1つ、避けて通れない問いがある。

AIは方法を知っている。

サンダリングハードも、カスケード障害も、制約理論も。私が半年かけて学んだことを、AIは数秒で答える。操作の知識、言語の文法、ツールの使い方は、もう人間の優位ではない。分解の知識すら、AIは構造的に提示してくれる。

では、方法を学ぶ意味はなくなったのか。

逆だ。

AIは方法を知っている。しかし、違和感を持てない。

エディタの前で手が止まる。「なんとなくうまくいっていない」と感じる。会議を増やしても改善しない焦りを覚える。AIにはこれがない。AIは聞かれたことに答える。聞かれなければ、黙っている。

課題は、違和感から始まる。AIには、違和感がない。

違和感は、好奇心を持って世界に触れている人間にしか生まれない。「何かがおかしい」と感じるためには、「こうあるべきだ」という自分なりの基準が必要だ。では、その基準はどこから生まれるか。4つある。方法を学ぶ過程で作り上げた技術的な基準。過去の失敗から刻まれた経験的な基準。「こういうシステムはあるべきではない」という価値観の基準。そして、画面の前で「なんか気持ち悪い」と感じる身体的な基準言語化できないが、確かにそこにある直感だ。AIから借りた基準では、違和感は生まれない。借り物の基準は「なるほど」で終わる。自分の基準は「おかしい」から始まる。

もう1つ。

AIは汎用的な方法を知っているが、あなたの文脈を知らない。

VMの最適化に半年を費やした私の後悔。Kubernetesを目的化して得た教訓。Rustの遊びの中で見つけた「面白い」。これらは私だけの経験であり、私だけの課題認識を形作っている。同じ障害を見ても、同じコードを読んでも、私とあなたでは見える課題が違う。その違いが、課題設定の独自性になる。

AI時代に人間に残るのは、この2つだと思っている。

好奇心。 違和感を持ち、「なぜ」と問い続ける力。 自分だけの観点。 固有の経験が生んだ、代替不可能な視点。

と書いて、立ち止まる。この主張自体がすでにコモディティ化している。AIに「人間の価値とは」と聞けば、「好奇心と固有の経験」と答えるだろう。「人間にしかできないことがある」と言いたい人間の願望が、透けて見える。しかし、コモディティ化していることと、間違っていることは違う。「テストを書け」も「コードレビューしろ」もコモディティ化した主張だが、依然として正しい。問題は、正しいかどうかではなく、この主張を自分の経験で検証できているかどうかだ。私の場合、VMの半年、Kubernetesの目的化、OOMKillerの夜——それらの経験を通じて好奇心と観点が鍛えられたという実感がある。実感がある、と思っている。思い込みかもしれない。

方法はAIに聞ける。しかし、何を聞くかを決めるのは自分だ。好奇心がなければ、そもそも問いが生まれない。自分だけの経験がなければ、独自の問いにならない。

ここにもう1つ、根本的な問題がある。障害対応のセクションで書いた「道の存在を知らなければ、歩き出すことも、誰かに道を聞くこともできない」という話——これがAI時代にはさらに先鋭化する。AIに聞けるのは、道の存在を知っている人間だけだ。 パフォーマンスが遅い。USEメソッドを知っている人間は「CPUのSaturationを確認して」とAIに聞ける。知らない人間は「遅いんですけど」としか言えない。AIは「遅い」から有用な回答を返すこともある。しかし、問いの精度が低ければ、本当に必要な情報にたどり着く確率は下がる。

もっと怖いケースがある。問題の存在自体を認識していない場合だ。テストが通っている。本番も動いている。AIに何も聞かない。問題がないと思っているのだから、聞く理由がない。道があることを知らなければ、地図を広げることすらしない。

だから、AI時代に必要なのは「AIに聞く力」だけではない。「ここに道がある」と気づく力だ。道の存在に気づくためには、自分の足で歩いた経験が要る。歩いたことがある人間だけが、まだ歩いていない方向にも道があるかもしれない、と想像できる。

さらに、見落とされがちなことが2つある。

第一に、AIの出力の質は、使う人間の力量で天井が決まる。

AIが100点の回答を出しても、その領域の理解が浅ければ、100点の回答を100点として受け取れない。40点の回答と区別がつかない。私がKubernetesマニフェストでやらかしたのは、まさにこれだ。

画力のある人間がAI画像生成を使えば、構図・色彩・解剖学的正確さを的確に指示し、選別し、修正できる。画力のない人間は「なんかいい感じ」で止まる。コードも同じだ。型システムを理解している人間がAIにRustを書かせれば、生成されたコードの所有権設計が妥当かどうかを判断できる。理解していない人間は、コンパイルが通ればOKだと思う。

自分で経験した。AIにKubernetesマニフェストを生成させたことがある。出力されたYAMLは文法的に正しかった。デプロイも通った。しかし、resources.limitsが設定されていなかった。本番でOOMKillerに殺されるまで、私は気づかなかった——いや、正確に言えば、AIの出力を読んだとき、resourcesの記述がないことに違和感を持てなかった。Kubernetesのリソース管理を深く理解している人間なら、「limitsがない」ことに即座に気づく。私は当時、その解像度を持っていなかった。AIの出力は正しかった。私の目が足りなかった。

AIは掛け算だ。 基礎力がゼロに近ければ、いくら掛けても結果は小さい。

第二に、AIへの指示の質は言語化能力に依存する。AIは空気を読まない。「いい感じにして」では「いい感じ」の定義が共有されていないから、期待通りにはならない。人間の同僚なら、組織の文脈や過去の経緯から補完してくれる。AIにはそのコンテキストがない。

ここに気づいたとき、私は苦笑した。

AIを使いこなせない人は、実は人間相手のコミュニケーションでも伝わっていなかった可能性がある。人間相手では「察してもらえる」ことに甘えていただけだ。AIは「察する」能力がない分、伝わっていないという事実を可視化しているにすぎない。

言語化能力とは、「なぜそう思うのか」「具体的にはどういう状態か」「何と何の間で迷っているのか」を自分に問い続ける習慣だ。これはAI活用のためだけのスキルではない。思考そのものの精度を上げる訓練でもある。障害対応中に「なんか変だ」と感じたまま言葉にせず、30分後にチームメイトが同じ違和感を言語化して、そこから10分で原因にたどり着いたことがある。私が30分間握りしめていた違和感と、彼が10秒で言語化した仮説は、同じものだった。言語化は正確さの問題であると同時に、速度の問題でもある。

AIに「何を聞くか」を決める力は、どんな訓練で伸びるか。私が実感しているのは、観察→仮説→質問→検証の反復だ。まず、目の前の状況を観察する。次に、「こうなのではないか」という仮説を立てる。仮説を検証するための質問をAIに投げる。返ってきた答えを、自分の仮説と突き合わせる。この4ステップを愚直に回す。仮説なしにAIに聞くと、「いい感じにして」になる。仮説があると、「AとBのどちらが適切か、Cの条件下で比較して」になる。後者の方が、はるかに使える回答が返ってくる。

そしてもう1つ、「自分だけの観点」を独りよがりにしないための条件がある。自分だけの経験で得た視点は、代替不可能だ。しかし、それが他者に伝わらなければ、組織では機能しない。「自分だけの観点」を「チームで使える知見」にするには、4つのステップが要る。言語化(経験を言葉にする)、検証(他の事例でも成り立つか確認する)、物語(なぜそう考えるに至ったかの経緯を語る)、データ(定量的な裏付けを添える)。全部揃わなくてもいい。しかし、言語化だけで止まると「俺の経験では」で終わる。検証とデータが加わると、初めて「組織の知見」になる。

だから「方法を学べ」は、AI時代にこそ意味がある。AIに方法を聞くためではない。方法を通じて自分の目を鍛えるためだ。AIが答えを持っている時代に、問いを立てられる人間でいるために。

おわりに

「課題から入れ」は正しい。正しいが、この原則には暗黙の前提がある。「課題が見えている」という前提だ。見えていない課題を「そこから入れ」とは言えない。

技の名前を知らなければ、負けた理由がわからない。わからなければ、直せない。

だから方法を学ぶ。複数の方法を知る。「深く知ることで、何が見えるようになるか」を意識しながら。方法の探求は、課題の発見につながっている。方法を学ぶことで課題が見え、見えた課題から入る。「課題から入れ」の原則は、方法の学びによって初めて実行可能になる。

と書いて、もう一度立ち止まる。冒頭で「課題から入れ」を批判した。課題が見えない人に「課題から入れ」と言うのは呪いだ、と。しかし、今の私は「方法を学べ」と言おうとしている。方法を学ぶための方法を持たない人に「方法を学べ」と言うのは、同じ構造の再生産ではないか。方法を学ぶ時間がある。本を買える。手を動かす環境がある。それは能力ではなく、環境の話だ。深夜まで障害対応に追われている人間に「本を読め」と言えるか。言えるとしたら、それは方法を持っている側の傲慢かもしれない。この記事自体が、ある種の恵まれた立場から書かれていることを、書きながら思う。それでも書く。書かないよりは、書いた方がいい。たぶん。

1つだけ補足する。怪物を殺す手段は銀の弾丸だけではない。鉛の弾丸もある。特別な知識がなくても、地道に撃ち続ければ怪物は倒れることがある。泥臭い試行錯誤、ひたすらコードを書いて壊して直す繰り返し。華麗ではないが、弾数で勝負する方法だ。金の弾丸もある。売上は全てを癒す。予算があれば人を雇える。技術で解けない問題が、金で解けることはよくある。銀の弾丸、鉛の弾丸、金の弾丸。どれで撃つかを選べること自体が、方法の知識だ。そして、どの弾であれ、撃たなければ怪物は倒せない。

明日からできることを書く。自分が「仕方ない」と思っているものを3つ書き出す。「毎週のレポートに5時間かかる」「チーム間の調整が遅い」「コードレビューが滞る」何でもいい。「仕方ない」と思っている時点で、そこには方法の知識が足りていない可能性がある。その領域で自分が知っている解決アプローチがいくつあるか数える。1つなら、2つ目を探す。2つなら、3つ目を探す。3つ以上あるなら、別の「仕方ない」に移る。注意点がある。同じ前提を持つ方法を3つ知っても視野は広がらない。前提の異なる方法を選ぶことで、初めてメタ視点が生まれる。

「仕方ない」は、方法を知らないサインだ。 そこに、学ぶべき方法がある。

エディタには、いつの間にか文章が並んでいた。最初の一行が出てこなかったはずなのに、気がつけばここまで書いている。あの日の私が知りたかったのは、「課題の見つけ方」ではなかった。「見つけるための道具」だったのだ。問いの立て方が間違っていた。たぶん、ずっと間違えていた。間違えていることを、わかりたくなかったのかもしれない。わからないことにしておいた方が、楽だったのかもしれない。

「課題って、どうやって見つけるんですか」。あの問いへの答えを、ようやく書ける気がする。方法を学べ。そうすれば、課題の方からお前に見えてくる。

おい、方法を学べ。