アブジェクト指向プログラミングのススメ

2007/6/25

Introduction to Abject-Oriented Programming」という記事がありました。 オブジェクト指向プログラミングで発生しがちな事柄を皮肉っています。 かなり笑えました。

最初は気がつきませんでしたが、原文のタイトルはObject-Orientedではなく、Abject-Orientedになっています。 面白かったので訳してみました。 一部良くわからなかったので省略してしまっているのと、間違っているかもしれないので、原文もご覧下さい。

また、原文のコメントも面白かったので、もしよろしければご覧下さい。 なお、原文のコメントにはネタであることを理解していないと思われる人の書き込みがありました。 念のためここにも書いておきますが「オブジェクト指向」じゃなくて「アブジェクト指向」ですよ!!!

仮に、

Abject: 絶望的な、悲惨な、惨めな、屈辱的な、ひどい

だそうです。


アブジェクト指向プログラミングとは、コードの再利用を促進し、長期間利用可能なコードをプログラマが生成していることを保障するための慣例集です。 プログラミングにおいては、生成した行数はアプリケーションの重要度を測る重要な指標です。 あるプログラマが日/週/月に生成可能な行数というのは、プロジェクト計画やリソース管理における有用な基準です。 アブジェクト指向プログラミングは、短期間のうちに大量の行数を生成する最良の方法です。

継承

継承は古い機能を新しいコードとして維持する方法です。 プログラマは、既存の機能や、複数行のコードをコピーしてから変更することによって、それらを派生させます。 派生したコードは、オリジナルのコードに含まれない機能を実装することによってスペシャライズされます。 これにより、古いコードは維持されたまま新しいコードとして継承できます。

継承されたコードは、ちょっとした違いしかなく差異が少ないコードであるという特徴を持ちます。 継承には、スタティックなメンバという特徴もあります。 オリジナルとの整合性を保つためだけに存在し、新しいコードでは参照または利用が全く無い変数やコードが存在していません。

以下が、継承を示すpseudo-codeです。



function getCustName(custID)
{
    custRec = readFromDB("customer", custID);
    fullname = custRec[1] + ' ' + custRec[2];
    return fullname;
}

function getCustEmail(custID)
{
    custRec = readFromDatabase("customer", custID);
    fullname = custRec[1] + ' ' + custRec[2];
    /***************
    * 4/15/96 git : email address stored in
    * second fax field
    ***************/
    return custRec[17];
}


getCustEmailという関数は、メールアドレスがアプリケーションに追加されたときにgetCustNameから継承されています。 このように継承を利用すると、新しいバグを産むリスクを軽減できます。

サブタイピング

サブタイピングは、オリジナルコードから利用する変数の型が変更されるときに行われる継承の一種です。

モジュール化

モジュール化されたプログラムとは、同様なコメントヘッダ部を持つ分けられたファイル群により構成されます。 各モジュールは、以下のような要素を持っています。

  • コピーライト
  • 免責条項
  • 3〜5行のアスタリスク
  • 変更履歴
  • 本来このモジュールがすべきだった事の説明
  • 3〜5行の追加アスタリスク
  • 各機能の名前、作者の名前、製作開始日などを含むアスタリスクやその他記号で囲まれた空白行の大きな塊
  • コード本体

モジュールは、結合動作を最小限に止めてモジュール強度を強化するために小さく保つ事が一般的です。 モジュールが大きくなりすぎたら、コピーライトなどを複製しながら小さく分割しましょう。 コメントの継承は必ず安全に行えるので、全てのオリジナルコメントをそのまま複製するのが最も安全な方法です。

コンポーネントとライブラリ

アブジェクト指向プログラマは外部コンポーネントを活用します。 外部コンポーネントは本の中やインターネット上で発見可能です。 検索エンジンを活用することによって、賢いプログラマは時間を節約します。

最も活用しやすいコンポーネントはブラックボックスです。 プログラマは、その中で何が行われているかを知りませんし、興味もありません。

巨大なプログラムの多くは、Web上で拾ってきたアプリケーションやコンポーネントから継承されたものの集合です。

カプセル化

カプセル化とは、コードとデータを分離することです。 これは、データ隠蔽と呼ばれる事がありますが、データは本当に隠されているわけではありません。 単に余計なコードの層に覆われているだけです。

例えば、データベース参照をそこら中に書き散らすことは良いことではありません。 アブジェクト的アプローチでは、データベースを参照するような機能は全てラップするか隠蔽します。 すなわち、データベースをカプセル化するということです。

上記例では、getCustName関数は直接データベースを参照していません。 他の関数を使ってデータベースを読んでいます。 getCustNameやgetCustEmailが知っていることは、ちょっとしたデータの探し方だけです。 どうやってデータベースを読むかは他の関数にカプセル化されています。

ポリモーフィズム

アブジェクト指向技術を習うときに必ず苦労するのがポリモーフィズムです。 難しく聞こえますが、実装するのは容易です。 入力の内容に応じて出力の種類が変わるコードはポリモーフィックであると言えます。

例えば前述した例は、以下のように既存のコードを継承したうえで新しい関数としてカプセル化することにより、ポリモーフィックなコードとして書き換えが可能です。



function getCustData(custId, what)
{
    if (what == 'name') {
        custRec = readFromDB("customer", custId);
        fullname = custRec[1] + ' ' + custRec[2];
        return fullname;
    } else if (what == 'email') {
        custRec = readFromDB("customer", custId);
        fullname = custRec[1] + ' ' + custRec[2];
        /***************
        * 4/15/96 git : email address stored in
        * second fax field
        ***************/
        return custRec[17];
    }

    /* ... etc. */
}


ポリモーフィズムは非決定性やチューリングマシンの考え方と関連しています。

Is○○ vs Has○○

これは巧妙で良いアブジェクト指向的設計です。 アブジェクト指向初心者は全てを継承で行おうとします(Is○○モデル)。 経験を積んでくると Has○○ モデルの方が適切である場合が多いことがわかってきます。 上記サンプルでは、全ての顧客は名前を持っている(Has A Name)ですが、custRecはデータベースです(Is A Database)。

バーチャル

バーチャルクラスもしくはバーチャルメソッドとは、必要であるがまだ製作されていない機能のことです。 一般的には、他のコードが依存するベース部分だけを定義しておいてあります。



function calcSalesTax(price, isTaxable, state)
{
    /****************************************
    *
    * TO DO:
    *
    * get tax rate for the customer state
    * eventually from some table
    *
    *
    ****************************************/

    /** 02/07/99 git -- use WA rate for now **/
    return price * (7.25 / 100.0);
}


Fragile Base Classとは、アプリケーションに長く存在し続けており、ちょっとした変更でもアプリケーション全体を駄目にしてしまうクラスもしくはモジュールのことです。

オーバーロード

オーバーロードとは、モジュールもしくはコードの一部が一つ以上のことをするときのことです。 例えば、顧客の名前とメールアドレスと税額を取得できるサブルーチンなどです。

ドキュメンテーション

コードは人が読めるように書くべきだと言われています。 ということは、ドキュメンテーションを読む人はいません。 新しいモジュールが作成される度にドキュメンテーションに項目を追記し、内容の変更は製品化後もしくはプロジェクトが小康状態になって余裕ができたときに行いましょう。

ドキュメンテーションを書く良いタイミングは、チームのメンバーが2週間の休みを取るときです。 その期間中に全てのドキュメントをその人に書いてもらいましょう。

コード中に大量のコメントを書く行為はコンパイラの速度を低下させます。 そのため、アブジェクト的手法を好む人達はプログラマが間違って消せないところでドキュメンテーション管理します。

バージョン管理

たとえ一人でプログラムを書いていたとしても、バージョン管理は重要です。 経験を積んだアブジェクトプログラマは、以下のようなバージョン管理を行っています。

  • ファイルの先頭に自分の名前と変更日を入れるようにしておく
  • 大きな変更を行うときには「.bak」という拡張子をつけたファイルとしてコピーを作っておく
  • 変更日を含むファイル名を持つ複数のバックアップを保持しておく
  • オリジナルコードと同じディレクトリにこれらのバックアップファイルを保持しておくことによって、ファイルの履歴をわかりやすくする

総括

読者の皆様は、これらの手法の多くは既にご存知だと思います。 アジャイルやエクストリームなどの流行は次々と発生しては消えていきますが、アブジェクト的手法は不変です。 多くのマネージャは、これらのアブジェクト的手法を熟知しており、彼らが過去に書いたアブジェクト的コードを元に仕事をすることを強要するでしょう。

最近のエントリ

過去記事

過去記事一覧

IPv6基礎検定

YouTubeチャンネルやってます!