[プログラム設計事始] 外部設計と内部設計の狭間
「外部設計と概略設計」 で、 外部⇔内部 と 概略⇔詳細 とは直交する概念だということを示しました。 同じ図をもういちど掲載しておきます。
ここで、 概略と詳細の間にはいくらでも中間段階がありえるということは、 おわかりいただけると思います。 複雑なシステムでは、 全体の概略を示し、 それを分割したサブシステムとして表し、 それぞれをまた分割したサブ・サブシステムとして定義し… と、 概略から詳細へ何段階かに渡って設計していかなければ、 人間のアタマでは把握しきれないでしょう。
では、 外部設計と内部設計は? きれいに二分されるものでしょうか?
外部設計は、 それを使うモノに対しての 「公約」 になります。
システムの外部設計は、 顧客・ユーザーに対しての 「公約」 ですから、 勝手に変更することは許されません。 フレームワークの外部設計は、 フレームワークを利用する開発者 (あるいはサブシステム) に対する 「公約」 になりますから、 やはり勝手に変更できません。 メソッドの外部設計は、 そのメソッドを使う開発者 (あるいはメソッド) に対する …以下同文。
それに対して、 内部設計は、 外部設計に影響が及ばない限りにおいて、 好き勝手に設計することができます。
そういう意味では、 「公約」 と 「お家の事情」 が綺麗に分離されていることが理想でしょう。
しかし、 現実はそう上手くいかないものです。
「プログラム設計」 ( 「プログラムの本質と、 インターフェース部分を分けるということ」 参照 ) においては、 次のような例を考えつきました。
(1) 内部設計を考慮して外部設計をしたほうが良いことがある ( 内部設計の外部設計への干渉 )
(2) 外部設計と内部設計に同じ部分がある。 ( 外部設計と内部設計の重複 )
◆ 内部設計の外部設計への干渉
よく言われる、 「言語やフレームワークを知らない SE が作った仕様は、 実装できやしねぇ~ (--; 」 という話です。 内部設計 ( 実装含む ) を考慮して外部設計やってよ、 というボヤキですね。
「メソッドの外部設計(1)」 で最初に示した設計では、 null の引数に対して、 出力を (NullReferenceException) としました。 なぜそうしたかというと、 わざわざそのために何か実装をしなくても、 NullReferenceException が発生するからです。
二番目に示した設計では、 null に対して null を返すこととしました。 その場合は、 実装するときに、 例えば if 文で null かどうかを判定する部分を追加しなければなりません。
この例では if 文ひとつの増加ですが、 実際のプロジェクトでは、 外部設計のちょっとした違いで、 実装の複雑さが大きく変わってしまう可能性があると思います。
このことは、 外部設計を完了させる前に、 内部設計を検討して、 外部設計を見直してみるべきである、 ということを示唆します。
別の例を挙げます。
メソッド A() が、 メソッド B() を呼び出すとします。 そのことを、 メソッド A() の外部設計に含めなければならない場合があります。 ( 別途、 書きます )
しかし、 メソッド B() を呼ぶ必要があるということ、 また、 ちゃんと呼び出せるということ ( 例えば違うアセンブリに入っていて、 そこを参照できなかったら、 呼び出せません ) を知るためには、 メソッド A() の内部設計を理解している必要があります。
このことは、 外部設計を検討しているときに、 内部設計も検討する必要がある場合もある、 ということを意味します。
◆ 外部設計と内部設計の重複
設計の記述は、 重複しないことが理想です。 同じことが複数箇所に書かれていると、 メンテ漏れが発生しやすくなりますから。 外部設計と内部設計も、 重複しないことが理想でしょう。
※ この見方からすると、 概略設計⇔詳細設計 の間は少ないほうが良いことになります。 しかし、 必要以上に中間レベルを飛ばしてしまうと、 こんどは把握しきれなくなります。 あるいは、 重複を避けようとして別文書への参照だらけにしてしまっても、 やっぱり把握しにくくなるでしょう。 けっきょくはバランスを取るのが難しい、 ということですね。
クラス設計は、 外部設計と内部設計の重複がわりと多くなると思います。 次に挙げる例は、 外から見える部分しか存在しないため外部設計と内部設計が完全に重複していて、 いわば内部設計が必要無い、 とも言える場合です。
パブリックメンバーしか持たないクラスを考えてみましょう。
クラス単体の外部設計では、 外から見える状態と振る舞いを定義します。 パブリックメンバーとして整数 x と y だけを持った、 Point クラスを考えてみます。
外部設計をクラス図で表現すると、 こうなります。
Point |
+ x : int |
+ y : int |
内部設計を、 実際のコードで示すと、 こうですね。
class Point{
public int x;
public int y;
}
表現形態は違いますが、 表現していることは同じです。
以上、 2つのパターンを挙げてみましたが、 他にもきっとあると思います。
外部設計と内部設計は、 理想としてはきれいに分離していて欲しいと思うものの、 そうはいかないこともある。 言い換えれば、 外部設計と内部設計の中間もあるであろう、 ということでした。
| 固定リンク
「プログラミング」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー(2018.02.10)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
この記事へのコメントは終了しました。
コメント