エンジニアの考え方 #4 - ノードの地図に関係の名前を付けると、オブジェクト指向が始まる
前回描いた連想の地図には、種類の違う線が混ざっています。「〜は〜の一種」「〜は〜を持つ」——関係に名前を付けて整理した地図は、そのままソフトウェア設計の図になる。連想と分類という人間の頭の動きが、オブジェクト指向の直系の祖先だったという話。
前回の地図には、違う種類の線が混ざっている
前回、傘を中心に連想の地図を描きました。広げるだけ広げて、最後に「似たもの同士をまとめたくなる」ところで終わっています。今回はその続き、まとめる側の話です。
あの地図の線を、あらためて1本ずつ見てみます。
- 傘 — ビニール傘:ビニール傘は、傘の一種
- 傘 — 骨組み:骨組みは、傘の一部
- 傘 — レインコート:別のモノだが、「濡れを防ぐ」働きが同じ
- 傘 — 梅雨:傘が使われる場面
広げているときは全部同じ「関係ありそう」の線でした。でも冷静に見ると、つながり方の種類がぜんぶ違う。この違いに気づくことが、今回の入り口です。
関係には、世界共通の名前がある
ソフトウェア設計の世界では、この「線の種類」のうち特に大事な2つに名前が付いています。
- is-a —「AはBの一種である」。ビニール傘 is a 傘。折りたたみ傘 is a 傘
- has-a —「AはBを持っている(Bを一部として含む)」。傘 has a 骨組み。傘 has a 持ち手
たったこれだけ、と思うかもしれませんが、あいまいな「関係ありそう」を「一種なのか、持ち物なのか」と問い直すだけで、地図は急に整理されます。そして経験上、この2つを混ぜたときに設計は壊れます。「一種」と「持ち物」は似て非なるものです。
「働きが同じ」仲間をくくると、上位の概念が生まれる
もう1つ、面白い線がありました。傘とレインコートと長靴。互いに一種でも持ち物でもないのに、仲間に見える。「要するに?」と一段上ると、共通の働きが抜き出せます——要するに、どれも雨具。
graph BT
A[傘] --> U["雨具(要するに=共通の形)"]
B[レインコート] --> U
C[長靴] --> U
ここで起きたことに注目してください。「雨具」というノードは、元の地図にはありませんでした。具体たちの共通部分を抜き出して、上位の概念を自分で作ったのです。設計の言葉ではこれを汎化と呼びます。第2回でやった上り(要するに?)を、地図の上で目に見える形にやったものが汎化で、下り(たとえば?)は上位ノードから具体を生やす操作にあたります。連想の地図に、抽象度という縦方向が生まれた瞬間です。
この地図は、オブジェクト指向の祖先だった
ここまで、プログラミングの話を一切せずにやってきました。ここで一度、歴史の話をします。
人間の知識を「概念のノードと、is-a / has-a などのリンクの網」として表す研究は、1960年代の認知科学・人工知能の分野に実在します。意味ネットワークと呼ばれるもので、そこから派生したフレーム理論という知識の表し方が、のちに進化して、現在のプログラミングにおけるクラスとオブジェクトになりました。
つまり、オブジェクト指向は数学の公式のように天下りで発明されたものではなく、人間の連想と分類のしかたを、プログラムの構造として写し取ったものなのです。連想の地図が描けて、線の種類を問い直せて、共通の形をくくり出せる——それができる人は、オブジェクト指向の入り口にもう立っています。クラスは「分類に付けた名前」、継承は「is-a の線」、部品として持つ関係は「has-a の線」。文法は、この地図の書き留め方にすぎません。
実際、設計の現場は「名詞の地図」から始まる
これは比喩ではなく、実務の手順でもあります。オブジェクト指向で設計するとき、定石とされるのは、対象の業務や世界の説明から名詞を拾い出して、概念の地図を描くことです。この地図はドメインモデルやクラス図と呼ばれますが、その実体は「ノード(クラス)と、名前付きの関係(is-a=汎化、has-a=集約など)でできた図」。前回描いたマインドマップと材料は同じで、違いは関係に名前を付けて厳密にしたことだけです。
なぜそこまでして地図をコードに写すのか。現実の構造とコードの構造が一致していると、現実の変更がコードの変更に素直に写るからです。新しい種類が増えたら、is-a の枝を1本足す。部品が変わったら、has-a の先を差し替える。どこを直せばいいか、地図が教えてくれる——オブジェクト指向が「変更に強い」と言われる理由の根っこはここにあります。
逆に有名な落とし穴も1つ。is-a が成立していないのに「書くのが楽だから」という理由で継承を使うと、一種でないものが一種として扱われて、あとで必ず壊れます。迷ったら地図に戻って、「これは本当に一種か?」と線を問い直してください。
まとめと次回
- 連想の地図の線には種類がある。「一種(is-a)」「持ち物(has-a)」「働きが同じ」「使う場面」
- 働きが同じ仲間から共通の形を抜き出して上位の概念を作るのが汎化。「要するに?」の上りを地図の上でやったもの
- 意味ネットワーク → フレーム → クラスという実際の系譜がある。オブジェクト指向は、人間の連想と分類の写し
- 設計の現場も名詞の地図から始まる。クラス図とは、関係に名前を付けたマインドマップ
- 地図とコードの構造が一致しているから、変更に強い。is-a でないものを継承でつなぐと壊れる
次回は外伝として、今回入り口まで来たオブジェクト指向の中身——クラス・カプセル化・ポリモーフィズム——を、少しエンジニア寄りに踏み込んで扱います。その後の本編では、第1回で予告した「道具のパズル」——分解した課題に既製の道具をはめていくアーキテクチャの話を書く予定です。
※ 本記事の内容は執筆時点の情報であり、正確性を保証するものではありません。ご利用の際は免責事項をご確認ください。
Series / 連載
エンジニアの考え方
- 01 エンジニアの考え方 #1 - 課題を「分解」するところから
- 02 エンジニアの考え方 #2 - 「要するに?」と「たとえば?」を往復する
- 03 エンジニアの考え方 #3 - 連想をノードでつないで、頭の中を地図にする
- 04 エンジニアの考え方 #4 - ノードの地図に関係の名前を付けると、オブジェクト指向が始まる(この記事)
Related / 関連記事
関連記事
エンジニアの考え方 #3 - 連想をノードでつないで、頭の中を地図にする
思考シリーズ第3回は、考えを頭の外に出す道具の話。中心にテーマを置き、連想したものを枝でつないで放射状に広げていく——マインドマップと呼ばれるこの方法は、思考整理にも自己分析にも効いて、実はプログラミングの設計にまでつながっています。
エンジニアの考え方 #2 - 「要するに?」と「たとえば?」を往復する
思考シリーズ第2回は、分解とセットで効く「具体と抽象の行き来」。例え話のうまい人が頭の中でやっていること、抽象的な指示に手が止まる理由、認識合わせが速くなる2つの質問について。
エンジニアの考え方 #1 - 課題を「分解」するところから
考え方の話をするシリーズの第1回は、すべての土台になる「課題の分解」。ネットが繋がらない日のトラブル対応から、郵便受けの通知の仕組み作りまで、大きすぎる問題を解ける大きさに割る話です。
Comments / コメント