OpenCourseWare(OCW)を勉強するWiki
6.170 Laboratory in Software Engineering Lecture 2
最終更新:
匿名ユーザー
-
view
MIT OpenCourseWare > 6.170 Laboratory in Software Engineering, Fall 2001 > 6.170 Laboratory in Software Engineering Lecture 2
MIT OpenCourseWare 6.170 Laboratory in Software Engineering, Fall 2001, Lecture 2: Decoupling のまとめ
ラジオの方では vol.2,3 にあたりました。Lecture Noteを読むときの助けにしてください。
6.170 Laboratory in Software Engineering, Fall 2001のLecture NoteのPDFはこちら
(※2006年4月16日現在、上記講義は6.170 Laboratory in Software Engineering, Fall 2005にアップデートされたようですが、PDFはまだ拾うことができます。)
6.170 Laboratory in Software Engineering, Fall 2001のLecture NoteのPDFはこちら
(※2006年4月16日現在、上記講義は6.170 Laboratory in Software Engineering, Fall 2005にアップデートされたようですが、PDFはまだ拾うことができます。)
2.0 introduction
どう分割して組み合わせましょうと言う話。
specificationが大事!
ちなみにuse(使う)とdepend(依存)は同じ意味で使うよ。
specificationが大事!
ちなみにuse(使う)とdepend(依存)は同じ意味で使うよ。
2.1 Decomposition
2.1.1 Why Decompose?
Dijkstraさんがこういいました。
「もしプログラムがN個の部分に分かれてて、それぞれが正しい確率がcだとしたら、全部合わせたときに正しい確率はc^Nじゃないか」
c<0だからNが大きくなるほど正しい確率は下がっちゃう。
え、じゃあ大きいほうがいいじゃん?
違うよ小さいほうが良いんだよ。
「もしプログラムがN個の部分に分かれてて、それぞれが正しい確率がcだとしたら、全部合わせたときに正しい確率はc^Nじゃないか」
c<0だからNが大きくなるほど正しい確率は下がっちゃう。
え、じゃあ大きいほうがいいじゃん?
違うよ小さいほうが良いんだよ。
- Division of labour 1個だけだと1人で頑張んなきゃいけないけど2個に分けたら2人で並列して作れるでしょ。
- Reuse
- Modular analysis ちょっとずつ、ちいさいとこ1個ずつ合ってるか確認できるよ。
- Localized change 変更したいときに変更の影響が小さくてすむよ。
2.1.3 What are the parts?
Top-down Design:1970年代の一般的なアプローチ。
もしもそのパートがすでにあるものならそれでオッケー。
そうじゃないならサブパートに分けて、開発して、くっつけよう。
サブパートの分け方は"functional decomposition"、すなわちfunctionごとに分けましょう。
最初の分ける時点でちゃんと考えて分けること。下まで言った後にて戻りするのは大変。
もしもそのパートがすでにあるものならそれでオッケー。
そうじゃないならサブパートに分けて、開発して、くっつけよう。
サブパートの分け方は"functional decomposition"、すなわちfunctionごとに分けましょう。
最初の分ける時点でちゃんと考えて分けること。下まで言った後にて戻りするのは大変。
2.1.4 A Better Strategy
サブパートの分け方はだいたいequal level of abstraction。
2.2 Dependence relationships
2.2.1 Uses Diagram
uses relationshipのお話。
どのpartがどのpartに関係しているか、を矢印でつなぐものです。
そうするとこんなグラフが出てくでしょう。
どのpartがどのpartに関係しているか、を矢印でつなぐものです。
そうするとこんなグラフが出てくでしょう。
- Trees ただし、グラフとしてみたときは一般的にはuses diagramはtreeにならないよ。みんなが共用するpartがあるときなんかかな。
- Layers これが一般的。システムをsequence of layersと考えて、色んなレベルのabstractionの各layerが互いに密接したviewを提供してる、と考えると便利だよ。
- Cycles uses diagramではよくある話(ちなみに、プログラムの再帰とは違うことに注意)。AがBを使ってBがCを使ってCがAを使うという。
uses diagramをどういう風に使う?
- Reasoning Pというpartが正しいかどうかを考えるとき、PおよびPからたどれるすべてのパートをチェックすればよい。(impact analysis)
- Reuse 再利用できるsubsystem(partの集合)の切り出しに使えるよ。
- Construction Order どの順番でpartを作れば良いか、どのpartたちを並行して作れるか(関係がないものは並行に作れるから)教えてくれるよ。
ここで問題。cycleになるとみんなが関係しちゃうからsubsystemの切り出しなんかができなくなるので特に大きいシステムでは問題になる。
2.2.2 Dependencies & Specifications
dependencyがぐるぐる回らないようにするにはどこかで切ってあげる必要がある。
Aが依存する唯一のパートとは、Aの振る舞いを完全に決めるものである。これがspecification。
Aが依存する唯一のパートとは、Aの振る舞いを完全に決めるものである。これがspecification。
ここでspecificationが入ったものをdependency diagramと呼ぶと、dependencyの矢印は2種類になる。
specification partは少なくとも1つのimplementation part、実装部を必要とする。
implementation partはspeficification partを満足させる。
specification partは少なくとも1つのimplementation part、実装部を必要とする。
implementation partはspeficification partを満足させる。
specificationを導入したdependency diagramはuses diagramより以下の点で優れている。
- weakened diagram AがBを使うといってもすべてを使うわけではない。BのspecificationのSはAが使うBの範囲を明確にする。
- Evaluating changes 変更範囲が明確になる。Bを変更したとしても、BのspecificationのSに関係してなければAは気にする必要はない。
- Communication AとBを違う人が実装していた場合、あらかじめ合意を取らなきゃいけないのはBのspecificationのSの部分だけ。
- Multiple Implementations specificationのSを実装する方法がいろいろある。
つまり、dependencyの矢印がAからBにいっている、というときは、AはBのspecificationに依存している。
この辺はJavaだとdesign patternとして後で学習するよ。
2.2.3 Weak Dependencies
パートのdependencyの中には、実際はただ途中経路として使われるだけで、中身を気にしなくていいときがある。これをweak dependenceと呼ぶ。
2.3 Techniques for Decoupling
part間のdependenceをどう表現するか。
常にdependenceとはliability(負債)。
デザインの主眼とは、dependenceを最小限にする、"decouple parts from one another"、質的にも量的にもdependenceを最小限にするということ。
質的な依存とは、どれだけ、依存するspecificationの情報に依存するか。
常にdependenceとはliability(負債)。
デザインの主眼とは、dependenceを最小限にする、"decouple parts from one another"、質的にも量的にもdependenceを最小限にするということ。
質的な依存とは、どれだけ、依存するspecificationの情報に依存するか。
2.3.1 Facade
facade patternとは、新しいimplementationを2つのpartの集合間に入れるもの。これはある種のgatekeeperになる。集合Sを使うすべての集合Bのpartは必ずこのgatekeeperを通らなきゃいけない。たとえば、プロトコルレイヤーとネットワークレイヤー。プロトコルは、ネットワークがどう実現されていようとかまわない。これでプロトコルパートが以前依存してたネットワークのspecificationよりも弱い依存になる。
2.3.2 Hiding representation
specificationを使えば、データの表現を気にしないですむようになるよ。
2.3.3 Polymorphism
ちなみにここでCとかEとか言ってる例は、コンテナCが、Eが提供するコンテナ要素に依存してる例。
Eさんに対してweak dependence(Eの中身を知らなくて良いとき、たとえば要素の比較などをEにしてもらうとき)のときのCさんはEさんに対してpolymorphic=many shaped。
ちなみにmonomorphicなときはCは直接Eのspecificationに依存する形。
(ごめんなさい、これ直訳気味で書いてます。実はよくわかんない……)
Eさんに対してweak dependence(Eの中身を知らなくて良いとき、たとえば要素の比較などをEにしてもらうとき)のときのCさんはEさんに対してpolymorphic=many shaped。
ちなみにmonomorphicなときはCは直接Eのspecificationに依存する形。
(ごめんなさい、これ直訳気味で書いてます。実はよくわかんない……)
2.3.4 Callbacks
GUIのボタンが押されたらMainの関数を直接呼んじゃうような、GUIがMainに依存しているのはよくない!
というわけでMainさんは実行時にGUIに、呼んでほしい関数を投げるべし。
これでGUIに対してMainの関数を対応させてるのと同じになるけどGUIはMainを直接使わなくなる。
GUIはその投げるやつ(Listenerですな)に依存することになる。
で、GUIはなにかあったときにはこの仕組みによってMainを”Callback”するよ。
というわけでMainさんは実行時にGUIに、呼んでほしい関数を投げるべし。
これでGUIに対してMainの関数を対応させてるのと同じになるけどGUIはMainを直接使わなくなる。
GUIはその投げるやつ(Listenerですな)に依存することになる。
で、GUIはなにかあったときにはこの仕組みによってMainを”Callback”するよ。
2.4 Coupling Due to Shared Constraints
ここではmodule dependency diagramに出てない依存を考える。
ファイルのRead / Writeの例。2つが同じファイルを読み書きする場合は、このままだとファイル形式が変わると2つとも書き換えなきゃいけない。
Matthias Felleisenの言う‘single point of control’を試みるべし。ファイルに依存するところは2つのクラスに分けず1つのポイントにすること。
David Parnasの提案は、まず、ファイルフォーマットとかのキーになるデザインの決定をリストアップすること。で、各パートでその決定を「外にはわからないように」(多分外に影響しないように)つくること。
ファイルのRead / Writeの例。2つが同じファイルを読み書きする場合は、このままだとファイル形式が変わると2つとも書き換えなきゃいけない。
Matthias Felleisenの言う‘single point of control’を試みるべし。ファイルに依存するところは2つのクラスに分けず1つのポイントにすること。
David Parnasの提案は、まず、ファイルフォーマットとかのキーになるデザインの決定をリストアップすること。で、各パートでその決定を「外にはわからないように」(多分外に影響しないように)つくること。
2.5 Back to Dijkstra: Conclusion
Dijkstraの話に戻ってみると、decouplingを使って変更範囲が遠くまで及ばないようにすれば、たとえおかしなところがあったり変更があったりしてもその影響はローカルですむよ。
today's visitor: -
total visitor: -
total visitor: -


