この記事の内容
オブジェクト指向ってわかるようでわかんない!それは、もしかしたらオブジェクト指向の世界に生物を持ち込んでいるからなのかもしれない... ウギャー
むかし携わった現場で、半年以上コードと睨めっこしてもシステム全体のイメージが掴めないことがありました。必要のないコードやモジュールが大量に入り混じり、いろんなコードが癒着して、もはやイメージなど出来ないのでは?と思わせるスパゲッティ状態でした。
このような、イメージできないシステムの保守は、全体像に目をつむって永遠とツギハギを繰り返すしかありません。
「数学はイメージが大切」と言われますが、プログラミングも同様システムをイメージできることが大切。イメージしやすければ、システムの保守管理は容易なものとなります。
そんな苦痛を伴った現場でしたが、逆にものすごくイメージしやすい現場に携わったこともあります。とてもわかりやすく、コードを読まなくてもディレクトリ名とファイル名を見るだけで全体がイメージできました。
オブジェクト指向の世界をイメージできるようになれば、プログラミングが楽になります。
この記事は「オブジェクト指向と10年戦ってわかったこと」を書いた筆者が、オブジェクト指向の世界をわかりやすくイメージするための方法をまとめたものです。
オブジェクト指向はSFの世界
長い間、僕はオブジェクト指向に疑問を抱いていました。「オブジェクト指向は現実世界をそのままソフトウェアに表現する」と言われるけれど、継承による機能受継ぎって現実世界ではどういう現象なんだろう?
僕たちの住む現実世界で量産するには時間がかかるけど、コンピュータの世界でコピーは一瞬だ。遠くにモノを運ぶときは、ダンボールに詰めてトラックで運んでもらう必要もないし、いらなくなったものは初めから無かったみたいに消せる。
こんなに現実とコンピュータの世界に差があるのに、いったい何が「オブジェクト指向は現実世界をそのままソフトウェアに表現する」なんだろう。
僕がオブジェクト指向を学んで3年目に気がついたことは、オブジェクト指向の世界は四次元ポケットが存在するSFの世界だということでした。
現実世界で何か作ろうとした時、途中で釘が足りないことに気がついて制作を断念させられることがあります。これは、現実世界は何が何処にどれだけあるのかの影響度を強く受けるということです。
しかしコンピュータの世界では、好きなものを好きな時に好きなだけ取り出せるので、このようなことは起こりません。むしろコンピュータの世界は選択肢が多すぎて何を使うかで悩む贅沢っぷりです。
ドラえもんも緊急事態で「あれでもない、これでもない」とポケットの中から何の道具を使うか悩むことがあるように、我々プログラマも何のモジュールを使うか、どのフレームワークを使うのかといったことで「あれでもない、これでもない」と悩みます。
実は、オブジェクト指向の世界は映画のようなSFの世界が舞台となっているんです。
このことに気がついたとき、僕は「オブジェクト指向は現実世界をそのままソフトウェアに表現する」はちょっと違うんじゃないか?と考え始めるようになりました。
そんな疑問を抱きながら、10年以上費やして僕はオブジェクト指向の理解を深めていきました。そして、オブジェクト指向の学習の妨げになる概念があることに気がついたのです!
オブジェクト指向の世界観
オブジェクト指向の世界観はSFです。好きなものを好きな時に好きなだけ取り出せるわけですから、道具を無くして慌てるドラえもんの世界よりも優れた未来をイメージしてください。
どうしてこんなSFの世界観になってしまうのか、それはコンピュータの世界では全てがホログラムのような存在であり、モノが空間を超えることが普通のことだからです。
コンピュータの世界をイメージする一番手っ取り早い方法は、文字通りコンピュータが作成したイメージを思い浮かべること。つまりコンピュータグラフィックスの世界をイメージすることです。
きっとゲームでコースから外れたキャラクターがリスポーンされたり、アイテムが突然出現したり、瞬間移動したりするのをみた事があると思います。
コンピュータの世界には物理的な現象が無く、重力はおろか時間もありません。ゲームで時間や重力を体験できるのは、コンピュータの世界にそれが構築されているからです。ゲームはスタートボタンを押せば、いつでも時間が止まります。
現実に存在するものがコンピュータの世界に存在しないように、コンピュータの世界にしか存在しないものがたくさんあります。
例えば、コンピュータの世界は、ひとつのものを複数で所有する事ができます。1着しかない洋服をみんなで同時に着るなんてことは現実世界では到底考えられませんが、コンピュータの世界ではそれができるし、そういうことはよくやります。
これは複製とはちがいます。実体はひとつしかありませんので、誰かが洋服を引っ掛けて破くようなことがあると、みんなの服が同時にビリビリっと破れてしまいます。
そうです!これはポインタの話です。インスタンスのアドレスを様々なオブジェクトが参照して利用する事ができます。
複製が一瞬だったり、壁をすり抜けたり、瞬間移動したり、コンピュータの世界は独特な世界観を構築していますが、ここで注意してほしい特徴があります。
それは、 コンピュータの世界には生命がいないということです。
僕がオブジェクト指向の感覚を掴む前、参考書に「オブジェクト指向は現実世界をそのままソフトウェアに表現する」と書いてあったので、DogやCat、Animalクラスのインスタンスを試しに作ったりしました。
僕はそんな行為を現実世界に当てはめ「神様になって動物を創ったぞ!」と思ってしまったのです。
しかし、プログラミングの本質は「モノづくり」。モノづくりとは工作のことであり、パーツやカラクリの作成を意味する。人は工作によって犬や猫のような生命を生み出すことはできなかったのです。
僕が実際に作ったのはおもちゃの犬と猫でした。それなのに僕は「神様になってコンピュータの世界に動物を創った!」と誤ったイメージをしてしまい、そのためにオブジェクト指向がなかなか理解できない罠にハマってしまったのです。
なぜオブジェクト指向に生命を持ち込むと混乱してしまうのでしょうか。
そもそも生命とは何か
生命と生命でないものの区別とは一体どこにあるのでしょうか?一般的に動物は生物と呼ばれ、土や石のような動かないモノは物質と呼ばれています。
また、僕たちは生きているけれど、僕たちのカラダ自体は「肉体」という名の物質です。
となると、生命とは一体なんでしょう?
それは「観測」「思考」「実行」の3つのサイクルで「物質に影響をもたらす物質」です。
このサイクルを持ち合わせているものを生命と呼びます。
コンピュータは生きていませんが、どんな物質よりも生命に近い存在と言えるかもしれません。なぜならコンピュータは、生命と同じようにデータを「読取」「変換」「出力」するからです。これは生命特有の3サイクルに限りなく酷似しています。
しかしコンピュータは、人間のようにアルゴリズムを生み出す「思考」を持ち合わせていません。コンピュータはプログラマが想定した通りに動くだけで、それは意識とは程遠いものです。
人は生命を作れませんが、コンピュータは生命に近い存在です。人間とロボットを比較した時、そこには数え切れないほどの様々な違いがありますが、イメージの世界で人間とロボットとはほとんど違いがありません。
そこが大きな落とし穴なのです。
オブジェクト指向に生命を持ち込むと混乱する
当たり前ですが、モノがモノを創ることはありません。人間のような思考できる生物がモノを創ります。
いやいやモノはモノを作るよ!工場とかでいっぱい作ってるじゃん!と思うかもしれませんが、これは効率よくモノを生産するために「モノを作るモノを創った」ということで、根源的にモノを創っているのは人のような生命です。
そんなに複雑になるかな?と思うかもしれませんが、いっけん複雑に思えないところが注意です。
オブジェクト指向の世界はものづくりの世界。すなわちプログラミングは言い方を変えれば「工作」ですが、工作によって人は命を創れません。挑戦し続けられている分野ではありますが、人はまだ命を工作によって創ることができていないようです。
動物や植物、僕たち人間のような生きた生命は神様が作ったもので、その仕組みや仕様は公開されていません。逆に車や冷蔵庫、電子レンジなどは人が工作したもので、その仕組みは人が理解できるものとなっています。
人は子供を産めるから生命は作れるのでは?と思うかもしれません。しかし、子供を作ることは工作ではありませんし、もし工作だったらアレコレいじって理想的な子供を産んだりできはずです。
なら魚の養殖は!?こちらも生命の創造とは違うと思います。養殖は、人が生命誕生のプロセスに介入して生産しているような状態で、工作によって命をゼロから生み出しているわけではありません。
すなわちオブジェクト指向に作れないものを持ち込んでしまうと、混乱が生じてしまうのです。ものづくりの世界に創造できない命を持ち込んでしまうと、自分が作り出したものを正しく認識できなくなってしまいます。
うーん、人工知能の分野で活躍してるんだけどコンピュータに意識がないと言われて黙ってられないな。コンピュータに意識が無いなんてわからないじゃん?そもそも、自分以外のものに意識があるかなんて証明できないよ?
確かにそうかもしれません。人間と人型ロボットはイメージは近いものの相違点が多いと言うお話をさせていただきましたが、生命は人工知能のように高速な計算をしたり、精度の高い記憶をしたり、知能を複製したりすることはできないため、やはり相違していると考えた方が良さそうです。
それに、もし人類がコンピュータに意識を持たせることができたら、おそらくプログラミングの常識が覆えってオブジェクト指向なんかどうでもよくなっちゃうと思います。
作成したDogやCatは、現実世界の生きた犬猫とは異なり、意識がありません。そのため、オブジェクト指向の世界に命があると解釈してしまうと、オブジェクト指向のイメージに混乱が生まれてしまいます。
ジッとしていられない生命
生き物はロボットのように指示が与えられるまで固まってくれたりしません。生命はリアルタイムに動き続けています。心臓の動きもそうですし、精神活動をとっても睡眠中でさえ夢を見たりして絶え間無く活動し続けています。
生命が固まるときは、生命が生命でなくなるときです。生き物はロボットのようにスタンバイしたりしません。子供に「ここでじっとしてなさい!」と言っても言う事を聞かないし、犬に「お座り!」と言っても10分もたないと思います。
逆にオブジェクト指向の世界で作ったDogインスタンスが生きた動物のようにウズウズして勝手に動き出したりするということもありません。もし勝手に動いたら面白いですが、Dogインスタンスは命令を受けるまで死んだようにじっとしています。いえ、もともと生きていないのです!
オブジェクトは指示が与えられるまでスタンバイしてくれます。しかし、生命はスタンバイできないため、オブジェクト指向の世界にジッとしていられない生命を持ちこむと、オブジェクト指向のイメージに混乱が生まれてしまいます。
生命は融通がきく
ジッとしていられない困った生命ですが、逆に生命が得意とすることがあります。
それは、生命は状況を読んで行動できるということです。人間はもちろん、犬でさえご主人の顔色を伺って行動したりします。虫のような小さな生命は人間のように哲学したりしないと思いますが、餌の場所を突き止めて仲間に伝達したり、あらゆる手段を使って逃げたり戦ったりと臨機応変に活動しています。
ロボットは転ぶと起きれなくなったり、例外が発生しているのに状況を判断できずに動き続けたりするけれど、生命は例外が発生すると「変だな」とか「やばいぞ!」といった感情が沸き起こり、適切な対処を取ることができます。
この状況を読むという行動からの中に「メンテナンス」があります。昆虫が自分たちの巣をメンテナンスするように、プログラマもソフトウェアのメンテナンスを行います。プログラムはソフトウェアの異常を検知して伝達することはありますが、自動的に問題点を探して修正してくれたりはしません。例外処理(try...catch)は、プログラマが前もって想定していた例外を処理するだけのことです。
生命は状況を読んで活動できますが、オブジェクトは状況を読んでプログラムしていないことを行ってくれることはありませんので、オブジェクト指向の世界に生命を持ちこむと、オブジェクト指向のイメージに混乱が生まれてしまいます。
生命には明確な規格がない
ロボットのような人が創ったモノはパーツを交換することができたりしますが、生命はパーツを気軽に交換できたりしません。
義手のような交換可能なモノもあります。しかし他人の義手を自分の腕にはめて使ったりすることはできないと思います。オーダーメイドなのです。
昔、人がまだ体の中に何の臓器が入っているかよくわからなかった頃、体を切り開いて中身を確認した人は、きっと認識しやすかったり、手に取りやすかったりといった理由で、臓器に名前をつけました。しかし、臓器に命名したからといってそれが交換可能なパーツになるわけではないのです。
これは生命には交換可能な規格というものが無いということです。もちろん臓器移植ができますので、一切交換できないわけではありませんが、交換できるようには作られいません。
人は利便性や拡張性を向上させる理由で規格を作ります。そしてオブジェクト指向のインターフェースはまさに交換可能なパーツを生み出す規格と言えます。
生命には明確な規格がありませんが、オブジェクトには明確な規格があり、インターフェイスに対してプログラミングすることが重要ですので、オブジェクト指向の世界に明確な規格を持たない生命を持ち込むと、オブジェクト指向のイメージに混乱が生まれてしまいます。
ロボットは出産しない
生命は出産しますが、同じようにインスタンスがインスタンスを生成する設計方法はあまり見かけないものです。
もしも、そのような設計を行った場合、それはインスタンスの出産と考えるより、ロボットがロボットを作ったとイメージした方が自然でしょう。
オブジェクト指向でインスタンスが生成されるプロセスは、よくタイ焼き機を使って解説されることがあります。もしオブジェクトが生命だとしたら、この生成プロセスを解釈が困難になります。現実世界でいろんな形の型にはめてタイ焼を作るみたいに命を生み出す方法なんて聞いたことないです。ちょっとロマンチックですがw
オブジェクト指向ではnewを使ってインスタンスを生成しますが、もしnewが出産だとしたら、メイン関数でnewしたインスタンスは誰が出産したことになるのでしょう?
また、オブジェクト指向ではパーツを組み合わせてオブジェクトを作成することがありますが、これをパーツを作るためにnewする行為を出産に結びつけるのはちょっと奇妙です。
生命は出産しますが、newを出産と考えるとオブジェクト指向のイメージに混乱が生まれてしまいます。
コンストラクタの無い生命
生命は小さな細胞が分裂を繰り返して成長することで誕生しますが、ロボットはパーツを組み立てることで完成します。
コンストラクタはインスタンス生成時に必要なものを渡すことができる機能で、これは工場などでロボット生産をする時にアームなどの必要なパーツを明け渡して作ることに置き換えて考えることができます。しかし、生命誕生の瞬間にパーツを渡す連想をするのは難しいと思います。
精子の中に含まれる遺伝子情報がコンストラクタに渡すパラメータであると考えることができるかもしれませんが、これではオブジェクト指向の世界をわかりやすくイメージをするために置き換えて考えたはずが、遺伝子情報というデータの話に逆戻りしちゃっています。
現実世界はコンピュータ世界のように一瞬にしてものを誕生させることはでず、また一瞬で生み出せたとしても、コンストラクタの概念を生命に紐づける良いアイディアは浮かびそうもありません。そのため、オブジェクト指向にコンストラクタを持たない生命を持ち込むとオブジェクト指向のイメージに混乱が生まれてしまいます。
まとめ
様々な角度からオブジェクト指向に生命を持ち込んではいけない理由を列挙させていただきました。
「オブジェクト指向は現実世界をそのままソフトウェアに表現する」と言われますが、オブジェクト指向の世界は現実でできないことができることが多いのです。
オブジェクト指向を学び始めた時、このことを知らされていないため「なるほどなぁ!オブジェクト指向は現実世界をそのままソフトウェアに表現するのかぁ!」と鵜呑みにして混乱に陥りました。
ソフトウェア設計は複雑です。その複雑性を取り払うには、ソフトウェアの中身をイメージできるようになることが大切です。
オブジェクト指向の世界は「生命のいないSF仮想世界」です。そのため、オブジェクト指向の世界はロボットだけのSF世界であると考えるのが良いかもしれません。
このロボットだけのSF世界は、コンピュータの中に存在する「真のオブジェクト指向の世界」です。我々はテキストエディタを使ってこの世界に唯一の生命として接触できます。
また、この世界はは現実世界とは異なる様々な法則があります。ロボットだけのSF世界は、高速で、モノの大きさの概念が無く、分身を所有でき、生命が存在しません。
この中で最も混乱を招くのが「生命」です。コンピュータが高速であることは知っているし、分身を所有できるということなども、なんとなく感じているはずです。
しかし生命が存在しないという考え方は、オブジェクト指向の説明にDogやCat、Animalを使った解説がなされることが多いので、なかなか気がつくことができません。
きっとこの新しい思考法を使えば、オブジェクト指向の誤解がとけ、オブジェクト指向を全身で感じながらプログラミングできるようになるかもしれません。
この記事に対する貴重な反対意見を@matari様に頂きました!こちらも合わせて読んでいただけると更なるオブジェクト指向の理解が得られると思います!