じゃあ、おうちで学べる

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

システムを作る人がまず理解すべきシステム思考の基礎

はじめに

先日、若いエンジニアと話をしていて、システム思考について話題になった。「物事を個別に捉えるのではなく、全体の関係性や相互作用を理解する考え方」—これがシステム思考の本質だ。僕は彼に、これはどんな分野でも応用できる基本的な教養だと伝えた。特にシステムを構築する立場の人には重要だけど、そうでなくても持っておいて損のないスキルだと。

その会話を終えた後、ふと考えた。僕たちエンジニアは日々システムを作っているのに、どれだけ「システムとして」物事を考えているだろうか、と。

あなたは日々、コードを書いている。機能を実装し、バグを修正し、システムを構築している。そして、予想外の挙動に困惑することがあるかもしれない。完璧に動くはずの機能が、別の機能と組み合わせると謎の不具合を起こす。チーム間の連携がうまくいかず、同じ問題が何度も繰り返される。「なぜこんなことが起きるのだろう?」と。

実は、僕たちの多くは「部品を組み立てる」思考法で「生きたシステム」を作ろうとしているのかもしれない。

プラモデルを思い出してほしい。説明書通りにパーツを組み立てれば、完成形は予測できる。壊れたら、その部品だけを交換すれば直る。これが部品思考だ。僕たちはプログラミングを学ぶとき、まずこの思考法を身につける。関数を書き、クラスを設計し、モジュールを組み合わせる。入力に対して出力が決まっている、予測可能な世界。

しかし、実際のソフトウェアシステムは、プラモデルというより生態系に近い。池に石を投げると波紋が広がり、その波紋が岸に反射し、さらに複雑な模様を作る。一匹の魚が動けば、水流が変わり、他の魚の行動も変わる。すべてが相互に影響し合い、予測困難な振る舞いを見せる。

現代のソフトウェア開発は、まさにこの生態系を扱う仕事だ。マイクロサービス、API連携、非同期処理、分散システム。個々の部品の品質だけでなく、それらの相互作用が全体の振る舞いを決める世界なのだ。

この記事では、システム思考とは何か、なぜそれが新人エンジニアにとって不可欠なのかを解説したい。完璧な理論ではなく、あなたの日常の開発体験を変える実践的な視点を提供できればと思う。

システム思考は難しく聞こえるかもしれないが、今日から始められる小さな習慣がある。まず、バグが発生したらすぐに修正するのではなく、立ち止まって考えてみる。「このバグ、前にも似たようなことがあったな」という違和感。「なぜかこの機能だけいつも問題が起きる」という引っかかり。この違和感に気づく習慣が、システム思考の第一歩だ。そして、一つの視点だけでなく、多角的に問いかけてみる。技術的な問題だろうか?それとも仕様の理解が曖昧だったのか?チームのコミュニケーションに課題があったのか?こうした多面的な視点が、出来事の背後にあるパターンや構造を浮かび上がらせる。

次に、コードを変更する前に、紙やホワイトボードに簡単な図を描く習慣をつける。「このファイルを変更すると、どのモジュールに影響するか?」「どのチームが関係するか?」「どのユーザー機能に影響するか?」。最初は5分で構わない。これを習慣にすることで、システム全体を見る視点が養われる。

そして、PRの説明文に「何を」変更したかだけでなく、「なぜ」その実装を選んだのか、他にどんな選択肢があったのか、何を考慮したのかを書く。これはレビュアーのためだけでなく、3ヶ月後の自分のためでもある。システムの背景や意図が言語化され、チーム全体の理解が深まる。

これらは特別なツールも会議も不要だ。明日のコーディングから始められる。小さな実践の積み重ねが、やがてシステム思考を自然な習慣に変えていく。

このブログが良ければ読者になったり、nwiizoのXやGithubをフォローしてくれると嬉しいです。では、早速はじめていきます。

線形思考の限界

「このコードを書けば、この結果が得られる」「この設計にすれば、このパフォーマンスが出る」「この人数を投入すれば、この期日に間に合う」

こんな風に考えたことはありませんか? これが線形思考です。

私たちは線形思考を教えられてきました。予測可能で、合理的で、再現可能で、手続き的で、二元論的で、トップダウンで、制御に関心を持つ思考。「if this, then that」の因果関係に支配された思考で、ソフトウェアシステムがすべての状況において、私たちが意図したとおりに正確に動作することを期待します。

しかし、実際のシステムは生態系のように振る舞います。単純な原因と結果の連鎖ではなく、複雑な相互作用の網の目なのです。

あるAPIの応答速度を改善したら、別のサービスに負荷が集中してシステム全体のパフォーマンスが悪化した。キャッシュを導入したら、データの整合性問題が頻発するようになった。こんな経験はないでしょうか? これらは、システムの非線形性を示す典型的な例です。

非線形ということの最も単純な形は、システムは完全には制御できず、予測不可能だということです。部分間の関係が、何が起こるかに影響を与えるのです。一つの変更が、思わぬ波及効果を生み出し、それがさらに別の効果を引き起こす。この連鎖は、事前に完全に予測することはできません。

そして、この非線形性を理解し、それと共に働く方法を学ぶこと。それがシステム思考への第一歩なのです。

システム思考とは何か

システムとは何でしょうか? それは単なる「複雑なソフトウェア」ではありません。

システムとは、共有された目的に奉仕するために相互作用し、相互依存する、相互関連したハードウェア、ソフトウェア、人々、組織、その他の要素のグループです。あなたが開発しているWebアプリケーションも、それを使うユーザーも、運用チームも、ビジネス要求も、すべてが一つのシステムを構成しているのです。

そしてシステム思考とは、「一緒に実践すると非線形思考スキルを向上させる、基礎的な思考実践のシステム」です。これは知識ではなく、実践なのです。

テニスについての本を読んでもテニスはできるようになりません。外に出てテニスをプレイする必要があります。システム思考も同じです。概念を理解するだけでなく、日々の開発の中で実践し、体得していく必要があるのです。

AIがもたらすことをシステム思考で理解する

システム思考が実際にどう役立つのか、今まさに起きている事例で見てみよう。AIによるコード生成だ。この新しい技術は、一見すると開発を加速させる魔法のツールに見える。しかし、システム思考の視点で深く掘り下げると、そこには三つの重要な非対称性が潜んでいることが見えてくる。

第一の非対称性:生産と理解の乖離

AIがコードを書くようになって、開発速度は確かに上がった。数分で数百行のコードが生成される。しかし、そのコードを修正しようとした時、予想以上に時間がかかることに気づいた人も多いだろう。

これは非線形性の典型例だ。「生産速度を上げれば開発が速くなる」という線形思考は、一見正しく見える。しかし実際のシステムでは、コードを安全に変更するには、まずそのコードを理解する必要がある。システム内にコードが流入する速度と、人間がそれを理解する速度の間に、決定的な非対称性が生まれているのだ。

氷山モデルで分析してみよう。表面に見えているのは「AIで開発が速くなった」という出来事だ。しかしその下には、「変更に時間がかかるようになった」というパターンがある。さらにその下には、「生成速度と理解速度の不均衡」という構造がある。そして最も深い層には、「速さこそが価値」「生産量で生産性を測る」というメンタルモデル(考え方の前提)がある。

第二の非対称性:生産量と成長の乖離

しかし、問題の本質はさらに深いところにある。生産量とエンジニアとしての地力の成長の非対称性—これこそが、長期的に見て最も深刻な問題だ。

AIを使えば、経験1年目のエンジニアでも、大量のコードを生産できる。PRの数も増え、機能の実装スピードも上がる。しかし半年後、1年後、その人のエンジニアとしての地力はどうなっているだろうか?

問題を自分で分析し、設計を考え、トレードオフを検討するプロセス—これこそが、エンジニアの地力を育てる。しかしAIに頼りすぎると、この思考プロセスそのものを外部化してしまう。「どう実装するか」をAIに聞き、「なぜその設計なのか」を考えずに進める。短期的には生産的だが、長期的には考える力が育たない。

同じく氷山モデルで分析すると、表面の出来事は「仕事量は増えている」だ。しかしパターンを見ると「似た問題に何度も遭遇し、毎回AIに頼っている」「自力で解決できる問題の範囲が広がらない」という現象が浮かび上がる。構造を掘り下げると「思考プロセスの外部化による成長機会の喪失」が見える。そして根底には「アウトプットの量こそが成果」「速く結果を出すことが全て」というメンタルモデルがある。

これは特に新人エンジニアにとって危険だ。経験年数は増えても、地力は停滞する。仕事量と本当の力が比例しないというシステムの非線形性が、キャリアの基盤を蝕んでいく。3年後、5年後に「AIなしでは何もできない」状態になっている可能性がある。

第三の非対称性:経験の量と学びの質の乖離

ここまで読んで、反論したくなった人もいるだろう。「AIを使うこと自体がスキルではないか? AIをうまく使えるようになることが、現代のエンジニアに求められているのでは?」

確かにその通りだ。AIを効果的に使うには、適切なプロンプトを書く力、生成されたコードの良し悪しを判断する力、AIの限界を理解する力が必要だ。AIを使えば使うほど、AIを使うスキルは向上する。これも事実だ。

しかし、ここにも非線形性が潜んでいる。問題は何の力が伸びているかだ。AIとの対話がうまくなることと、ソフトウェア設計がうまくなることは、別のスキルだ。プロンプトを洗練させることと、アルゴリズムを理解することは、別の能力だ。AIの出力を評価できることと、自分で最適な解を導き出せることは、別の次元の話だ。

そして、より本質的な問いがある。「何を経験したか」ではなく、「そこから何を学んだか」が重要なのだ。

毎日AIを使って100行のコードを書く経験を1年積んだとしよう。しかし、そこから「AIへの依存」しか学ばなければ、その経験はエンジニアとしての地力にはつながらない。一方、週に1回しかAIを使わなくても、「なぜAIはこのアプローチを提案したのか」「他にどんな選択肢があったか」「この設計の背後にある原則は何か」を考えながら使えば、その経験は深い学びになる。

システム思考では、これを学習のフィードバックループと呼ぶ。経験(Experience)→ 振り返り(Reflection)→ 学び(Learning)→ 実践(Practice)→ 経験、というサイクルだ。このループが回っているか、それとも単に経験を積み重ねているだけか。この違いが、長期的な成長を決定する。

AIを大量に使っているのに成長しない人は、経験だけが積み上がり、振り返りと学びのステップが欠けている。一方、AIを適度に使いながら成長する人は、このループを意識的に回している。「今、自分は何を学んでいるか?」というメタ認知が、すべての違いを生む。

たとえば、AIに複雑なアルゴリズムを実装させたとしよう。成長しない使い方は「動いた、完了」で終わる。成長する使い方は、生成されたコードを見て「なぜこの時間計算量なのか?」「なぜこのデータ構造を選んだのか?」「もっと効率的な方法はないか?」と問いかける。そして、自分でも実装してみて、AIの提案と比較する。この意図的な学習プロセスがあるかないかで、同じAI利用経験が、まったく異なる成長につながる。

三つの非対称性が示すもの

AIがもたらしたのは、三つの相互に関連した非対称性だ。生産と理解の非対称性、生産量と成長の非対称性、そして経験の量と学びの質の非対称性。これらは別々の問題ではなく、一つのシステムとして機能している。速く書けることを追求すれば、理解が追いつかなくなる。理解しないまま大量に生産すれば、思考力が育たない。そして経験を積んでも、そこから学ばなければ、成長は起きない。

システム思考が教えてくれるのは、これらの問題を個別に対処しても意味がないということだ。根底にあるメンタルモデル—「速さが価値」「量が成果」「経験が成長」—を変えない限り、どんな対症療法も一時的な効果しか生まない。必要なのは、システム全体を理解し、深い層から変革することなのだ。

どこに介入すれば効果的か

この構造を変えずに、出来事のレベルだけで対処しようとすると問題は悪化する。「変更に時間がかかる?ではAIにもっと変更させよう」という対応は、理解されないコードをさらに増やすだけだ。

では、どこに介入すれば効果的だろうか。システム思考では、レバレッジポイント—小さな変更で大きな影響を与えられる場所—を見つけることが重要だ。

最も深い層であるメンタルモデルを変革することが、第一のレバレッジポイントだ。「速く書けることが価値」から「理解できることが価値」へ。「大量に生産することが成長」から「深く考えることが成長」へ。そして「多くを経験することが成長」から「経験から学ぶことが成長」へ。チームで「このコードを6ヶ月後の自分たちは理解できるか」という基準を共有する。生産性の測定も、コード行数ではなく、「変更可能性」で評価する。個人の評価も、「何本PRを出したか」ではなく、「どれだけ難しい問題を自力で解決したか」「どれだけ設計の理解が深まったか」を重視する。この転換がなければ、どんな対症療法も一時的な効果しか生まない。

次に、フィードバックループを設計し直すことが効果的だ。具体的には、AIが生成したコードには「なぜこのアプローチを選んだか」を必ず追記する。コードレビューでは「このコードは理解できるか」を明示的にチェック項目に入れる。PRの説明文に「3ヶ月後の自分が読んで理解できるか」を自問する。そして重要なのは、「このコードを自分で書けるだけの理解があるか」「今日、AIを使って何を学んだか」を自問することだ。AIの提案を鵜呑みにせず、なぜそのアプローチなのか、他にどんな選択肢があったのかを考える。毎日の終わりに5分、「今日AIに任せた部分で、理解が曖昧なところはどこか」を振り返る。これらの小さな習慣が、経験を学びに変換し、チーム全体の理解を促進し、個人の成長を加速させる。

そして、適切な制約を設けることも重要だ。プロトタイピングではAIを積極的に使い、本実装では人間が設計してから使う。AIが生成したコードは、必ず一度すべて読んでから取り込む。週に一度、「今週AIに生成させたコードで理解が曖昧な部分」をチームで確認する。さらに、意図的にAIを使わない時間を設けることも効果的だ。難しい問題に遭遇したとき、まず30分は自分で考える。設計の選択肢を自分でリストアップしてから、AIの意見を参考にする。週に一度は、AIなしで機能を実装してみる。無制限にAIを使うのではなく、こうした制約がシステム全体の健全性と、個人の成長を両立させる。

新人エンジニアのあなたに伝えたいのは、AIを使うこと自体が問題なのではないということだ。問題は、生産と理解の非対称性を無視することであり、さらに言えば、生産量とエンジニアとしての地力の成長の非対称性を無視することだ。そして、経験の量と学びの質を混同することだ。あなたがAIを使ってコードを書くとき、「このコードを3ヶ月後の自分は理解できるだろうか」「チームの他のメンバーは理解できるだろうか」と問いかけてみてほしい。そして同時に、「今、自分は本当に考えているだろうか」「このプロセスで自分は何を学んでいるだろうか」「今日の経験から、明日使える原則を抽出できているだろうか」と問いかけてほしい。速く書けることと、持続可能なシステムを作ることは、別の話なのだ。そして、たくさん作ることと、エンジニアとして成長することも、別の話なのだ。さらに言えば、たくさん経験することと、深く学ぶことも、別の話なのだ。

概念的完全性

フレッド・ブルックスは『人月の神話』で「概念的完全性はシステム設計において最も重要な考慮事項である」というようなことを言っている。

でも、概念的完全性って何でしょうか?

簡単に言えば、システム全体が一つの統一された設計思想で貫かれている状態です。ここで言う「概念」とは、アイデアが形を成し、明確な意味を持つようになったもの。「オブジェクト指向」「非同期処理」といった、定義可能な考え方のことです。

例えば、Unixには「すべてはファイル」という設計思想があります。デバイスも、プロセス間通信も、ネットワーク接続も、すべてファイルとして扱う。この一貫した思想があるから、cat、grep、sedといったシンプルなコマンドを組み合わせて、複雑な処理ができるのです。

逆に、概念的完全性が欠如したシステムはどうなるでしょうか?

あるAPIエンドポイントはRESTful、別のエンドポイントはRPC風。あるデータはJSON、別のデータはXML。エラーハンドリングも、ある部分は例外を投げ、別の部分はエラーコードを返す。多くの良いアイデアが、調整されずにバラバラに実装されている状態です。

新人エンジニアのあなたも、こんなコードベースに遭遇したことがあるかもしれません。「なぜこんなにやり方がバラバラなの?」と困惑した経験があるでしょう。それは、概念的完全性が失われた結果なのです。

概念的完全性を保つには、「このシステムの核となる考え方は何か」を常に問い続ける必要があります。新機能を追加するとき、「これは既存の設計思想と一致しているか」を確認する。もし一致しないなら、設計思想を進化させるか、別のアプローチを考える必要があります。

例えば、「すべての操作を非同期で処理する」という設計思想があるシステムに、同期的な処理を追加すると、概念的完全性が崩れます。しかし、「ユーザー体験を最優先する」という、より高次の設計思想があれば、「即座にフィードバックが必要な操作は同期、それ以外は非同期」という一貫した判断基準が生まれます。

概念的完全性は、システムを理解しやすく、保守しやすく、拡張しやすくするのです。

関係性が効果を生む

ドネラ・メドウズはシステム思考を「部分が一緒になって、各部分が単独で生み出す効果とは異なる効果を生み出すこと」と定義しています。関係性が効果を生み出すのです。

マイクロサービスアーキテクチャを考えてみてください。個々のサービスは完璧に動作していても、それらの間の通信パターン、データの流れ、障害の伝播の仕方によって、システム全体の振る舞いは大きく変わります。

具体例を見てみましょう。あなたのチームがECサイトを開発しているとします。「商品検索」「カート」「決済」の3つのサービスがあり、それぞれは単独で問題なく動作します。しかし、セール時に検索サービスへのアクセスが急増すると、その負荷がカートサービスに波及し、最終的に決済が遅延する。サービス間の「関係性」が、予期せぬ障害を生み出したのです。

重要なのは、ソフトウェアシステムが技術だけでなく人も含むということです。コードだけがシステムではありません。それを書く開発者、使うユーザー、運用するチーム、すべてがシステムの一部なのです。

「コンウェイの法則」を聞いたことがあるでしょうか?「システムを設計する組織は、その組織のコミュニケーション構造をコピーした設計を生み出す」というものです。これは非常に興味深い法則です。

例えば、フロントエンドチームとバックエンドチームが別の場所にいて、週1回しか会議をしない組織では、API設計がきっちり固められ、変更しにくいものになりがちです。一方、同じ部屋で毎日顔を合わせるチームでは、より柔軟で変更しやすいインターフェースが生まれやすい。組織の構造が、そのままシステムの構造に反映されるのです。

だから、「技術的負債を解消する」だけでは不十分です。「なぜその負債が生まれたか」という組織的・文化的な要因も同時に扱う必要があります。技術システムと人のシステムは、切り離せない一つの全体なのです。

反直感性

「このプロジェクトは遅れている。もっと人を投入しよう」

これは理にかなっているように聞こえます。しかし、ブルックスの法則は「遅れているソフトウェアプロジェクトに人員を追加すると、さらに遅れる」と教えています。

なぜでしょうか?

反直感性とは、直感的に正しいと思える解決策が、実際には問題を悪化させる現象です。システム思考において、これは最も重要な概念の一つです。

人を増やすと生産性が上がる、これは工場のライン作業なら正しいかもしれません。しかし、ソフトウェア開発では違います。新メンバーの教育コスト、コミュニケーションパスの増加(n人なら n(n-1)/2 の組み合わせ)、意思決定の複雑化。これらの隠れたコストが、追加された人員の生産性を上回ってしまうのです。

日本の開発現場でもよく見る例があります。「品質が悪いからテストを増やそう」。しかし、無意味なテストが増えるだけで、本質的な品質は改善しない。むしろ、テストのメンテナンスコストが増大し、開発速度が低下する。

「ドキュメントが足りないから、すべてを文書化しよう」。結果、誰も読まない膨大なドキュメントが生まれ、更新されずに陳腐化し、かえって混乱を招く。

これらはすべて、システムの一部だけを見て、全体の相互作用を考慮しなかった結果です。

反直感性を理解するには、「この解決策を実施したら、他の部分にどんな影響があるか」を考える必要があります。そして多くの場合、真の解決策は、問題とは違う場所にあるのです。

品質が悪いなら、テストを増やすのではなく、設計を見直す。ドキュメントが足りないなら、全てを文書化するのではなく、コードを自己文書化する。プロジェクトが遅れているなら、人を増やすのではなく、スコープを削減する。

直感に反する解決策こそが、しばしば最も効果的なのです。

氷山モデル

バグが発生しました。修正しました。同じようなバグがまた発生しました。また修正しました。

こんなサイクルを繰り返していませんか?

氷山モデルは、出来事の表面下にある根本的な原因を探るためのツールです。氷山の一角だけを見ていては、本当の問題は解決できません。

氷山モデルは4つの層から成ります。最も表面にあるのが「出来事(Events)」—目に見える現象です。例えば「本番環境でNullPointerExceptionが発生した」という具体的な問題がこれにあたります。

その下にあるのが「パターン(Patterns)」—繰り返される傾向です。例えば「毎週金曜日のリリース後に、似たようなエラーが発生している」という規則性に気づいたら、それは単なる偶然ではなく、システムが生み出しているパターンかもしれません。

さらに深い層にあるのが「構造(Structure)」—パターンを生む仕組みです。例えば「金曜日は全員がリリースを急ぐため、レビューが形骸化している。テスト環境と本番環境のデータに差がある」といった、システムの要素がどのように配置され、関係しているかの枠組みがこれにあたります。

そして最も深い層にあるのが「メンタルモデル(Mental Models)」—根底にある考え方です。例えば「週末前には必ずリリースしなければならない」「テストで動けば本番でも動くはず」といった、チームが無意識に共有している前提や信念です。

多くの場合、私たちは出来事のレベルで対応します。バグを修正して終わり。しかし、それでは同じ問題が繰り返されます。本当の解決は、より深い層にアプローチすることです。

具体的な使い方を見てみましょう。あなたのチームで「デプロイ後に障害が頻発する」という問題があったとします。出来事として見えているのは「今週も本番でエラーが起きた」ということ。しかし過去3ヶ月を振り返ると、毎月第2週の金曜に障害が起きているというパターンが見えてきます。さらに掘り下げると、第2週は月次リリースと重なり、テストが不十分なまま本番投入しているという構造が見えてきます。そして最も深い層には、「月次リリースは絶対に守るべき」「遅らせることは失敗」というメンタルモデルが潜んでいます。

この場合、構造やメンタルモデルを変えない限り、問題は繰り返されます。解決策は、リリースプロセスを改善する(構造の変更)、あるいは「品質を犠牲にしてまで月次リリースを守る必要はない」という考え方を共有する(メンタルモデルの変更)ことかもしれません。

新人エンジニアのあなたにできることは、出来事の背後にある深い層を探ることです。単に「どう直すか」だけでなく、各層を意識しながら掘り下げるのです。これが、はじめに紹介した「違和感に気づく習慣」の深い意味です。「このバグ、前にも似たようなことがあったな」という違和感から、パターンを見つける。「なぜこのパターンが繰り返されるのか」と考えることで、構造が見えてくる。そして「私たちは何を当たり前だと思っているのか」と問うことで、メンタルモデルに気づく。この階層的な分析が、システム思考の核心なのです。

まとめ

ここまで、システム思考の基礎的な概念を見てきました。線形思考の限界、非線形性、関係性、反直感性、氷山モデル—これらは、システムを「生態系」として理解するための基本的な視点です。

重要なのは、これらが単なる理論ではなく、日々の開発で使える実践的な道具だということです。バグに遭遇したとき、氷山モデルを思い出す。新機能を設計するとき、関係性を考える。直感的な解決策を思いついたとき、反直感性を疑ってみる。

プラモデルのように部品を組み立てるのではなく、生態系のように全体の相互作用を設計する。完全な制御を求めるのではなく、システムと調和し、共に進化していく。これがシステム思考の本質です。

次は、この基礎知識をもとに、具体的にどうシステム思考を日々の開発に取り入れていくかを見ていきましょう。自己認識、問いの立て方、フィードバックループの設計、パターンの見つけ方—明日から使える実践的な方法があります。

基礎を理解したあなたは、もう準備ができています。

syu-m-5151.hatenablog.com