なにかな~

なにかな~

Lecture2

Lecture2: 分割



ソフトウェアをデザインする点で一番大切なことは、プログラムを部分に分ける方法である。この講義では、部分についてとどうやって別の物と関連付けるかについての基本的考えのいくつかを紹介する。私たちは、部分ごとを組み合わせることに問題があることに気がつき、組み合わせることを減らす方法を示すだろう。次の講義では、javaは分断技術を明確にサポートしていることを知るだろう。

今日導入されている一番主要な考えは、仕様書である。仕様書は、退屈なドキュメントではない。それどころか、分割に不可欠で、従って質の高いデザインに不可欠である。そして、私たちはより進んだデザインにおいて、仕様書はそれ自身デザインの要素になっていることを知る。
私たちのコーステキストはusesとdependを同義語として取り扱う。この講義では2つを分け、dependの考え方は古いusesの考え方よりもより便利だということを説明する。私たちは、相互関係ダイアグラムを構築し、分析する方法を理解する必要がある。ダイアグラムを使うことは、道しるべとして説明される。


2.1 分解


プログラムは部分の集合から構築される。どんな部分があり、どうやって関連づけるべきだろう。これは分解の問題である。


2.11
DijkstraはプログラムがN個の部分を持っており、それぞれが正しくなる確率がcであるなら、開発者が間違える確率が1-cである。ゆえに、すべてのシステムが動く確率はcN である。もしNが大きいなら、cが1に非常に近くない限り、cN は0に近づく。Dijkstraはそれが正しい方法と示すために、この議論を作った。そして大きな問題が得られれば、問題が大きくなる。あなたがそれぞれの部分を完璧にできなければ、プログラムを動かせる望みはない。

(あなたは古いテキスト構造的プログラミング Dahl,Dikkstra,Hoare著、Academic Press 1972でその議論を見つけることができる。実際に、すべてのプログラムが完璧に動く可能性は0である。そして確実にする方法は、ある限られた、しかし重要なプロパティを把握し、すべての部分は必要がないことである。私たちは後ほどここに戻る)


しかし、これは私たちはプログラムを部分にわけるべきではないという意見だろうか。より小さいNは、プログラムが動くであろう高い確率を持っている。もちろん、それはジョークだ。大きい1つのものより、小さい部分を得るのは易しい。(そして、パラメーターcはNと独立ではない)しかし、プログラムを小さい部分に分けるのはどんな利益があるかを問うのは価値がある。ここにいくつか挙げてみよう。

○分業 プログラムは無から現れるのではない。それは徐々に作られるべきだ。もし、あなたが部分に分けるなら、いろんな人でそれぞれの場所を分担してすばやくプログラムを作ることができる。

○再利用 時々、異なったプログラムにある共通の部分を部分として解釈することができる。そして彼らは1度作成し、何度も使うことができる。

○モジュラーアナリシス   たとえ、プログラムが1人の人によって作られたとしても、それを小さい部分にわける利点がある。それぞれの部分が完了するたびに、正しいかどうか解析される。(コードを読むことにより、テストをすることにより、後に話す洗練されたやり方により)もし、それが動くなら、最訪問することない別の場所で、使われるのが可能である。進歩の満足いく意味を与えるそばで、これは微妙な利点を持っている。2度目のでかい部分を解析することは、2倍以上大変なことである。それで、小さい部分でのプログラムの解析は、解析のすべてのコストを劇的に減らすことになる。

○ローカライズ チェンジ  実用的なプログラムは、その環境にあわせての適応と拡張が必要である。もし、1箇所の変更が少しの部分をローカライズできるなら、変更をし、有効にするときに全体としてより小さなプログラムの部分が必要とされる。

Herb Simonは興味深い議論をしている。なぜ構造は――人工的なあるいは自然の――階層構造をとる傾向にあるのだろうか。彼は2人の時計作りを考えた。1人はたった1つの長い工程で組み立てる、もう一人はラインになった工程で作り組み合わせる。電話が鳴ると、時計作りは止まって、どんな作業をしていたとしても中断しなければならなく、作業はだめになってしまう。たった1つの工程で作っている時計作りは全部がだめになり、1からやり直さなければならない。しかし、階層的に作業している時計作りは、失敗しない。その結果いつも時間を節約でき、効果的に時計を生産することができる。ソフトウェアを作るにはどちらが適していると思いますか?
(この議論はSimon’s paper The Architecture of Complexityに載っている)

2.1.2 部分って何?

プログラムはどんな部分に分割できるのだろう。今からモジュールより部分という用語を使おう。その結果言語特有の考えから離れることができる。(次の講議では、Javaがどんなふうに部分に分割するために特別なサポートをしているか見てみよう)今から、私たちが記述する必要があるすべては、プログラムの部分は内容である。実際、ソフトウェアの進歩は内容を生産し、解析し、実行するのがすべてである。私たちはじきに、プログラムの部分がすべて実行可能なコードではないということがわかる。それは部分としての仕様として考えるのが適当である。


2.1.3 トップダウンデザイン

いくつかの部分Aが必要であり、それぞれを部分に分解したいと仮定しよう。どうやって正しく分割するのだろうか。このトピックはこのコースで学ぶであろう大事なところである。AをBとCに分解すると仮定しよう。それから、少なくともそれはBとCを構築することができるべきだ。そしてBとCを一緒にすればA ができるだろう。

1970年代には、ソフトウェア開発にはトップダウンデザインと呼ばれる人気のある手法があった。その考えは単に次の手順を再帰的に適用する。

○もし、あなたが構築する必要がある部分がすでに利用可能なら、できている。
○さもなければ、それを細分化し、それらを開発し、合体させる。

より小さい部分にわけることは、「関数的分割」として使われた。
あなたはその部分が持つ関数について考え、その関数をより小さい手順に分解する。たとえば、ブラウザはユーザが入力でき、Webページを取りに行き、表示させる。それでブラウザは、入力受け、ページ得る、ページ表示に分割できたかもしれない。

その考えは魅力的で、まだ人々の支持を集めている。しかし、それはみじめに失敗する、そしてそれはこんなわけだ。一番最初の分割は非常に大切なものである。そして、未だにあなたは分割”木”の”葉”までいくまでにそれがよいかどうか見つけることができない。あなたはそのやり方で、きちんとした評価をすることができない。それら自身が実装されていない2つの部分に分割されたかどうかテストすることができない。あなたが、分割”木”の最後までいくと、上でやっていたような分割はもうできない。それで、危機の観点からいくと---必要としてる情報を持っているとき、意思決定をし、失敗の機会と費用を最小限に抑える---それは非常に悪い方法である。

実際に、よく起こることは分割はあやふやで、進むにつれてよりはっきりと定義されたものになるだろうという期待を持っている。そこで、解決しようとしている問題がどんなであるか実際に指摘しよう。結果として、末尾近くに辿り着いた時、部分を組み合わせ 望ましい働きを実現するために、自分でありとあらゆるハックを加えていることを知るだろう。部分は広範囲に渡って組み合わされ、その結果小さな変更は他のものすべてを変更しないとできない。もし運が悪ければ、部分はまった組み合わさらない。そして、最終的にトップダウンデザインには再利用を勧めるものはない。

(トップダウンデザインの危険についての議論は、Software Requirements and Specification: A Lexicon of Software Principles,Practices and Prejudices,Michael Jackson,Addison Wesley,1995というタイトルの記事を見よ)

これはもちろん、システムの階層を見ることは悪い考えと言っているのではない。その方法では開発できないということなのだ。


2.1.4 よりよい方法

もっとよい方法は抽象的にほぼ同じレベルで多数の部分を考慮したシステム構造を開発することだ。あなたは一度すべての部分の記述を絞り込み、どこの部分が組み合わされるか解析し、いろいろなものを実装を始める前に望ましい機能を実現する。それもまた、機能寄りより、データ寄りのシステムの方がよいということに結局なる。

おそらく、部分へと分割するのを評価する最も大切な検討事項は別の部分とどんな風に組み合わせるかということだ。最小限の組み合わせにしたいー切り離すためにーそうすれば、それぞれの部分を他の物と独立したものとして取り組むことができる。これが今日の講議の主題である;このコースの後ほどで、部分の性質とどのように他の部分と関係するかの詳細をどのように表現することができるかを知るだろう。

2.2 独立した関係



2.2.1 ダイアグラムを使う。

部分間の関係で一番注意することは、リレーションシップを使うことだ。
もし、Aの意味がBの意味によるという方法でAがBを参照しているなら、部分 
Aが部分Bを使っていると言おう。もし、AとBが実行可能コードである時、実行された時、Aの意味はその動作になる。そこでAの動作がBの動作に基づく時、AはBを使うと言う。
たとえば、ウェブブラウザをデザインしていると仮定しよう。
ダイアグラムは架空の部分への分割を示す。

メインの部分はHTTPプロトコルに携わるプロトコル部分を使っている。HTMLをパースするパース部分はページを受け取り、ディスプレイ部分はスクリーン上に映し出す。これらの部分は順々に他の部分を使う。プロトコルはネットワーク接続を確立し、低レベル接続をするためにネットワークを使い、受け取ったHTMLページを蓄積するためにページを使う。
figure1

パーサーはHTMLページから抽象的なシンタックスを作るためにAST部分を使うーページを文字列としてよりも論理的構造としてデータ構造は表現する。パーサーは未加工のHTML文字列にアクセスすることができる時までページを使う。ディスプレイは
抽象的シンタックス木をスクリーン上に描写するためにレンダーを使う。

どんな形のグラフが使われているか考えてみよう。
○木。ーーまず、グラフとしてみた時、使われているダイアグラムは一般的な木構造でないことに注意せよ。複数のユーザに使われる部分が再利用されている。そして部分が2つに分割する時はいつでも、それぞれの部分がコミュニケートするために共通部分を持っているようだ。たとえば、ASTはパーサーにその結果とディスプレイとをコミュニケートすることを許している。

○レイヤーーーー階層化された組織は共通である。ブラウザのより詳細なユーザダイアグラムは我々が上に掲げたそれぞれの部分に代わっていくつかの部分を持つかもしれない。たとえばネットワーク部分は、ストリームやソケットとして置き換えられるかもしれない。レイヤーの並びとしてシステムを考えることは時としてやりやすいことだ。それぞれは抽象の変化するレベルにおいて根本的な基盤を提供している。ネットワークレイヤーはネットワークの低レベルでのビューを提供し、プロトコルレイヤーは一番上に位置し、HTTPクエリを処理する基盤としてのネットワークのビューを提供する。そして一番上のレイヤーはシステムのユーザの視点としてのアプリケーションを提供する。それはURLを見えるウェブページへと変える。技術的に、私たちはそれぞれの部分をレイヤーに割り当てることによりいろんなユーザーのダイアグラムを階層化することができる。その結果いくつかのレイヤーからより高いレイヤーの部分への矢印はない。

figure2

しかし、これは本当に階層化されたプログラムを作らない。なぜなら、レイヤーはまったく概念的な整合性がないから。

○循環、ユーザダイアグラムの中で循環を持つことはまったく共通と言ってよい。それはプログラムの中で再帰をしなければならないという意味ではない。ここで、私たちのブラウザのデザインの中でどんなふうに起こったか見てみよう。私たちはディスプレイがどんな風に働くか考えたことはない。
 たとえばディスプレイに描くための機能を備え、呼び出しをすることにより別の部分への機能を入力処理をする(ボタンが押されたとか)GUI部分があると仮定しよう。そのとき、ディスプレイはGUIを出力のために使い、GUIは入力のためにメインを使うかもしれない。オブジェクト指向デザインでは、よく言われるように、異なったクラスに強く作用するとき、循環がしばしば起こる。


ユーザダイアグラムをどうすればよいのか
○推論。 部分Pが正しいかどうかを決めたいと仮定しよう。P自身は除いて私たちが調べる必要がある部分はどれだろう。答えは、Pが使っている部分やその部分が使っているもの、などなどである。言い換えれば、すべての部分はPから到達可能である。私たちのブラウザの例ではディスプレイの動きを調べるために、レンダーやASTもまた固定する必要があるだろう。逆に、もしPに変更を加えたら、どの部分が影響を受けるだろう。その答えは、Pを使うすべての部分であり。それらを使う部分であり、などなどである。もし、例としてAST を変更したら、ディスプレイ、パーサー、メインなどすべてが変更しなければならないだろう。これはインパクト分析と呼ばれ、変更の結果が完全にわかっていることが確実で、すべての部分を止めることを避けたい時に大きいプログラムのメンテナンスの間を通じて重要である。

figure3

○再利用。サブシステムを独立させるために、部分の中の一部は、再利用可能である。私たちはサブシステムではどの部分も使われていないことを調べなければならない。同じ決定が、最初の実装のための最小限のサブシステムを見つけるやり方を教えてくれる。たとえば、他の部分によらないディスプレイ、レンダー、AST などの一部はユニットとして再利用することができる。

○建設指示書、ユーザダイアグラムは部分を組み込む命令をする決定を助ける。私たちは2つの部分セットを2つの異なったグループに割り当て、並列に動かすと仮定しよう。1つのセットの部分が別のセットの部分を使わないことを保証すると、どちらのグループももう片方を待つことにより行き詰まることはないと確約できる。そして私たちはそれぞれの部分を使い、他の部分を使わないユーザダイアグラムの最後から始めることにより、システムを増加的に構築することができ、そして、私たちが整合的なサブシステムを作る時はいつでも上昇し、組み立て、テストをする。たとえば、ディスプレイとプロトコル部分がそれらが使っている部分にそって独立的に開発することができるが、ディスプレイとパーサーはできない。


これらの事実を考えることは、デザインの質を明らかにする。私たちが上で指摘した循環(メインーディスプレイーGUIーメイン)はたとえば、メインを再利用しなければディスプレイを再利用できなくしている。

ダイアグラムを使うのにはやはり問題がある。私たちがちょうど議論しているほとんどの解析は、到達可能または届いているすべての部分を見つけるこを伴う。そして悪いことに、システムが発達すれば、問題は悪化する。以前したのと同じように、部分でないものを直接に参照する部分があると考えたとしても。違ったように置くことは、用途の根底にある基本的な関係は、過渡的である。もし、AがBに作用され、BがCに作用される。そのとき、AはCに作用される。もし、部分への推論が、たとえば、参照する部分を見ることだけにより必要ならもっとよい。

リレーションを使う考えは、そしてソフトウェア構造を考える点での役割という考えはまずDavid ParnasによりDesinging Software for Ease of Extension and Constraction IEEE Transaction on Software Engineering,Vol.SE-5,No2,1972で述べられている。

2.2.2 独立と仕様書

この問題の解決方法は、歩みごとに止まる従属の概念の代わりを持つ。いくつかの部分Aについて推論するために、それが従属している部分だけを考える必要がある。これを可能にするために、Aが従属しているすべての部分に渡って完璧になされることが必要である。











© Rakuten Group, Inc.
X
Design a Mobile Website
スマートフォン版を閲覧 | PC版を閲覧
Share by: