読書会(アジャイルソフトウェア開発の奥義)第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< --


[ 戻る ]