猿でも分かる継承の作法

継承は、新しい機能を追加するだけでなく、既存の機能を差し替えることにより、基本クラスを拡張することができます。具体的には、基本クラスのメソッド(あるいはプロパティ)を派生クラスで再定義して、置き換えるというものです。これは「メソッドオーバーライド(override)」と呼ばれます。

 

これは危険な考え方だ。別に嘘を書いている訳ではないがこのような説明がしばしばトラブルの原因となる。よい継承には作法があるのだ。

例えば警察官というクラスがあったとする。

警察官の仕事はいろいろだ。お巡りさんのような制服警官の仕事はパトロールであり科捜研であれば証拠分析だろう。刑事なら犯人確保。それぞれ仕事の内容は違う。

だが共通点もある。それは「パトロール」という仕事も「証拠分析」という仕事も「犯人確保」という仕事も「町の安全を守る」という仕事の一種である、ということだ。

具体的なコードでかけばこうなる。

class 警察官{

  void 仕事(){町の安全を守る} 👈この仕事が町のパトロールとは限らない

}

class お巡りさん extends 警察官{

  void 仕事(){町のパトロールをする} 👈この仕事は町の安全を守る仕事である

}

class 科捜研の人 extends 警察官{

  void 仕事(){証拠分析をする} 👈この仕事は町の安全を守る仕事である

}

class 刑事さん extends 警察官{

  void 仕事(){犯人を確保する} 👈この仕事は町の安全を守る仕事である

}

これが継承の作法を守った「よい継承」の例である。

では「悪い継承」とは何か。

例を示そう。こんな継承はすべきではない。

class 泥棒 extends 警察官{

  void 仕事(){他人の家に侵入し金品を奪う} 👈この仕事は町の安全を守る仕事ではない

}

できるだけ分かりやすく説明したつもりだが、これではよくわからない、という方もいるだろう。そんな諸君は是非ともメイヤーのオブジェクト指向入門を一読してほしい。

オブジェクト指向入門という本

ここで、オブジェクト指向が禁止なら継承もできないのか、のように、裏返せば継承つかったらオブジェクト指向のような認識であるなら、メイヤーの「オブジェクト指向入門」2冊を隅から隅まで読んで出直すべきだ*1

そこまで云うのであればこの人はその2冊を隅から隅まで読んだのだろうか。
というか、文の意味がよく分からない。継承はオブジェクト指向原語特有の機構である。使い方の善し悪しはあるが、継承を使ったプログラムはみなオブジェクト指向であるというのが私の認識であるからだ。
では継承の善し悪しとは何か。
バートランドメイヤーによればよい継承とは「OCP(開放閉鎖の原則)を守った継承」である。OCPはメイヤーがオブジェクト指向入門で説明しているので詳細をここでは書かない。この本のOCPに関する章を一読してほしい。高価な本なので学生なら大学の図書館で借りてくるのがいいだろう。ボブマーチンがアジャイルソフトウェア開発の原則で説明しているOCPとの違いを確認しながら読んでみると面白い。
 
ただしこの本は入門書とありながら入門書と呼べないほどに難解である。おそらく著者が大学の講義で使っている(た)教科書である。理解するにはある程度の数学知識が必要で、学生の頃に数学が得意ではなかったという方は苦労するだろう。

ラムダについての懸念

JAVAの新機能ラムダ。関数型プログラム到来と絶賛されているが私はこの評価に戸惑いを覚える。そもそもこのラムダは関数型プログラムにパラダイムシフトできる人間だけがそのメリットを教授できる。一介のプログラマが手を出せる代物ではない。だが技術者にとって最先端の技術ほど魅力的なものはない。最先端であればよく分からないままに使ってしまうのが技術者の悪い癖である。

かつてオブジェクト指向に憧れ、パラダイムシフトしないまま手を出したプログラマがどれほど居たことか。そしたそれは、そのまま負の資産となった。彼等の作ったその負の資産は今だに保守担当技術者を苦しめている。

ラムダもその運命を辿るのではないか。また同じ過ちを繰り返さないことを願うばかりだ。

バグとは何か

「仕様と違う結果」が起きる原因をバグと云う。バグはエラーとは異なる概念だ。 
ログイン画面を考えてみよう。 
ユーザーIDとパスワードを正しく入力し、ログインボタンを押すとトップ画面に移る。これは正常系というログインの本来の事象だ。 
これに対し、ユーザーIDかパスワードを間違って入力しログインボタンを押すとエラーとなる。これは異常系というユーザーの想定外の事象である。また
ある事象が異常系である条件は

・エラー画面に遷移する 
・エラーメッセージが出力される 
のどちらか若しくは両方が満たされることと云える。
ではバグとは何か。 
正常系であれ異常系であれ、テストに於いてその事象が設計通りの結果にならない時、そこにはプログラマの想定外の何らかの問題があると云える。この問題をバグと云う。バグを発見した場合プログラマはテスト後に直ちに故障票を書いて直す必要がある。 
バグはテストだけでは捕捉できない。レビューが必要である。レビューをしなければ問題のあるシステムをリリースしてしまうリスクが高くなる。 
次のメソッドをみて欲しい。 
void e2j(String english){ 
return "我輩は猫である"; 

このメソッドの機能は本来和訳であるが入力値を 
I am a cat. 
とせねば正しい結果は得られない。まさにこのメソッドにはバグがあると云える。だがこのバグはテストでの捕捉が難しい。入力値を 
I am a cat. 
とすればテストOKとなってしまうからだ。OKとなればもうその同類のテストはやらない。バグは二度と見つからなくなる。 
この問題の解決方法はレビューである。レビューをすれば簡単にバグを捕捉できる。 
検証とは本来、テストとレビューのダブルチェックにより行うべきである。ダブルチェックをしなければバグはなくならない。だがコストがかかるという理由からダブルチェックをやらないというシステム開発もある。もちろんそんな開発は
論外である。

ソースコードの正しさ

システム開発に於けるソースコードの正しさとは何か。

バグがないこと、ではない。仕様書の記載をソースコードが守っていることだ。仕様書ソースコードのルールである。遵守していればそのソースコードは正しくそうでなければそのソースコードは正しくない。

こんなことは基本中の基本である。知らない方がどうかしている。

仕様書の雛形とアーキテクト責任

仕様書が曖昧になる要因に雛形の不備がある。

例えばオブジェクト指向設計に於いてはクラス仕様書は必須である。所がクラス仕様書の雛形がない現場もある。そのような現場ではしばしば他の仕様書の雛形が代用される。勿論出来ないことはないことはない。だが雛形というのはあればいいというわけではない。設計に合った形式でなければ歪みが起きる。歪みは曖昧な(若しくは誤った)表現となる。

曖昧になる要因は他にもある。ガイドラインがないこともそのひとつだ。いくら雛形が優れていてもガイドラインがないか、有っても表現が難解であれば、仕様書の表現レベルはバラバラとなる。

であるから、クラス図の雛形が無ければ作るしかない。それをしなければシステム品質は確保出来ない。

開発が遅れる主要因は技術者の迷いである。迷いは技術者が既存の雛形では対処出来ない時に起きる。回避するには、バリエーション豊富な仕様書の雛形とそれを利用するガイドラインを用意する必要があり、これを用意する責任はアーキテクトにある。


曖昧な表現という問題

もしも技術者が常に「明確で論理的な仕様書」を作成できるなら、システム開発など児戯に等しい。然し残念ながら我々にはその能力がない。我々の作る仕様書にはどこかに曖昧な表現がある。この曖昧な表現は人を混乱させ彼等に間違った解釈をさせる。混乱は進捗の停滞、間違った解釈は手戻りを発生させる。
例えば
「ユーザに紐付いた承認権限」
と言われてピンとくる人がどれ程いるだろうか。これは実際の現場で作られた仕様書の一文である。
意味はこうだ。
ログインユーザのユーザIDを条件に承認テーブルを検索し承認権限を取得する。」
となる。具体的には
「セッションから「userid」をキーに取得したユーザIDをselect approvalflag from auth where userid = ?のパラメータに指定し実行する」
のような実装となる。
最初の文からこの答えに辿り着いた方は経験豊富な技術者に違いない。イメージと違ったとか見当違いだったという方が殆どだろう。当たり前である。それだけこの文章は曖昧なのだ。「紐付いた」などという曖昧な表現は極力仕様書で使うべきではない。
今回の格言。
「答えに辿り着けない者がダメなのではない。答えに辿り着けない者が出てくるような曖昧な文章を書いた者がダメなのだ」