オブジェクト指向はなぜ生まれたのか —— プログラマたちを救った「考え方」の物語

広告

プログラミングを学んでいると、いつか必ず「オブジェクト指向」という大きな壁に出会います。

class を書いて、private をつけて、インスタンスを作って……。文法は教わったとおりに書けるのに、「で、結局これって何がうれしいの?」という気持ちがずっと残る。そういう人はとても多いです。

実はこれ、あなたのせいではありません。オブジェクト指向は「文法」から学ぶと、いちばん大事な部分が見えなくなるからです。

オブジェクト指向は、ある日天才が思いついた便利な書き方ではありません。何十年もかけて、世界中のプログラマが「もうこのままじゃ無理だ」と追い詰められた末に、たどり着いた苦肉の策です。

だから、本当の意味で腑に落ちるには、彼らが何に困っていたのかを知るのがいちばんの近道なんです。今日はその物語を、最初から順番にたどってみましょう。


第1章 昔、プログラムは「命令の長い行列」だった

コンピュータが生まれたばかりのころ、プログラムというのは、ただひたすら命令を上から順番に並べたものでした。

「この数を足せ」「ここに保存しろ」「もし0だったらここに飛べ」。そういう指示が一行ずつ並んでいる。プログラマの仕事は、コンピュータにやってほしいことを、正しい順番で書き並べることでした。

これは、プログラムが小さいうちは何の問題もありません。あなたが今書いている、数十行のコードを思い浮かべてください。上から下まで全部見渡せて、どこで何をやっているか頭に入っている。とても快適です。

世界も最初はそうでした。プログラムは数百行、せいぜい数千行。一人の頭の中に、全部が収まっていたのです。


第2章 プログラムが大きくなりすぎた日

ところが、コンピュータが世の中の役に立つとわかると、人々はもっと大きな仕事を任せたくなりました。

銀行のシステム、航空機の予約、企業の給与計算。プログラムは数万行、数十万行へと、あっという間に膨れ上がっていきます。

すると、奇妙なことが起こり始めました。

ハードウェアはどんどん速く、安くなっているのに、ソフトウェアだけが完成しない。 予定どおりに動かない。バグが取れない。直したはずの不具合が、別のところで再発する。納期は延び、予算は膨らみ、ついには「もう誰にも全体が把握できないプログラム」が生まれてしまいました。

1968年、世界中の専門家がこの問題を話し合うために集まり、こう名づけました ——「ソフトウェア危機(Software Crisis)」。

危機、です。それくらい深刻だったんです。

では、いったい何が彼らを追い詰めていたのでしょうか。犯人は、意外なところにいました。


第3章 真犯人は「データ」だった

プログラムが大きくなって何がいちばん困るのか。それは「処理(命令)が増えること」ではありませんでした。

本当の犯人は、データがどこからでも自由に書き換えられてしまうことだったのです。

たとえば、簡単なゲームを手続き型(昔ながらの命令を並べる書き方)で作ってみましょう。

// プレイヤーや敵の状態が、そこら中に剥き出しで置いてある
int playerHp = 100;
int playerMp = 50;
int enemyHp  = 80;

void Attack()
{
    enemyHp -= 10;   // 誰でも、どこからでも、勝手に減らせる
}

void Heal()
{
    playerHp += 20;  // HPの上限チェックは……いったい誰がやるの?
}

最初はこれで動きます。ところがプログラムが大きくなり、何十人もの人が関わり、何万行にもなったとき、こんなバグが起きます。

「プレイヤーのHPが、いつのまにか 250 になっている。なんでだ?」

playerHp という変数は、プログラムのどこからでも触れます。だから、HPを書き換えているコードがプログラム中に何十か所もあるかもしれない。回復処理、罠のダメージ、デバッグ用のコード、誰かが昨日追加した謎の処理……。

このうちのどれか一つが「上限チェックを忘れていた」だけで、バグになる。そして、その「どれか」を探し出すのが地獄なのです。

これが、ソフトウェア危機の正体でした。規模が大きくなると、人間の頭は「どのデータを、どこで、誰がいじっているか」を追いきれなくなる。 命令の数ではなく、データの管理に人間の限界が来ていたのです。


第4章 発想の転換 —— 世界を「モノ」として見る

この行き詰まりを破ったのは、まったく違う角度からの発想でした。

時は1960年代、ノルウェー。オルヨハン・ダールとクリステン・ニガードという二人の研究者が、船の航行や交通の流れをシミュレーションするプログラムを作ろうとしていました。

シミュレーションというのは、現実の世界を計算機の中に再現することです。海には何隻もの船がいて、それぞれが自分の速度、自分の積荷、自分の目的地を持って動いている。

ここで彼らは気づきます。

「現実の船は、自分の情報を自分で持っていて、自分で動いているじゃないか。だったらプログラムの中でも、船という"モノ"を一つのまとまりとして表現すればいいのでは?」

つまり、こういうことです。

これまでは「データ(HPや速度)」と「処理(動く・攻撃する)」を、別々の場所にバラバラに置いていました。それを、現実の"モノ"の単位でひとまとめにする

船には船のデータと船の動きを。プレイヤーにはプレイヤーのデータとプレイヤーの行動を。一つの箱に閉じ込めてしまう。

彼らが作った言語は Simula(シミュラ) と呼ばれ、ここで「クラス」と「オブジェクト」という言葉が初めて登場しました。これがオブジェクト指向の出発点です。


第5章 「モノ」に責任を持たせる

この発想を、もう一歩おしすすめた人がいます。アメリカ・ゼロックス社の研究所にいたアラン・ケイです。

彼は「オブジェクト指向(object-oriented)」という言葉を広めた人物で、こんなイメージを持っていました ——生き物の細胞です。

私たちの体は、何十兆もの細胞でできています。一つひとつの細胞は、自分の中身を膜で守っていて、外から勝手に内臓を引きずり出されたりはしません。やり取りするときは、決められた信号(メッセージ)だけを送り合う。

それでいて全体としては、ちゃんと一つの生き物として動いている。

「プログラムもこうあるべきだ」とアラン・ケイは考えました。

つまり、それぞれのオブジェクトが自分のデータを自分で守り、自分に関するルールに責任を持つ。 外からは、決められた窓口を通してしかお願いできない。

この「中身を守る」という考え方を、カプセル化(encapsulation) と呼びます。薬のカプセルのように、大事なものを包んで守るイメージです。

では、第3章のゲームのコードを、この考え方で書き直してみましょう。

public class Player
{
    private int hp = 100;            // 外からは直接さわれない(private)
    private const int MaxHp = 100;

    // HPを増やすときのルールは、Player自身が責任を持つ
    public void Heal(int amount)
    {
        hp += amount;
        if (hp > MaxHp) hp = MaxHp;  // 上限チェックは、ここに一回書けばいい
    }

    public int Hp => hp;             // 外からは「見る」だけ
}

何が変わったか、わかるでしょうか。

hpprivate になり、Playerの外からは一切さわれなくなりました。 HPを変えたければ Heal() を呼ぶしかない。そして上限チェックは Heal() の中に一回だけ書いてあります。

つまり、「HPに関するルールは、Playerクラスの中にしか存在しない」 という状態を作れたのです。

ここでもう一度、第3章のあのバグを思い出してください。「HPが250になっている、原因不明」。

カプセル化された世界では、このバグは起きにくくなります。なぜなら、HPを書き換える方法がたった一つの窓口に限定されているから。探す場所が、プログラム全体から、たった一つのクラスの中に絞られるのです。

これこそが、ソフトウェア危機への答えでした。プログラムが何十万行になっても、「このデータの面倒を見ているのは誰か」がはっきりしていれば、人間はそれを追いかけられる。 オブジェクト指向は、コンピュータのためではなく、人間の頭の限界に合わせて生まれた考え方なんです。


第6章 だから、C#のクラスはこの形をしている

ここまで来ると、いつも丸暗記していた文法が、急に意味を持って見えてきませんか。

  • class ——「データと処理を、一つのモノとしてまとめる箱」。ダールとニガードがシミュレーションのために考えた、あの発想そのものです。
  • private ——「中身を外から守る膜」。アラン・ケイの細胞のイメージ。勝手にさわらせない、という意思表示です。
  • public のメソッド ——「外から使える窓口」。細胞が信号をやり取りするための、決められた入口です。

classprivate は、覚えるべき呪文ではありません。「データを守って、責任の置き場所をはっきりさせたい」という長年の願いが、言語の文法になったものなのです。

その後、ダールたちのSimulaに影響を受けて生まれた C++、その流れをくむ JavaC# へと、この考え方は受け継がれていきました。あなたが今書いているC#のコードは、ソフトウェア危機と戦った人々の知恵の、いちばん新しい姿なのです。


まとめ —— オブジェクト指向は「人間への思いやり」

最後に、いちばん大事なことをお伝えします。

オブジェクト指向は、コンピュータを速くするための技術ではありません。コンピュータは、データがバラバラに置いてあっても平気で動きます。困るのは、いつだってそれを読み書きする人間のほうです。

  • プログラムが大きくなると、人間は全体を把握できなくなる(ソフトウェア危機)
  • 原因は、データがどこからでも書き換えられること(第3章の地獄)
  • だから、データと処理を「モノ」の単位でまとめ(クラス)
  • 中身を守り、責任の在り処をはっきりさせた(カプセル化)

オブジェクト指向とは、つまるところ 「未来の自分や、一緒に働く仲間が、混乱しないように書く」 という、人間どうしの思いやりの技術なのです。

これから class を書くとき、ぜひ自分にこう問いかけてみてください。

「このデータの面倒を見る責任者は、誰だろう?」

その問いに答えられるようになったとき、あなたは文法を覚えただけのプログラマから、オブジェクト指向で"考えられる"プログラマへと変わっています。

その日を、楽しみにしていてください。

訪問数 12 回, 今日の訪問数 12回

広告