システムを作る人がまず理解すべきシステム思考の基礎 – じゃあ、おうちで学べる

はじめに

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

世界はシステムで動く ― いま起きていることの本質をつかむ考え方

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

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

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

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

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

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

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

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

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

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

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

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

線形思考の限界

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

ようこそ!FACT(東京S区第二支部)へ(1) (マンガワンコミックス)

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

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

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

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

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

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

システム思考とは何か

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

実践システム・シンキング 論理思考を超える問題解決のスキル (KS理工学専門書)

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

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

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

生産と理解の非対称性をシステム思考で理解する

システム思考が実際にどう役立つのか、今まさに起きている事例で見てみよう。AIによるコード生成だ。

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

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

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

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

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

最も深い層であるメンタルモデルを変革することが、第一のレバレッジポイントだ。「速く書けることが価値」から「理解できることが価値」へ。チームで「このコードを6ヶ月後の自分たちは理解できるか」という基準を共有する。生産性の測定も、コード行数ではなく、「変更可能性」で評価する。この転換がなければ、どんな対症療法も一時的な効果しか生まない。

次に、フィードバックループを設計し直すことが効果的だ。具体的には、AIが生成したコードには「なぜこのアプローチを選んだか」を必ず追記する。コードレビューでは「このコードは理解できるか」を明示的にチェック項目に入れる。PRの説明文に「3ヶ月後の自分が読んで理解できるか」を自問する。これらの小さな習慣が、チーム全体の理解を促進する。

そして、適切な制約を設けることも重要だ。プロトタイピングではAIを積極的に使い、本実装では人間が設計してから使う。AIが生成したコードは、必ず一度すべて読んでから取り込む。週に一度、「今週AIに生成させたコードで理解が曖昧な部分」をチームで確認する。無制限にAIを使うのではなく、こうした制約がシステム全体の健全性を保つ。

新人エンジニアのあなたに伝えたいのは、AIを使うこと自体が問題なのではないということだ。問題は、生産と理解の非対称性を無視することだ。あなたがAIを使ってコードを書くとき、「このコードを3ヶ月後の自分は理解できるだろうか」「チームの他のメンバーは理解できるだろうか」と問いかけてみてほしい。速く書けることと、持続可能なシステムを作ることは、別の話なのだ。

概念的完全性

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

人月の神話

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

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

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

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

ある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




Source link

関連記事

コメント

この記事へのコメントはありません。