Top Of Page 強いモジュール 情報隠蔽 隠蔽する対象 モジュールデータ 情報隠蔽への障壁 規約 Bottom

モジュール

モジュールも、ルーチンと並んで、現代プログラミングに必要不可欠な概念です。
書籍によっては、モジュールの定義を「1本のソースファイルのこと」などと説明しているものもあります。
それも確かに正解ですが、しかし一本のソースファイルをどうやってつくりましょうか?
適当にルーチンを寄せ集めて、まあこのくらいの大きさだからファイルにまとめておこう─それでは、いけません。
現在主流となっているプログラミング言語には、いずれもモジュール化を支援するしくみが備わっています。
せっかくソースファイルにまとめるなら、そのまとめ方にもぜひこだわりをもちましょう。
単にルーチンの寄せ集めではモジュール化の甲斐がありません。
あるモジュールを、そのモジュールたらしめているこだわりは何でしょうか。
その鍵はデータにあります。
モジュールとは、データと、そのデータに関連するルーチンの集まりです。
それをまとめてソースファイル1本にする、だからそのソースファイルのことをモジュールと呼ぶのです。

モジュールの「強さ」

強さ、と言っていいものかどうか悩みますが、モジュールにまとめられた(このことを指して「モジュール化された」といいます)ルーチンの結びつきが強いほど、そのモジュールは強固で正当なモジュールとなります。

どんな基準で「結びつきが強い」というのかというと、それは、あつめられたルーチンの目的が同じならば強い、といえます。
ある目的に関する一連のサービスを一つのモジュールで提供します。 雑多な目的のために寄せ集められたモジュールは、くくりの弱いモジュールとなります。
データを中心に、そのモジュールのテーマを考えてモジュール化しましょう。

複雑さを管理するために ─ 情報隠蔽

人間が同時にあつかう「複雑さ」には限度があります。
自分が組んでいるプログラムの「複雑さ」が自分の能力の限界を超えたとき、バグの発生率は飛躍的に上昇し─
─1から組み直そう─(T-T)。
とか思いつめたりする訳ですが、結局組み直しても同じ苦しみに打ちひしがれます。
高品質の、バグのないプログラムを書くためには、プログラム全体の「複雑さ」をなるべく軽減しなければなりません。
私はこのことを「複雑さを管理する」と言っています。
この「複雑さの管理」の手段として、モジュール化による情報隠蔽があります。

それぞれのモジュールの性質や内部を、どれだけ他のモジュールから隠すことができるか、その「隠す」ことを情報の隠蔽と呼びます。
これはモジュール化が提供する強力な機能です。
情報を隠蔽は、モジュールのどのルーチンを公開(ほかのモジュールから呼び出せるようにすること)するか、どのルーチンを非公開にするかを決めることによって行われるといっていいでしょう。
また、データは一般的に公開しない方がモジュールとして丈夫に設計できます。

情報隠蔽 ─なにを隠すか

他のモジュールに対して隠しておくとよいことは何でしょうか?
典型的なものを挙げることにしましょう。
これらは、いずれも、「難しい」とは言わないまでも「面倒な」部分です。
プログラムに変更を加える必要がある時、考えたくない部分でもあります。
それらを他のモジュールから見えないように記述します。
つまり、他のモジュールは、そのモジュールの関数を呼ぶだけ、関数名とパラメータは知っているが、その関数の内部でどんな処理をしているのかは関知しない、という作り方です。
そのモジュール内部の処理は、そのモジュールが責任を持って取り計らいます。
これによって他のモジュールは、そのモジュール本来の処理に集中できるのです。

これらの情報隠蔽は、プログラムの複雑さを軽減するとともに、変更箇所の封じ込めも目的にしています。
このため、

も、モジュール内部に隠しておくべきです。

グローバルデータとモジュールデータ

モジュールデータとは、そのモジュール内でのみアクセス可能なグローバルデータ(CやC++ならばstatic、VBならばPrivateなど)のことです。
さらにモジュールデータに直接アクセスするのはそのモジュールのいくつかのルーチンだけに限定した方がよい場合が多いです。

無制限なグローバルデータアクセスは大きな危険性を伴っています。
グローバルデータアクセスを許すとすると、そのデータの整合性は誰が保証するのでしょう?連帯責任?
それを認めると、なんらかのデータ変更のコードを書いたら、すべてのモジュールのすべてのルーチンでその変更が受け入れられるかどうかチェックしなければならなくなります。

たとえば、ゲームの点数を入れる変数 Score を考えましょう。
これが、どんなルーチンからでも自由に値を設定できたとします。
さあゲームができました。でも、動かしてみると、どうもおかしい。
いつのまにかスコア表示が0点になってしまっています。
どうやらどこかでミスしてScoreに0をいれてしまっているようなのですが…
さあ大変です。プログラム全体を調べなくてはなりません。
しかし、Scoreに対するモジュールがあり、Scoreに対する直接のアクセスはすべてそこで行われているとしたらどうでしょうか。
調べる範囲はずっと少なくなります。

データに対しては責任者たるモジュールを作り、そのモジュールがデータの整合性について保証するべきです。データに対する責任の分担をするわけです。

モジュールは、データの直接アクセスを自モジュール内の限られたルーチンのみに限定する事により、そのデータの「正しさ」について責任がもてます。
責任を持たなくてはなりません。
そして、他のモジュールが受け持つべきデータの「正しさ」に対する責任は、他のモジュールに任せる事ができるのです。

情報隠蔽への障壁

(ルーチン化と同じように)心理的な障壁があります。それは、日常的に(あるいは無意識に)使用している他のプログラミングテクニックと違うことによる精神的なこだわりです。

これらが、主な障害となりえます。
グローバルデータは確かに便利です。ですがそれはプログラムの複雑さを増大させる諸刃の剣です。絶対使わないほうがいいとまでは主張しませんが、その効果とリスクを十分に考慮に入れた上で使用すべきですし、他にスマートな解決法があるなら使わないほうがいいでしょう。

循環呼出しというのは、すこし面倒な言葉かもしれません。
これは、モジュールAからモジュールBのルーチンを呼んでいて、なおかつモジュールBからモジュールAのルーチンも呼んでいるということです。
つまりお互いがお互いを呼び合っているような構成になっているということです。
これを高度なテクニックとして好んで使うプログラマもいますが、このようなプログラムは「スパゲッティ」と言われて他のプログラマから嫌われます。もちろん、何ヶ月か経って自分でそのプログラムを調べるようなことがあると、そのプログラマは後悔をするのですが…(苦笑)
このような呼び合いをするということは、モジュールの分割が的確でないということの現われであることも多いので、モジュールの分け方を再検討してみたほうがいいかもしれません。

パフォーマンスチューニングに関しては、この情報隠蔽をあきらめてもやむなし、という部分もあります。
拡張性、保守性(直しやすさ)を犠牲にしてまで性能を上げなければならない場合もあるでしょう。
しかし管理者や上司、プロジェクトリーダーに対して、性能向上と、その犠牲となるものを報告し、相談してみるくらいのことはするべきです。
もしかしたら、リーダーは保守性を重視するかもしれません。

モジュール化のための規約

CやVBなど、現在では直接「モジュール」という概念をサポートする言語が主流です。しかし、そういった言語を使用する場合でも、コーディングする際に一定の決まりを設けた方が効率的にモジュール化が行えます。
このほかにコメントによる説明も効果的です。しかしコメントに頼らず、関数や変数名そのものでモジュール化を現したほうが、ずっとスマートです。
私がよく使用しているのは、内部ルーチンにはp_をつける(privateの意)、モジュールデータにはm_をつける(module)ということです。
また、関数名も、公開するものはモジュール名をプレフィクスしています。
たとえば、モジュールAのfooという関数を公開する場合、関数名をA_fooにしています。公開しないならp_fooです。
これらは一例です。効果的なルールを考えて実践してください。

そして、ようこそ。「オブジェクト指向」の世界へ

(2/6/2000 add thanks! : handle「虎之助」さん)
ここまで「モジュール」だ「モジュール化」だと書いてきましたが。
すみません。白状します。じつは、ここで書いたことのほとんどは、より厳密に言えば「オブジェクト指向」のことなのです。さらに正確に言えば、私が、オブジェクト指向の中のキモ、つまり根底だと考えている、「カプセル化」のことをここで書いていました。
情報の隠蔽が大事だとか、データを中心にルーチンを集めましょうとか、いろいろとここでまとめました。
これは、オブジェクト指向の言語(C++など)が出現し、そしてオブジェクト指向的な設計手法ができてからのまとめかたで、古き良き(悪しき?)時代の、いわゆる「モジュール」とは少々異なります。
誤解を恐れずに乱暴な表現でいえば、この「モジュール化」で触れたことに足して、「継承」と「多様性」の概念をさらっと説明すればオブジェクト指向の説明は終わります。
ですが、あえて繰り返します。
これからの「モジュール化」はこうあるべきだと思っています。
オブジェクト指向の初心者は、その特徴的なレトリックである「継承」や「多様性」を使いたいがあまり、この根本にして最強の概念である、「カプセル化」の力を軽視してしまいがちです。
オブジェクト指向言語にある便利な文法を覚えても、カプセル化(モジュール化)の意義を決して忘れないで下さい。
はじめに ルーチン モジュール 変数名の力 変数使用法 制御構造 レイアウト コメント テスト デバッグ 謝辞 Top of Site

Copyright (c) 2000 Takao Tamura