N2 ToolBox(跡地)

跡地です。引っ越しました。http://d.hatena.ne.jp/nosen

テストケース vs DbC

2004-08-07 22:41:56 | 開発手法/方法論
XPでは特に、テストケースが仕様書の意味も持つと言われます。
これとDbCの事前条件/事後条件によるコントラクトはどちらが優れているのでしょうか?

これはきちんと考えると意外とややこしい問題だと思います。Martin Fowlerはこの問題に対して興味深い意見を述べています。

DbCでは一般的なルールとして仕様を記述しますが、ちょっと難しいことをやろうとするとものすごくトリッキーなコントラクトを書かなくてはならなくなります。これに対して、テストケースではAPIの使用例が仕様の代わりになるので記述は簡単になります。
その代わり、仕様としての厳密さは失われるし、アサーションコードは煩雑になります。DbCの方がすっきり書けるケースも確かに存在するのです。

使われる状況を考慮にいれなければ、どちらが良いということはいえないと思います。現実的に考えた場合、仕様を理解するには使用例と、一般的なルールのどちらも必要です。新しいライブラリを使いこなすには、最初はコード例を見た方が早いでしょうが、完全に使いこなすには一般的なルールを知らなければなりません。コード例だけだと、そこから一般的なルールを頭のなかでリバースエンジニアリングしなければならなくなるのです。

XPのようにチーム間のコミュニケーションがうまくとれている場合、一般的なルールは暗黙のうちにチームのメンバーが了解しているので、正しくインターフェースを実装することができるでしょう。
従来型の開発手法を採用している組織では完全な仕様を記述する必要があるため、DbCのようなアプローチを採用する必要があると思います。

テストケースを使用例とするなら、一般的なルールは実装コード自体になります。あの「コードは仕様だ!」という奴です。
これは実装コードがきれいにかかれており、プログラマの意図が明解に示されている場合のみ成り立ちます。

DbCではこれに加えてエラーが起こったときに誰が悪いのかを簡単に特定できるというメリットがあります。ただし、その代償として多少の冗長さを必要とすることは否めません。コントラクトはほとんど実装コードと同じくらいの長さになってしまうことが良くあります。現状、テストケースにおけるJUnitのようなデファクトスタンダードとなるツールがないのも問題です。

結局最終的な結論は出ていないのですが、個人的な好みとしてはいまのところDbCの方が好きです。最近結構DbCについて勉強しているのでバイアスがかかった見方だとは自分でも思いますが。。。

皆さんはどう思いますか?

コントラクトを普通のJavaクラスとして実装する

2004-07-29 23:42:47 | 開発手法/方法論
yoshiさんにおしえて頂いたページに紹介されていた、Contract自体は普通のJavaクラスとして記述し、Contractを呼び出す箇所のみをAspectとして記述するアプローチには大きく分けて2つのメリットがあると思います。

1.eclispeのJDTの機能をフルに活かせる
eclipseはいまやJavaの開発環境のデファクトスタンダードになっています。そのeclipseのAspectJプラグインであるAJDTでは、JDTの強力な機能である、ソースコード補完やリファクタリング機能の多くが使えません。シンタックスハイライトが聞いたエディタくらいのイメージでとらえたほうがしっくり来ます。コントラクトをPureJavaで書けるとJDTの優れた機能をそのまま使えるというメリットがあります。

2.Javaソースコードを解析する各種ツールを使用できる。
コントラクトはプログラムの仕様です。ソースコードそのままでも意味的には仕様書として通用するとは思いますが、大抵の環境では、仕様書というのはMS-WordやHTMLなどの形式で書くものだという
固定観念に囚われているのが普通です。そのような環境向けには、
ソースコードに書かれた情報をMS-WordやHTMLのような形式に変換してあげるのが良いとおもいますが、コントラクトがAspectJで書かれているとそれがうまく行きません。AspectJの構文を解析して、
その構造にアクセス出来るツールが僕の知る限りまだ存在
しないのです。
それに対してコントラクトがJavaソースコードで書かれていれば、
qdoxなどのツールを使用してコントラクトの情報を他の形式に比較的簡単に変換できそうです。

ただし、紹介されていた通りの方式でコントラクトを実装してしまうと、メソッド一つ毎に一つJavaクラスと対応するアスペクトを作成しなければならなくなります。それではあまりにも煩雑です。

そこで、JUnitがtestXXXという名前のメソッドをテストメソッドとして自動的に展開するようにpre_XXXとかpost_XXXという名前付けルールで事前条件/事後条件チェックに対応するメソッドを起動するように工夫すれば、一クラスあたり一つのコントラクト用クラスを作成すれば良くなって煩雑さが少し軽減されます。

時間をみつけてこのアイデアを実現させる方向で考えてみたいと思っています。

AspectJによるDbCの注意点

2004-07-23 00:50:27 | 開発手法/方法論
AspectJを使用してDbCを実践する時には、いくつか注意しなければならない点があります。それは主にAspectJがDbCに特化したツールでなく、「何でも出来てしまう」ために起きる現象です。
チェック対象オブジェクトはコントラクトがWeavingされていようといまいと、完全に同じように動作する必要がありますが、AspectJのを間違って使うと、この原則をいとも簡単に破壊することが出来てしまうのです。以下に注意点を述べます。

1.対象オブジェクトの状態を変更しないこと
事前条件/事後条件のチェックの際に、呼び出すチェック対象オブジェクトのメソッドは、対象オブジェクトの状態を変更してはいけません。そうしないと、コントラクト自体がオブジェクトの振舞に影響を与えてしまいます。
一般にDbCを適用する際には、メソッドを「コマンド」と「クエリ」に分けて考えると良いとされています。「コマンド」はオブジェクトの状態に影響を与える何らかの処理を実行するメソッドです。
「クエリ」はオブジェクトの状態を取得するメソッドで、それ自体がオブジェクトの状態を変更することはありません。平たくいうとgetterですね。DbCでは基本的に「コマンド」に対してコントラクトを定義します。そのコントラクト内で呼び出すメソッドは「クエリ」で無ければなりません。
クラスを設計する際に最初からメソッドを「コマンド」と「クエリ」に分けて考えておくと良いでしょう。
このあたりの考え方はDesign by Contract By Exampleという本に詳しく解説されています。DbCの基本が豊富な例題を用いて分かりやすく説明されており、おすすめの一冊です。

2.チェック対象メソッドの振舞を変更しないこと
コントラクト記述の際にはaroundアドバイスを多用しますが、aroundアドバイス内では元のメソッドの振舞を好きな様に変更できてしまうので注意が必要です。具体的には

1. proceedの戻り値をきちんと返却しているか?自分で勝手な戻り値を返していないか?
2. 例外が発生した場合、そのままスローしているか?握りつぶしたり、自分で勝手な例外を投げたりしていないか?

といった点に気を付ける必要があります。

以上の様な注意点の他にもいくつかのTipsや課題が明らかになりつつあります。それらに関しても適宜紹介して行きたいと思います。

厳密なプロセスによって守られるもの

2004-07-15 06:44:36 | 開発手法/方法論
ASDに限らず、アジャイル開発方法論では、一般に細かい作業のすすめ方は開発者がお互いに相談して決めることになっています。
ここも重量級方法論の立場の人達から批判の的となるポイントです。
彼らの典型的な意見は以下のようなものになるのではないでしょうか。

「なるほど、厳密なプロセスではケース・バイ・ケースの判断が必要となる複雑な状況に対応できない、というのは分かる。
しかし、複雑な状況に対して適切な判断を下すには高いスキルが必要とされるのではないか?現実のプロジェクトではそんなに優秀な開発者ばかり集められるものではない。それに優秀な開発者ほど単価も高い。
そのような状況でも会社として案件を受注している以上、ある程度の品質を保証する必要がある。実証済の厳密なプロセスに従っていれば、状況によって多少現実とそぐわなくなる部分が出て来るかもしれないが、最低限の品質は守られる。そのことが重要だ。」

この主張に対する反論を試みてみることにします。

細かく定義された成果物とワークフローは、形式知に過ぎません。それらの意義を本当に活かすには、開発者がどうしてそのような成果物が必要なのか、成果物を作成するためにそのような手順でなければならないのかを内側から理解している必要があります。

しかしそれにはスキルが必要です。

プロセスには従っているけれど内容はボロボロな設計書など、僕はいくらでもみたことがあります。

厳密なプロセスによってスキルの低い開発者でもある程度の品質のものをつくることができるという前提が間違っているのです。

そもそも品質とはユーザに納品される価値ですが、その価値の内容自体複数の要素が絡み合って状況に応じて変わる複雑な物です。
例えばバグ。もちろんバグは品質に関する重要な指標で、少ないに越したことはありませんが、開発のスピードや機能の豊富さ、価格もまた品質を構成する重要な要素です。
これらの品質を構成する要素の間にはトレードオフがあって、開発のスピードを上げようとすれば、バグは増えるし、機能も削らなくてはなりません。
そして開発のスピード、バグ、機能、価格の間の最適なバランスは作ろうとしているソフトウェアによって異なります。
例えば、原発の制御系のシステムであれば少しくらい納期が遅れてもバグが一つもないものが望ましいでしょうが、次期Windowsのリリースが2010年で価格が1CPUあたり50万円だったら嬉しいでしょうか?

実際には厳密なプロセスはマネージャが自分で責任をとらないための言い訳として機能していると思われます。
マネージャは自分で重要な判断を下したり、開発者に委ねるかわりにプロセスに従うことで次のような言い訳ができるようになります。

「確かに今回のプロジェクトはうまく行きませんでした。でも私は標準化されたプロセスに従っていました。だから私は悪くありません...」

結局のところ、厳密なプロセスが守るのは品質ではなくマネージャの心の平和なのです。

実際にアジャイル開発手法導入を説得する際にこれをいってしまうと感情的反発をくらってうまく行かないような気がするのが悩みどころです。

ASDの世界観

2004-07-14 01:38:22 | 開発手法/方法論
昨日の続きで、ASDの視点(=ジム・ハイスミスの視点)からみたソフトウェア開発の世界観について僕なりの解釈で紹介したいと思います。

かつて、ソフトウェア開発は極めて大規模かつ長期にわたっておこなわれていました。開発手法は今となっては伝統芸能の趣すらあるウォーターフォール型で、この官僚主義的なアプローチを記念事業的ソフトウェア開発と呼びます。

このやり方は当初それなりの効果をあげましたが、その時代は長く続きませんでした。強力なPC、C++やVisualBasicなどの新しい開発環境が登場し、コンピュータで出来ることの幅がひろがると、短期的なニーズに基づき、設計を重視せずいきなりコーディングを始める手法が広まっていきました。
これを場当たり的ソフトウェア開発と呼びます。重厚長大な記念事業的ソフトウェア開発ではツールの変化やビジネスの要求の変化に対応しきれなかったのです。
もちろん場当たり的なソフトウェア開発にも欠点はあって、保守性やコードの汎用性は犠牲にされていきました。
こうしてソフトウェアは官僚主義と場当たりの両極に分解していき、その状況は現在まで変わっていません。

ASDは両極のどちらでもなく、その中間の妥協案でもない第3の選択肢をとっています。それが複雑適応系理論に基づいた「創発的秩序」によるソフトウェア開発です。

現在の記念事業的的開発の創本山はSEIのCMMです。CMMにおいては反復可能、認識可能、測定可能なプロセスを最適化していくことがよしとされています。
これは製造業に例えると、ベルトコンベアで作業する作業員の歩数などをストップウォッチではかりながら効率をあげて行く作業などが想起されます。しかし、このやり方は、刻々とベルトコンベアのフローが変化して行くような状況では当然なりたちません。

ASDは現状のソフトウェア開発の多くがこのように変化の激しい複雑な環境におかれているということを前提にしています。
複雑な環境では、最適化という作戦はうまく働きません。

例えば将棋。

「将棋で勝つ手順」をCMM的最適化の手法で編み出すことは難しいでしょう。「初心者でも必ず勝てる将棋の手順」を定義するにはあまりにも考慮すべきパターンが多すぎるのです。ソフトウェア開発
が置かれている状況も同じくらい複雑だと思うのですが、「スキルのないエンジニアでも良いソフトウェアが創れる開発プロセス」を定義できると本当に信じている人が結構いるのは驚きです。

まぁ、本当にそんな開発プロセスがあるとしても適用分野はあらかじめ必要な技術もビジネスの要求もはっきり分かっていて要求の変化も少ないような案件にしか適用できない限定的なものとなるでしょう。銀の弾丸は存在しないのです。

では、そのような複雑さに人はどのように立ち向かっていったらいいのでしょう?

将棋は単純に手順化するには複雑すぎますが、そこには一定の秩序があります。一つ一つの駒の動ける範囲はきまっていますし、勝ちにつながる定石もあります。

ソフトウェア開発も同様に複雑なものではありますが、決してカオスではなく、将棋と同様そこには一定のパターンがあります。

ASDでは、このような複雑な状況のなかで、最適では無いけれどもベターな解を見付けようとします。この「ベターな解を見付ける」ということを「適応」と言っており、解を導くのにかかる時間の短さのために「最適」より「適応」の方が優れていると主張しています。

これはASDというよりすべてのアジャイル開発手法がベースにしている考え方のような気がします。

長くなってしまってので、続きはまた次回に回します。

設計は死んだか?

2004-07-08 01:30:47 | 開発手法/方法論
XPに対するよくある批判の中で、僕を悲しい気分にさせるのは「XPは設計をしない」というものです。
もっと悲しい気分にさせるのは、アジャイル開発手法が「設計をしない」ことの免罪符として使われることです。
「私らはずっとアジャイルでやってるんで。。。」とまともな設計をやっていないことを堂々と表明された日には、
もう絶望的な気分になってしまいます。

そんな人達に読んでもらいたいのは、マーチン先生の「Is Design Dead?」という論文です。

初稿は2000年ということもあって、目新しさはないですが
XPにおける設計の考え方が簡潔にまとまっています。

この論文のなかで、マーチン先生は
「XPは設計をしないのではなく、設計に対する考え方が違うのだ」
とはっきり述べています。
パターンもUMLも、XPにおいては大切なスキルなのです。

従来型のプロセスでは、開発プロセスの後半になるほど変更の
コストが指数関数的に増大するため、上流工程で要件をFixし、
未来の変更と実際のコーディング時に起こる問題を
予測して設計を行う必要がありました。

しかし、ビジネスの状況の変化に起因する要件変更は、
如何なる要求工学をもってしてもコントロール不能ですし、
コーディング時に発生する問題を全て前もって予測する事も
現実的ではありません。

この問題にたいするXPの解答は、
「テスト」「常時結合」「リファクタリング」の3つの
プラクティスによって変更のコストの指数関数的な増大を
回避するというものです。

ここで強調したいのは、XPで回避されるものは、

「未来の変更を回避するための過剰な設計」であって、「設計」そのものではない

ということです。「シンプル設計」というプラクティスを忘れてはいけません。
XPにおける「シンプルなコード」の基準とは

・全てのテストを通過し、
・プログラマーの意図が明確であり、
・重複したコードがなく
・最小限の数のクラスとメソッドで構成されていること

です。

パターンの力を借りずにどうやってこのシンプルさを保つのでしょうか?
UMLを使わずに、どうやってこのシンプルさを実現するための方法について
他のプログラマーとコミュニケーションするのでしょうか?


アジャイル開発手法と契約

2004-07-06 01:17:06 | 開発手法/方法論
アジャイルな開発手法を採用するにあたって障害となることの一つには、契約の問題があると思います。
アジャイルソフトウェア開発宣言では、契約よりもユーザとの協調を重視していますが、仕事をしてお金をもらうからにはやはり何らかの契約は必要になると思われます。

ここで、あらかじめ仕様をすべて明白にしてコーディングと単体テストの作業のみをビジネスパートナーにお願いするような契約の結び方は当然論外と言えます。

ある程度仕様を詰めながら順次コーディングをして、少しずつシステムを組み立てて行くようなアプローチが必要になるのですが、一般にコーディングと設計の工程が完全に分かれていることを前提にした契約形態をとっている会社ではこのような柔軟なやり方を取るのが非常に難しい。

全てを設計工程の契約のなかで行ってしまうというのが手っ取り早いのですが、設計に携わるエンジニアの方が普通単価が高いので、
これをやると全体的に費用がかかりすぎてしまいます。

かといって開発一括請負という枠組のなかでは、下請法などの制約が厳しくて柔軟に仕様変更を行うことができません。

結局元請けと下請けが両方得をするには1人月いくらという契約のなかで少し一人あたまのお値段をディスカウントしていくしか方法がないような気がしているんですが。。。
そうすると、いままで1k stepいくらとかいう良く意味のわからない契約で開発を請け負ってきた会社からはいくら頑張っても同じお金しかもらえんという文句がでそうですし。。。

むずかしいですね。

AspectJでDbC(サンプル2)

2004-07-04 23:46:41 | 開発手法/方法論
前回紹介したコントラクトをもとにStackインターフェースを実装したコードを紹介します。
package sample.dbc;

import java.util.ArrayList;

/**
 * Stack.
 */
public class StackImpl implements Stack {
    private ArrayList stack = new ArrayList();

    public int size() {
        return stack.size();
    }

    public void push(Object o) {
        stack.add(o);
    }

    public Object pop() {
        int idx = stack.size() - 1;
        //ポイント1
        if(idx <0) {
あらかじめコントラクトが決まっていることで、ポイント1のような箇所でNullを返すのか例外を投げるのかといったありがちな実装上の迷いがなくなります。次に、JUnitのテストケースを一部ですが紹介します。
    /**
     * testPop2.
     */
    public void testPop3() {
        Stack s = new StackImpl();
        s.push(new String("foo"));
        s.push(new String("bar"));
        s.pop();
        s.pop();
        s.pop();
    }

見て分かる通り、アサーションのコードが一切ありませんね。
このテストケースはあらかじめ前回紹介したAspectJによるコントラクトがWeavingされていることが前提となっています。ですから、実際にはStackImplの呼び出しの前後に事前条件と事後条件のチェックのコードが挿入されることになります。

今回紹介したのは、本当にシンプルなケースです。現実に運用されるシステムはもっと複雑ですし、開発者のスキルの問題などもありますから、実際の開発にAspectJによるDbCを適用するには、もっといろいろなノウハウを蓄積していく必要があると思います。

AspectJでDbC(サンプル)

2004-07-02 00:25:26 | 開発手法/方法論
今日は、AspectJでDbCを実際にちょろっとやってみたサンプルを紹介したいと思います。サンプルとして簡単なスタックの実装を考えてみました。
以下のようなインターフェースがあるとします。

package sample.dbc;

public interface Stack {
    /**
     * スタックのサイズを返す.
     */
    int size();
    /**
     * スタックに引数のオブジェクトをPushする.
     * @param o Pushするオブジェクト
     */
    void push(Object o);
    /**
     * スタックからオブジェクトをpopする.
     */
    Object pop();
    /**
     * スタックの一番上のオブジェクトを返す.
     */
    Object peek();
}
特に説明する必要も無いですね。
このインターフェースに対するContractをAspectJで記述すると以下のようになります。

package sample.dbc;

import junit.framework.Assert;

public aspect StackContract {
    declare parents: StackContract extends Assert;

    /**
     * Invariant.
     */
    after(Stack s) : !within(StackContract) && target(s) && call(public * Stack.*(..)) {
        assertTrue(s.size() >= 0);
    }

    /**
     * Stack#push.
     */
    void around(Stack s, Object o) : target(s) && args(o) && call(public void Stack.push(Object)) {
        //@pre
        assertNotNull(o);

        //@post
        int oldsize = s.size();
        proceed(s, o);
        assertEquals(oldsize + 1, s.size());
        assertSame(o, s.peek());

    }

    /**
     * Stack#pop.
     */
    Object around(Stack s) : target(s) && call(public void pop()) {
        //@post
        int oldsize = s.size();
        Object oldpeek = s.peek();
        Object rv = proceed(s);
        if(oldsize > 0) {
            assertSame(oldpeek, rv);
            assertEquals(oldsize - 1, s.size());
        } else {
            assertNull(rv);
            assertEquals(0, s.size());
        }
        return rv;
    }
}

事前条件、事後条件のチェックをJUnitのAssertクラスを使って行っています。ですから、このアスペクトをWeavingしてテストすれば、JUnitのテストケースにはアサーションのコードを一切書かなくて良くなります。
JUnitでは一般的に一つ一つの入力データに対する具体的な結果を検証するのに対し、DbCでは一般的なルールとして記述するので、記述自体の難易度はDbCの方が難しいです。しかし、クラスの仕様としての明解さ、厳密さはこちらの方が上だと思います。

よく言われるJUnitのメリットの一つに、テストケースからクラスの使い方が分かる、というのがあります。しかし、テストケースからクラスの使い方を知る、という作業は、具体的な入力値と出力値から一般的な仕様を頭の中でリバースエンジニアリングする作業だと思います。DbCにおいては、記述されるのは仕様そのものなので、より直截なアプローチだと思います。

次回は、Stackの実装とJUnitテストケースを紹介します。

AspectJでDbC

2004-06-30 01:49:37 | 開発手法/方法論
Design by Contractは古くて新しい技術です。結構前から提唱されてる概念で、実践してみるとものすごく効果があるのになかなか世の中に広まっていかないのは、おそらく一つは厳密なContractを書くのがあまりにもめんどくさいということと、ツールが充実していないということがあると思います。
Eiffelの様に言語自体にDbCの機能が組み込まれている言語ならいざ知らず、JavaでDbCを実践しようとするのは大変です。JDK1.4からは一応assertキーワードが使えるようになってますが、単純に式がtrueかどうかをチェック出来るだけというのはあまりにもシンプルすぎる気がします。
JavaでDbCを実践できるツールとしてはJML
を試そうとした事がありますが、日本語がうまいこと通らない等の問題があって挫折しました。(2004/3月時点)
以前、 JavaDocに自然言語ベースでContractをがりがりと書いてDbC的なことをやったこともがあるのですが、その時はJUnitのテストケースのコーディング量が本体の3倍くらいになって、あやうく開発メンバーを殺すところでした。アサーションのコードをいちいち書くのがめちゃくちゃめんどくさいのです。やはりツールのサポートは不可欠のようです。

いろいろ考えた結果、最近ではAspectJを使ってAspectとしてContractを記述するのが良いのではと考えるようになっています。
JMLと比べて、AspectJが良いとおもった理由はいくつかあります。

1.柔軟性 - おそらくどのようなチェックでもかけられる。またContractと本体のコードは完全に切りはなせるし、必要に応じてアサーションをいれたり外したりも自由。
2.メジャー度 - JMLなどに比べて使ってる人が多くて安心。
3.開発環境-Eclipse AJDT等が使えて便利
4.明解さ:アスペクトとして定義されたContractがどのようにWeavingされるかが、明解に定義されている。Weavingのされ具合を視覚化するツールも充実している。JMLではどのようにアサーションコードを入れ込んでいるのか、謎。

とりあえず簡単なサンプルを作って動かすところまではできてるで、次回こそはそれを紹介したいと思います。