読書会(アジャイルソフトウェア開発の奥義)第3回議事録
[ 戻る ]
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
java 読書会
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< --
[ 戻る ]