[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends-ml 11725] 「アジャイルソ フトウェア開発の奥義」 : 第三回議事録 ( 案)



栗野@日大 です。

今回は、朗読者の方の名前も反映できました。

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
java 読書会 <http://www.javareading.com/bof/>

BOF in 高津区民館 第6会議室 at 2005/01/29 10:00 - 17:00

出席者(敬称略)

西野, 金井, 小棚木, 
遠藤, 吉村, 岩室, 奥, 村山,
岩永, 亀井, 栗野, 九十
高橋(智), 高橋(徹), 根本, 吉本,

朗読者: 岩室, 高橋(智), 吉本, 遠藤,
書記: 栗野

本 : 「アジャイルソフトウェア開発の奥義」

==

[自己紹介] 略

==

# p.112 7.3 から

p.175 を目標

==

7.3 Copy プログラムの例

# 腐敗の様子をみる

	キーボードからプリンターヘ Copy するプログラムを要求される
		1 日仕事なんだけど.. 3 week かかると答える

	A. 良くある話だ...

	図 7.1 

		Q. 矢印の意味がわからない
		A. データの流れを表している

			Q. 落書 ?
			A. このような図を書くの流儀がある
				# UML ではない。UML 以前の記述

			関数呼び出しをすると、文字が戻ってくる

			Q. 設計がへん
			A. それを議論する場所でない

			Class ではなく関数の Module 分解を行う場合の書き方

			A. ビジオで色々、調べてみよう

	List 7.1 Copy Program Code

		Q. 欠損 0 の意味は ?
			A. 0 Defect の訳では ?
			Q. この業界では無理では ?

		A. プリンターの紙を減らすという話題は現実にもあった
		A. アメリカ人って太りそう

	# SCCS に、1 日 ?

	誤殖 p.113 下から 3 行目
		採用される「ころ」になる -> 採用される「こと」になる

	仕様が変る ( 紙テープからの入力も Okey とする )
		Logic 引数をいれると .. ?
			interface が変る、利用しているモジュールを再コンパイル
				=> だめ !!

	List 7.2 グロバール変数 ptflag & "?:" を導入
		=> コメントを追加

		Q. ?: 演算子って ?
			A. 三項演算子
				Q. 使用禁止では ?
				A. 便利な場面も色々ある
				A. 左辺値にもつかえるし..

	仕様が変る ( 紙テープへの出力も Okey とする )

		A. 予想できる変更だよね..
		A. 風刺にみえない

	我々は、仕様が変更される世界にすんでいる
		仕様が変更されると設計が腐るのは、手法が悪い
			# アジャイルは、腐らないようにするための手法

7.3.1 アジャイルな Copy プログラム

# 脚注 : テスト志向でおこなえば、始めから正しい答が得られたのだが..

	List 7.4 : 最初の要求変更があった時点で後の変更を予想すべき !!

		Q. GdefaultReader ? この変数の名前は何 ?
 		A. グローバルの G

		default 引数が利用されている
			# C++ 固有 (引数の省略) の Code

		Q. Overload にしない理由は ?
		A. こちらでもよいが..
			Q. java には、ないよね ?
			A. 可変長はふえたけど、形がちがう..

		Q. public 継承って ?
		A. C++ 固有 : private 継承などもある..

	変更を許容するためのコードを入れるタイミング ( チャンス ) として捉える
		Open / Close の原則

	「要求に応じてコードを入れる」という原則が働いている
		=> 出力側の方は、直していない

	Q. テスト主導だったら、うまく行くって、どんな感じ
	A. テストを自動化しようとすると、自動的に、I/O を切り換える設計にするだろうから、その時点で、List 7-4 のように、出力が切替をするコードになるだろう

		Q. これって I/F が変っている ( recompile 必要じゃん )
			A. そのとおりだ.. ( Overload ならば I/F が変らない )

		Q. C++ の必然性は ?
			A. 確かに変だ java ならこうならない
				Q. C++ より java の方がよいというつもりで ?
				A. 特に記述はないが.. そうかも

	図 7.1 は依存性が歴然 ( cf. 11 章 )
		ストラテジィパターン ( 14 章 )

	A. 変更要求があった時点で、そこで、設計を行う ( 行うならまじめに設計せよ )

==

7.4 可能なかぎり設計を美しく保つ

# 設計者は、常に設計を綺麗にしようとする : 恒常的に、しょっちゅう行う

	Q. 何時もおこなっているっていっているけど、 C++ とかで、 DLL は変更してよいの
		クリーンアップをしょっちゅうするのは ?
		Q. 「一度書いたコードは直さない」という習慣
		Q. 工数に組込めないし..
		Q. 組み込み系で、直すなんて現実的ではない

		A. アジャイルを前提なので..テストを容易な形にしたらで..

		A. Libirary を想定していのでは ?
			ミドルウェアは対象にしていない ?
				Corba の アイオナ ではアジャイル開発をやっている
					マイグレーションが大変

			ボーランドでは、I/F を変ていない

		A. Clean Up がリファクタリングの話なら、他の場所には影響しないから..
			実際は、I/F も変っているので、リファクタリングだけで済まないから Clean up という言葉を利用しているのでは ?
			# Clean Up の一手法としてリファクタリングがあるのでは ?


7.5 結論

	アジャイルプロセスとは ?
		原則やパターンを継続的に適用する行為
		設計を綺麗にしようとする努力

	Q. printout で Buffer Flush は不要 ?
	A. 考えていないのでは ?
		Q. stderr は unbuffer で、stdout は、bufferd 
		# err と out では、出力の方針が異る

		A. ダイイングメッセージは、stderr へ..

		Q. core をはくのは、IBM の JDK ?
		A. Sun では、Core をはかない

==

8. SRP ( 単一責任の原則 )

モジュールの要素間の「凝縮度の状態」として定義されたが、ここでは、「凝縮の強制」の意味で使う

	SRP: 1 Class には、一つの機能を持たせるという原則
	SRP でないと、要求変更の影響が多数の Class に及ぶ
		=> 脆い設計の要因

	Rectangle Class の例
		SRP を満していない
		# GUI の部分を分離すべき

		A. Server Side で、AWT を使おうすると X がないので、Error になった
			# 最近の JDK では、直った

		Q. Server Side で、Graphic 処理 ( i.e. GIF 生成 ) をしたい時に、X がないという問題はよくあるよね..

8.1.1 役割とはなにか

	役割 = 機能 = 変更理由 !!

	Class を変更するのに、二つ以上の変更理由がある場合は、二つの役割をもつ
		分離するのは、難しい ( because : 人間が関係するものを Group 化する習慣があるため.. )

	modem の例
		設計としては、ごく自然なのだが...
			SRP 違反 ( 堅い設計 )

		変更要求があれば、堅さが露呈でする ( 要求がなければわからない )

	同時に一つの Class に変更がしなければ

		A. いきなり沢山の Class を作られると迷惑
			A. 一つの変更をするだけなのに、沢山の Class を変更しないといけない
		A. 変更が生じなければ、SRP を適用してはいけない
		A. 最初は SRP を考えない。変更が生じた時点が適用のタイミング

		A. jakarta のダイジェスターは、けっこう汚い
			変更がはいらないのが前提なので、そのまま変更されていないのだろう

		A. I/F を考えるひとは責任重大
			A. Eclipse で、Duplicate が沢山出て大変だった..

		Q. C++ で、reflection って ?
			A. 大変では ?

8.1.2 
	好ましくないが、必要な場面もある

	みにくいかも
		依存関係がなくなる
			みにくさが他にもれない

8.1.3 永続性と SRP

	図 8.4

	# 混ぜるな危険

		Q. store はデータを書き出すこと ?
		Q. SQL 文がある

8.2 原則
	内容は単純だが、正しく適用するのが難しい
	結合している役割を見付け、それらを分離する作業は、ソフトウェア設計の本質

[文献] 古い。デマルコは、よく refer される。OO の人ではない。

==

休憩

==

9 章 (OCP) Open/Closed 原則

	A. ダッチドア ?
		Q. おきやのドアがこうなっているのでは ?

	Software は長い間使われ続ける

9.1 OCP

	Class/Module/Function は、Open であると同時に Closed でなければならない
		既存の Code に影響を及ぼさない (Closed) で、変更を加える (open)

	変更に対して Open
		機能の拡張

	修正に対して Closed
		利用する側の変更をしなくてもよい

	Source を変更せずに、機能を追加するには ?
		「抽象」利用する
			機能の拡張は、派生クラスの追加で実現

	図 9.1 : Client / Server : OCP に違反
	図 9.2 : Client / Server : OCP に準拠

	抽象 Class は、利用する側に関係する

	Q. 純粋でない仮想関数 ?

		A. 仮想関数は、純粋なものとそうでないものの両方ある
			純粋であるは、実装がない
			純粋の場合は =0 と書いてある

			A. 実装してもよいらしい ?
			A. java の仮想関数と同じ

		Q. 純粋とそうでないものの使い分けは ?

		A. C++ では、仮想でない関数があることが問題

		Q. C++ の NULL と 0 との関係は ?
			A. C++ 的には、常に 0 を使う ( NULL を使わない ) のが望ましい

9.2 shape

	shape: 悪名高い例
		A. C++ のチュートリアルで利用される

	ポリモロフィズムで利用される

	図 9.1
		A. C 言語のくせに、拡張子は cc だ..

		新しい処理を追加するには、既存のプログラムを変更する必要がある(堅い)
			三角形を追加したら、switch 文のある draw をいじる必要がある

		# 新しい図形を追加すると、binary も変更されている

9.4.2

	draw を抽象メソッドにすることで、問題を解決

	Q. 引数での const 宣言
		A. 変数を変えない ( 不変性の表明 )
			# エミュータブル.. ( 変更不可能 )

	三角形を追加する場合は、Shape Class の派生 Class を作るだけ
		他の場所に影響を及ばさない。
			もろさも、堅さもない

		# 例外 : Shape のインスタンスを作るモジュール ( ファクトリ ) は影響を受ける
			移植性もある
				draw だけが移植できる ( 他の部分は不要 )

9.4.3 落し穴
	変更の内容によっては、大変な変更が必要かも

9.4.4
	描画の順序が重要なシステムでは、shape モデルは正しくない
		どのような変更がおこるかを戦略的に予想して、モデルを選択する必要がある
			=> 経験が必要

	OCP はコストが高い ( 抽象 )
		起きる可能性が高い変更だけに対応させる必要がある

	Q. 結局、設計の段階では予測ができない
		A. MBA で行う必要が..

	Q. 結局、最初からしない
		A. 一度変更されれば、その変更が繰り返される可能性がある
			そこで、はじめて OCP を適用する

	Q. drawShape が影響されるわけでは ?
		関数を追加するだけでは ?
		A. YES : But OCP の立場では、他への影響してはいけないとう前提で考えると..
		関数を追加すると、Client 側に変更があるので、とりあえず Ng といいたい

	A. 継承は恐い

9.4.5 変更から自分の身を守る

	前世紀は、予め身を守る仕組を組込むことが流行した

	Q. 前世紀 ?
		A. 原書は 2001

	最初は変更が起きないと仮定して作成。一度目は弾丸を甘んじて受ける
		二度目からは対応する ( 免疫システム )
			=> 早いうちに、沢山の弾丸を受けた方がよい
				テストの形で、弾丸を大量生産しておく
			テストのための抽象化は本番でも必要 !!!
				# テストはワクチン ?

		List 9.4 	順番に対して抽象化
					# virtual でない

		List 9.5	順序を判定するメソッドは OCP にそっていない
				=> 28 章で解決

9.4.7 データ駆動型

	List 9.6 データ駆動型

		テーブルに、Class 間 Order を記述した table を利用すれば
			=> DrawObject を閉じる

		テーブル自身が問題
			テーブルを切離なせば..

		描画する順序を决める関数が、一箇所にまとまっている
			# virtual でない

		Q. 結局、具象の情報を得る必要があるのでは ?
			A. Yes

		Q. 弾丸の種類をきちんと識別する必要がある

9.4.8 結論

	OCP は重要だが、適用は難しい
		変更がよく行われる部分だけに抽象化をすべき


==

10 LSP ( リスコフの 置換原則 )

	継承に適用される原則
		典型的な継承とは ?

10.1 リスコフの置換原則

	派生 Class の Instance は、基本 Class の Instance で置き換え可能でなければならない。
		=> OCP を支える原則

10.2

	実行時の型情報を使っている場合は、LSP を違反している

		List 10.1 : LSP に違反

		なぜ、LSP に違反するのか ?
			Virtual 関数は、コストが高い
				Q. 組み込み形は、このような型になる

		LSP に違反すると、自動的に OCP に違反している

10.3

		List 10.2 : LSP に違反

	# 利用されるモジュールは、変更を要求される

	正方形は、長方形の一種 ( is-a ) なので、継承するのが当然。
		# OOA で、is-a をきちんと使えていないことが多い

		だが、本当だろうか ?
			Rectangle は member 変数が二つあるが、square は一つでよい。
			setWidth, setHight も変

		例 : LSP に違反している

		Q. どこが問題 ?
			A. Virtual の問題
				# Rectangle で、setWidth, setHight を Virtual にしないとだめ !!
		A. C# も virtual が必要

		Q. なぜ Virtual が必要 ?
			A. 効率がわるいから
				C++ は (java の) HotSpot がない
					あれば、効率がそれほど悪くならないのに..

		Q. C++ volatile は、何も保証してくれる ( java は色々と.. )
			A. java には Multi スレッディングとか、動的順序変更への影響がきちんと述べられている。

			A. Multi CPU では、java の SDK では、却って大変
				4 CPU 位だとリニアーに高速化されるが、8 CPU 位でサチる
					それ以上では、かえって、遅くなる

			Q. 最近の CPU アーキテクチャでは、コード順を変更しないと速くならない

			Q. どうやって、高速化するの ?

		Q. Linux が 2.4 から 2.6 で 6 倍速くなった
			A. スケジューラが馬鹿だった

		Q. 水平スケーリングがのぞましいが
			A. 場所問題もあるし、限界がきているのでは ?
				=> ステートレスにすればよいのでは ?
				Web で、ステートレスにできないのでは ?

		異るプロセスが動いている場合は、Multi CPU でもよいが..
			アプリケーションサーバーでは、こうはうまく行かない

p.145
		Q. LSP -> OCP だけど、逆はいえるの ?
			A. 逆は必ずしもいえない

10.4 問題の本質

	Test の作者の仮定 : 横幅を変えた場合でも、縦は変らないはず
		=> Square は、それを満さない

10.5 モデルの正当性

	正当性は、立場によって、
		正しい立場は Client の Test !!

	[誤殖] p.160 line 4 : だけし「が」使って -> だけし「か」使って

	明らかに LSP に違反する場合は、変更、そうでない場合は保留する

10.6 is-a への理解

	Square Object は Rectangle Object でない
		振舞いが異るから
			モデルとして is-a であるだけでは不十分

10.7 契約による設計

	契約による設計
		LSP が自動的に保証されるための仕組

	Class への契約
		Method の実行での事前 / 事後条件の記述

	派生型の条件は、基本型に対して
		事前条件は弱く、事後条件は強くする

	# Eiffel では、言語の中に組込まれている

		Q. 他の言語できるの ?
			A. D ではできたのでは ?
			Q. どこでつくっているの ?
				A. 元々 C 言語のメーカが..

		Q. アノテーションでできない ?
			a. 実行時にチェックするには、なんらかの仕組は必要

		Q. assert は ?
			A. return の時と例外の時につらい => Aspect が必要.. ?

		Q. 並列同期とか ?

		Q. 並列で debugger はいれられない

		Q. 1.6 でなんとかならない ?
			A. みんなで投票しよう

		Q. 親 Class での契約が、子 Class に適用されると嬉しい ?

	# p.151

Unit Test に契約を記述する

10.4.1	動機
	10.2
		Q. 図の 「点線囲まれた四角」 は ?
			A. Generic や パラメタライズド を表す UML 図 (最近入った)


10.4.2 問題勃発

	永続性がある Set を追加したら...
		図 10.3

		Q. 点線の意味がわからない
			A. 単に関係があるという以上の意味はない
				# メソッドの中でよびだされるとか..
		# Runtime Error は、判断ミスをした個所と遠く離れている

10.4.3
	考えた開発ルール
		永続 Set の利用の場合は、呼び出し側で専用の入口を設け、Rule 化した
			=> 失敗した ( Rule を守らない人がいる )

10.4.4 LSP に対応した答

	永続 Set を、抽象 Set の子 Class にしたのがいけない
		=> 分離した

	Q. こうしたらうれしいの ?
	Q. Member 名が変っているが .. ?
	Q. 斜体になっているのは ?
		A. アブストラクト Class

	Q. add だけなの ? remove は ?
		A. add は条件が必要だが、remove は不要
		# add は事前条件が変更されるが remove は変更されていない

	Q. パラメタライズされてる型 T に条件が少なすぎる
		T に条件があれば..
		# 結局 T だけでは実現できない

10.5 括りだしの方法 (OODの基本的なやりかた)

	List 10.7

	LSP に準じないという手もあるが..

	共通部分を括りだして、新しい Class を作る
		=> コードを沢山作る前じゃないと大変

		複数の Class に共通する Code があれば、上位へ
		上位 Class がない場合は作れ
			=> 一般に、抽象 Class となる

10.6
	基本 Class から何かの機能を取り除いているような派生 Class は、LSP に違反している

		Q. ここでは java か ? ( さっきは、C++ なのに.. )

10.6.2
	例外を投げる場合が増えるのも、契約違反
		Q. java では、そもそも起きないのでは ?
			A. runtime 例外の場合は、この問題がある。

10.7 結論
	Open / Closed 原則は重要
		契約が必要
			明示的にできなければ非明示的に

		Q. 原則そのものは、理解り易いが、適用は..
			A. 難しい
				# 十戒は理解りやすいが、実際に罪を犯す人間が絶えない
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

--
栗野 俊一 <kurino@xxxxxxxxxxxxxxxxxxxxxx>