ストーリーテリングなコードを書こう
先日、ある女性プログラマが、
「いまだにオブジェクト指向がよくわからない」と言っていました。
彼女はPHPerですが、最近はもっぱらLaravelでの開発プロジェクトに関わっているので、
普段から実装でオブジェクトを扱っており、オブジェクトの仕様はもちろん理解しています。
でも、「よくわからない」気持ちもよくわかります。
これが正解なのかどうかはよくわかりませんが、
少し考えて、以下のような2つのコードを送ってみました。
「ある男女の生涯を記録する」という仕様を実装した、くだらないコードです。
個人情報保護の都合上、適当なハリウッド夫婦に置き換えていますが、
実際に送ったコードには、彼女とその近親者の名前等が入っていました。
1つめ。
$human_model = new HumanModel();
$working_model = new WorkingModel();
$relation_model = new RelationModel();
$man_data = ['name' => 'Will', 'sex' => HumanModel::MALE, 'birthday' => '1968-09-25'];
$man_id = $human_model->create($man_data);
$working_model->save($man_id, 'Actor');
$working_model->save($man_id, 'MC');
$woman_data = ['name' => 'Jada', 'sex' => HumanModel::FEMALE, 'birthday' => '1971-09-18'];
$woman_id = $human_model->create($woman_data);
$working_model->save($woman_id, 'Actless');
$relation_data = ['man' => $man_id, 'woman' => $woman_id, 'created' => '1994-09-19'];
$relation_id = $relation_model->create($relation_data);
$relation_model->update($relation_id, ['married' => '1997-12-31']);
$child_data = ['name' => 'Jaden', 'sex' => HumanModel::MALE, 'birthday' => '1998-07-08', 'parents' => $relation_id]:
$child_id = $human_model->create($man_data);
$working_model->save($child_id, 'Actor');
$relation_model->update($relation_id, ['expired' => '9999-12-31']);
2つめ。
$man = new Man('Will');
$man->born('1968-09-25');
$man->workAs('Actor');
$man->workAs('MC');
$woman = new Woman('Jada');
$woman->born('1971-09-18');
$woman->workAs('Actless');
$couple = $man->meets($woman, '1994-09-19');
$couple->married('1997-12-31');
$child = $couple->haveBaby('1998-07-08')->asBoy();
$child->named('Jaden');
$child->workAs('Actor');
$couple->forever();
そして訊ねてみました。
「どっちがいい?」
「・・・?」
「」
私が伝えたかったのは、
どっちのコードが読みやすいとか、使いまわしが利くとか、実装が楽とか、
そういう話ではないんです。
圧倒的な「ストーリー感」の差なんです。
前者のコードは、せいぜいこうです。
$human_model = new HumanModel();
$working_model = new WorkingModel();
$relation_model = new RelationModel();
//男のデータを作成
$man_data = ['name' => 'Will', 'sex' => HumanModel::MALE, 'birthday' => '1968-09-25'];
$man_id = $human_model->create($man_data);
$working_model->save($man_id, 'Actor');
$working_model->save($man_id, 'MC');
//女のデータを作成
$woman_data = ['name' => 'Jada', 'sex' => HumanModel::FEMALE, 'birthday' => '1971-09-18'];
$woman_id = $human_model->create($woman_data);
$working_model->save($woman_id, 'Actless');
//男女の関係データを作成
$relation_data = ['man' => $man_id, 'woman' => $woman_id, 'created' => '1994-09-19'];
$relation_id = $relation_model->create($relation_data);
//結婚日を更新
$relation_model->update($relation_id, ['married' => '1997-12-31']);
//子供のデータを作成
$child_data = ['name' => 'Jaden', 'sex' => HumanModel::MALE, 'birthday' => '1998-07-08', 'parents' => $relation_id]:
$child_id = $human_model->create($man_data);
//子供の職業データを更新
$working_model->save($child_id, 'Actor');
//夫婦データを更新
$relation_model->update($relation_id, ['expired' => '9999-12-31']);
後者のコードからは、自然とこんなストーリーが見えてきませんか?
//男の名はウィル。1968年生まれ。俳優・ラッパーとして活動
$man = new Man('Will');
$man->born('1968-09-25');
$man->workAs('Actor');
$man->workAs('MC');
//女の名はジェイダ。1971年生まれ。女優として活動
$woman = new Woman('Jada');
$woman->born('1971-09-18');
$woman->workAs('Actless');
//男は1994年のある日、女と出会った
$couple = $man->meets($woman, '1994-09-19');
//2人は1997年の大晦日に結婚
$couple->married('1997-12-31');
//翌年、2人は男の子を授かり、ジェイデンと名付けた。
$child = $couple->haveBaby('1998-07-08')->asBoy();
$child->named('Jaden');
//子供もまた、俳優になった
$child->workAs('Actor');
//2人はいつまでもおしどり夫婦として幸せに暮らしました
$couple->forever();
男は生まれ、働き、出会ったり結婚したりするものです。
カップルは子供を授かったり、絆を深めたりするものです。
そう、そういう「もの」。
この「もの」こそがオブジェクトですよね。
ストーリーテリングなオブジェクト
前者のコードでは、これらは全て、単なる変数、配列、レコードないしIDでしかありませんでした。
しかし、全ての「もの」には、それぞれ意味や役割があり、行動や変化があります。
その「もの」の種類を1つのクラスとして、
性質や状態をプロパティとして、行動や変化をメソッドとして表現するのが、
オブジェクト指向(志向)の出発点なのではないかなぁ、と。
この思想でコードを書けば、プログラムはとてもストーリーテリングになります。
男が女に出会う、という出来事(処理)が、
$man->meets($woman)
そのまま “man meets woman” と書けるではないですか。
自然と、クラスは主語となり、メソッドは述語となり、引数は目的語となります。
そして、その結果何か(ここではカップル)が生まれるなら、それが戻り値になります。
メリットがよくわからない
もはやオブジェクト指向の話なのかどうかさえ怪しくなってきましたが、
オブジェクト指向にせよ何にせよ、こうした思想がなかなか腑に落ちない方は、
目の前のメリットを求めがちなんじゃないかと思います。
実装が楽になるとか、コードが読みやすくなるとか、使い回しが利くとか。
実装レベルで考えると、
前者のコードの HumanModel, WorkingModel, RelationModel クラスを実装するのと、
後者のコードの Man, Woman, Couple クラスを実装するのとでは、
たぶん前者のほうが圧倒的に楽です。
オブジェクト指向の具体的なメリットを言葉で伝えるのは難しいです。
カプセル化とか多態性とか継承とか、伝えるべきことはたくさんありますが、
腑に落とすためには、めんどくさいコードをたくさん書くしかないと思います。
ただ、そういうコードを書いてみようというモチベーションのひとつとして、
このような、オブジェクトが綴る「ストーリー感」を感じてもらえればいいなと思いました。
Discussion