2011年1月30日日曜日

C#での例外処理コードの基本

C#コーディングで例外をどう扱うか。

普通はこうなる。
<A.防止可能か?>
├─(yes)─→ [B.防止するコードを書く]
(no)
└→<C.予見可能か?>
├─(yes)─→ [D. catch して処理するコードを書く]
(no)

[E. スルー]


A. 防止可能か?
例えば、「パラメータで null を渡されたら ArgumentNullException を投げる」ってドキュメントに書いてあったり、ソースコード上自明もの(バグも含む)だったり、例外発生の条件が分かっていて、そうならないようなコードを書ける場合は、防止可能と言う事になる。

B.防止するコード
A を満たす場合に、例外を発生させないようにコーディングする。

C.予見可能か?
防止できず、つまり実行するまで分からないが、状況によっては発生する事が分かっている例外状況を、「予見可能である」とする。例えば、ファイルを開くときの FileNotFoundException など。

D. catch して処理するコード
C で可能性が認められた例外については、catch してハンドリングするコードを書く。

E. スルー
防止も予見もできないものについては、復旧処理のしようも無いので、無理にアプリを動かし続けて誤動作による事態悪化を招くより、スルーしてアプリが停止するに任せる。書いてもせいぜい、AppDomain の UnhandleException イベントくらい。

この手順は、以下の URL で FxCop の開発者が詳説していたりもする。
http://blogs.msdn.com/b/codeanalysis/archive/2006/06/14/631923.aspx

まあ、普通のプログラマにとっては、いつも実践している通りの、言われるまでもない当たり前のコーディングじゃないだろうか。今更感満載で、「他にやり様あったっけ?ないでしょ?」てな感じになっちゃうと思う。

で、これを踏まえた上で、例えば、メソッドの API リファレンスに例外が沢山書いてあったらどうしようとか、catch 節もちゃんとテストしましょうだとか、finally を活用しましょうとか、いろいろな細かい事が生じてくる。

====
というのが、普通に計算機科学を勉強して、普通にプログラミングを習得して、普通にC#を書いてる人の自然なコーディングプラクティスだと思うのだけど、底辺プロジェクトでは、この基本フローの段階で物言いがつく事がある。

曰く
「うちのアプリは何があっても落とさないポリシーだから、E のスルーは容認できない。未知の例外はもみ消して無かった事にするのが我々の流儀である。」と。

・・・いや、それ、マジで言ってんのかと。

次は、これについて考えてみる。

2011年1月29日土曜日

パターンカタログの私的ランキング(TOP 20)

1位から10位までは前回書いた、独断と偏見によるパターンのランキングを、20位まで続けてみる。

1位 GOFのパターン (100.0)
2位 PoEAA (89.6)
3位 Effective Java (86.4)
4位 CodeSmell (85.3)
5位 xUnitパターン (82.8)
6位 アンチパターン (81.3)
7位 POSA (79.1)
8位 Effective C# (77.9)
9位 アナパタ (69.5)
10位 Enterprise Integration Patterns (67.7)

11位 Implementation Patterns
ベック の smalltalk イディオムの古典 SBPP をベースに、言語を Java に代えて内容を調整したもの。個人的にはもっと普及しても良いと思うのだが。

実用度有名度使い勝手教養度面白さポイント
4233467.4


12位 Portland Pattern Repository / Wiki Wiki Web
元祖 wikiwikiサイト。カタログとしてはイマイチ使いにくいが、有名人たちの過去の議論が読めたりして、意外とおもしろい。

実用度有名度使い勝手教養度面白さポイント
2415464.9


13位 『パターン言語』
PLoP のパターンの選集、『プログラムデザインのためのパターン言語』に掲載のパターン。ここでも挙げている他のパターン集に含まれているものが多い。

実用度有名度使い勝手教養度面白さポイント
2254264.1


14位 Patterns for Effective Usecases
同名の書籍より。ユースケース・ライティングの記念碑的傑作『Writing Effective Use Cases』に書いてある内容の焼き直しがほとんどだが、パターン仕立てになっているのが良い。

実用度有名度使い勝手教養度面白さポイント
4241263.5


15位 SOA Patterns
ネットで見られる良質な SOA のパターン集だが、不勉強にも、最近まで気づかなかった。これはいい感じ。 → [URL]

実用度有名度使い勝手教養度面白さポイント
3342363.4


16位 Core J2EE Patterns
Java EE x が J2EE だった昔のエンタープライズ・アプリのパターン集。今、読み返しても、意外と古くさい感じはしない。→[URL]

実用度有名度使い勝手教養度面白さポイント
2443263.4


17位 Patterns for Test-Driven Development
ベックの傑作『Test-Driven Development』の PART3。TDD のためのパターン集が収められている。

これに限らずベックのパターン集は、パターンやプラクティスや単なる基本用語が、境界がよくわからないまま並列に解説されていて、カタログとしてはどうかと思うが、不思議と違和感無く読めて面白い。

実用度有名度使い勝手教養度面白さポイント
4322363.1


18位 コプリエンのイディオム本
イディオム・カタログの発祥とも言われている『C++プログラミングの筋と定石 』より。かなり古い本だが、これにもアンチ・イディオムが載っていて、当時の書評でもこれが重要って事で指摘されていた。

実用度有名度使い勝手教養度面白さポイント
2424361.7


19位 Workflow Patterns
workflowpatterns.comで紹介されている、ワークフローのパターン。通常、パターンというと問題に対する解の事を指すが、これはどちらかというと解というより問題の方の定形って感じ。このうちの基本的なパターンは BPM の試験でも問われる。

実用度有名度使い勝手教養度面白さポイント
2342461.6


20位 Data Model Patterns
アナパタでも参照されている分析レベルのモデリングの古典、『Data Model Patterns: Conventions of Thought』より。アナパタ同様、これも図法がとっつきにくいが、自分でUMLなどを使って分かり易い図に起こすと理解が進む。

実用度有名度使い勝手教養度面白さポイント
3233359.3


★ ついてでに20位圏外


Smalltalk Best Practice Patterns
(58.2)
言わずと知れた smalltalk イディオムの古典的名著。いろんな記事とか本とかから引用されていて教養的価値が高いけど、差し当たり仕事では smalltalk を使わない事もあり圏外。

Enterprise Solution Patterns (57.8)
ちょっと古いが、良く体系化されている。なのに何故かイライラする。理由は不明→[URL]

Effective C++ (55.7)
Effective C++: 55 Specific Ways to Improve Your Programs and Designs
Effective ナントカの C++版。最近、C++の案件やってないなあ・・・

Ajax パターン (53.7)
Ajax Design Patterns
文字通りAjax のパターン。Ajax そのものの勉強にもなる。

J2EEアンチパターン (46.8)
J2EEアンチパターン
この手のパターンは陳腐化しやすい。

EJB Design Patterns (45.1)
EJB Design Patterns: Advanced Patterns, Processes, and Idioms
これも Java の EoD 運動以前のものだから、さすがに古い。

EJBアンチパターン (44.6)
EJBアンチパターン
これも EJB Design Patterns と同様古い。

AOPパターン (43.3)
Aspectj in Action』に掲載されている AOPパターンと AspectJイディオム。そこそこ面白いが、まだ数も少なく未成熟。

以上、「物」と「事」でいうと、「物」的なパターンを特に選び、「事」性が強い リファクタリングやプラクティスは入れないことにした。

今回のは洒落で作った私的な順位だけど、工夫すればもっと客観的な点数付けができると思う。そうしたらスキル評価の尺度として、開発要員のアサインや調達の際に、ちょっと使えるかも。

つうか底辺プロジェクトでは、GoF すら覚束ない人が多数派なので、切なくなってくるが・・・

パターンカタログの私的ランキング(TOP10)

パターン・カタログ=GoFのデザパタだと思ってる人をたまに見かけるが、実は結構、他にもたくさんある。

以下、勝手に作ったパターンカタログのランキング。飽くまでも私的で主観的な尺度でポイントを付けた。

1位 GOFのデザパタ
言わずと知れたデザインパターンのバイブル、『オブジェクト指向における再利用のためのデザインパターン』掲載されている、23のパターン。まずはこれが基本かと。
実用度有名度使い勝手教養度面白さポイント
55555100.0


2位 PoEAA
エンタープライズ アプリケーションアーキテクチャパターン』に掲載されている、いわゆる PoEAA (Patterns Patterns of Enterprise Application Architecture)。2000年代初頭までのオブジェクト指向システム開発の流れを総括した上で、現在に至るその後の展望を示したパターンの金字塔。さすがに、もうそろそろ、若干の陳腐化が見られなくもないが。

実用度有名度使い勝手教養度面白さポイント
4545589.6


3位 Effective Java
Effective Java (2nd Edition)』掲載の Javaコーディングイディオム。Java プログラマは必携・必読かと。

実用度有名度使い勝手教養度面白さポイント
5533586.4


4位 CodeSmell
ファウラーの『リファクタリング本』に載っているアンチパターン。リファクタリング手法そのものより、むしろこっちの方が重要だと思う。

実用度有名度使い勝手教養度面白さポイント
5434585.3


4位 xUnitパターン
xUnit Test Patterns』で紹介されている UnitTesting のパターン。XUnitPatterns.comでも閲覧可能。これもアンチパターンの部分が重要。

実用度有名度使い勝手教養度面白さポイント
5434482.8


6位 アンチパターン
AntiPatterns』掲載の、定番のアンチパターン集。ちょっと古いが、コーディングや設計に止まらず、プロジェクト管理などにも渡る広めのスコープをカバー。

実用度有名度使い勝手教養度面白さポイント
3455481.3


6位 POSA
ブッシュマンの『POSA本』(Pattern Oriented Software Architecture)に載ってる、アーキテクチャパターンの古典。1巻しか和訳されていないので余り知られていないが、2巻3巻もある。いや、確か5巻くらいまであったかもしれない。

実用度有名度使い勝手教養度面白さポイント
3455379.1


8位 Effective C#
Effective C#』と『More Effective C#』に掲載の C#のイディオム。

実用度有名度使い勝手教養度面白さポイント
5432477.9


9位 アナパタ
ファウラーによる分析レベルのパターン集の古典『アナリシスパターン』。モデルの図法が若干とっつきにくい。

実用度有名度使い勝手教養度面白さポイント
2425569.5


10位 Enterprise Integration Patterns
Enterprise Integration Patterns』掲載のパターン。意外と知られていないが、ここで導入された図法、グレゴールグラムも含めて、EI 界隈では金字塔と言われるパターン集。SOA、ESBをやる人はほぼ必須知識に近いかと。

実用度有名度使い勝手教養度面白さポイント
3343467.7


→TOP20へ

====
★ 補足
上記のとおり、五つの評価軸について5段階評価して、ポイントに集計してランクをつけてみた。

・実用度は、仕事で役に立つかという観点。個人的な職歴によるバイアスがかかっている。したがって、仕事では使わない smalltalk や最近現場では使っていないC++に関連するものは、点が低かったりする。

・有名度は、各種の記事や著作から引用されてているのを目にしたり、同僚との会話の中に出てくる事が多いもの。これももちろん私的な環境に依存する。

・使い勝手は、主にカタログとしての質。書式・体裁や、粒度、識別し易さなど。またダイアグラムやサンプルコード、パターン間のナビゲーションなども。

・教養度は、他のパターンが前提的な知識として要求していたり、このパターンを知っていると他のパターンを理解し易いというもの。

・面白さは、文字通り面白いという事。知的好奇心を刺激されたり、可能性が開けていく感覚があったり、思わぬ気付きがあって興奮したりとか、そういうやつ。

評価軸自体にも、実用度に5点、有名度に3点、使い勝手に3点、教養度に2点、面白さに1点と言うように重みを付けた。

点の集計は、一応技術者らしくフィボナッチスケールを応用してみた。1~5の点数をフィボナッチをもとにした数列{21, 27, 34, 44, 55}に変換して総合点を集計し、オール5だったときに100になるように調整した。

2011年1月27日木曜日

ソフトウェア品質の対概念

プロがで自分の職能分野の事柄を wikipedia で調べる事となると、何となく気恥ずかしさを感じないでもないが、たまに良い事が書いてあってちょっと嬉しい時がある。

ソフトウェア品質Software_quality)」で調べると、ちゃんと「ソフトウェア製品品質Software_product_quality)」と「ソースコード品質(Source_code_quality)」に分けて書いてあった。

ソフトウェアに関しては、一般的な意味での品質ーーーつまり「日本の精密機械の品質は・・・」なんて言うときの「品質」とは別の、もう一つの品質があるという事が、実はわりと普通の考え方なのだという証言が一つ得られた事になり、少しほっとした。更に少し調べると、ISO/IEC 9126-1:2001でも「内部品質」という形で定義されているらしい。不勉強だった。

とは言っても、この二つの品質が互いに異なる別物だという考え方は、まだソフトウェア開発業界で常識となるには至っていないように見える。

開発中の製品の品質について会議なんかで議論すると、こっちが後者の意味で話しているのに、しかも、どういう意味での「品質」か、ちゃんと前置きしてから語っているはずなのに、いつの間にか前者の話に流れて行ったりする。終いには「”品質”の話をしてるんだから、コードとか関係なくね?」みたいに返してくるから、こっちも「だ~か~ら~」みたいになってくる。

大雑把に言うと、製品品質は売上に関わり、ソースコード品質は費用に関わる。つまり、製品品質は使う側の生産性を左右し、ソースコード品質は作る側の生産性を左右する。あるいは、製品品質の問題は消費者側で顕在化し、ソースコード品質の問題は生産者側で顕在化するとも言える。

ある意味正反対の概念が、「品質向上」などと言ったスローガンの下で一緒くたに扱われるから、品質管理会議が何だか噛み合わない。いっそ別の言葉でもあれば良いんだけど、日本語でも英語でも適切な言葉が見当たらない。

「今話している「品質」はソースコード品質の意味での「品質」なわけで、つまり(略)」みたいな面倒くさい断りを入れずに済む状況は、当分なくなりそうにない。

2011年1月26日水曜日

リファクタリングの因果ループ

リファクタリングの効果をシステム・シンキングで考えてみる

まず、もっとも近視眼的に原因 → 結果を考えるとこうなる。


+記号は、原因側の増加・強化が、結果側にプラスの効果をもたらす事を意味する。反対に、原因側の減少・弱化は、結果側にマイナスの効果を与える。-記号ならば、原因側の増加・強化が、結果側にとってのマイナスとなる。

つまり、上図ではリファクタリングの実施が開発工数の増加をもたらす事を表している。逆に言うと、重複やらスパゲティコードやらの放置も、直接的には工数を減少させるとも言っている。

これに、「ソースの体質」(ソースコードの読み易さ、書き易さ、使い易さ)と開発作業における「余裕」を付け加えて、因果関係のループを作ると以下の用になる。



要するに、短期的には工数増加をもたらすリファクタリングが、ループを繰り返すに連れて効力を増して、次第に工数を減少させていく様子を表しているが、これを説明してみたい。

解説のため、二つのループに分けると下図のようになる。


上のループは-が一個(奇数個)なので、バランス・フィードバック・ループになる。

つまり「リファクタする」→「工数増える」→「余裕が減る」→「リファクタさぼる」→「工数減る」→「余裕がでる」→「またリファクタする」→「・・・」という感じで、一周ずつ反転しながら繰り返して、適当な均衡点に落ち着いて行こうとする。

下のループは-が二個(偶数個)なので、拡張フィードバック・ループになる。

この場合、「リファクタする」→「ソースが改善される」→「だんだん工数が減ってくる」→「余裕が出る」→「もっとリファクタする」→「もっとソースが改善される」→「さらに工数が減ってくる」→「・・・」という自己強化的な繰り返しになる。

ただしソースの体質改善が開発工数に影響を与える際、遅延(上図のコンデンサー記号)を生ずるのが一般的なので、ループの勢いは最初は弱い場合が多い。

とは言っても、ループの効果は一方向的に増強されるのみなので、「リファクタ実施 → 工数増加」と言う短期的な効果を、いずれ結局は追い越す事になる。

というのが、システム・シンキングで理屈をつけたリファクタの効果。

※実は、ループによる効果の増加を待てないような使い捨て度の高いシステムでは、リファクタしたところで却って費用対効果が良くない事も、同時に示唆していたりする。

ちなみに、リファクタしない場合の悪循環は、「リファクタさぼる」→「体質悪化」→「じわじわと工数増大」→「余裕が減る」→「リファクタしようにもできない」→「もっと体質悪化」→「さらに工数増大」→ ・・・、と言った感じ。

2011年1月25日火曜日

GUI コードのUnitTest の例

こんな感じのしょうもないフォームがあるとする。 DataGridView があり、A列と B列は数値を入力できる列で、C列は A - B の計算結果を表示する。 さて、このフォームには、C列の値が負のとき赤で表示するという振る舞いがあるが、果たしてこれをテスト駆動で書けるだろうか? TDD に慣れた人なら、普通にテストファーストで書くだろうけど、ハナからできないと決め付けてる人も意外と多い。 そんな人が考えるテストはこんな感じ。
  • アプリケーションを起動する。
  • A列、B列に値を入力する。
  • C列の前景色が変わったことを確認する。
まあ普通の手動の動作確認と同じだけど、これを自動化テストコードとしては書けないから UnitTest は無理と言う。 実際にはそういったテストコードも書けないことはないが、TDD の UnitTest ではそんなのは書く必要ないし、第一、テストの観点も目的も手法も違ってるから、むしろ書いてはいけない。 前に書いた HumbleView の作法でやると、例えばこんな風になる。
[TestFixture]
public class Form2PresenterTest
{
    public Form2Presenter presenter;
    public Mock<IForm2> mock;

    [SetUp]
    public void SetUp()
    {
        this.mock = new Mock<IForm2>();
        var view = mock.Object;
        this.presenter = new Form2Presenter(view);
    }
    [Test]
    public void SelectStyle_Plus()
    {
        TestSelectStyle(10, 5, CellStyle.NonNegative);
    }
    [Test]
    public void SelectStyle_Zero()
    {
        TestSelectStyle(10, 10, CellStyle.NonNegative);
    }
    [Test]
    public void SelectStyle_Minus()
    {
        TestSelectStyle(10, 20, CellStyle.Negative);
    }
    public void TestSelectStyle(int a, int b, CellStyle style)
    {
        //arrange
        var rowData = this.presenter.RowDataAt(0);
        rowData.A = a;
        rowData.B = b;
        //act
        this.presenter.Update(0);
        //assert
        mock.Verify(v => v.SetGridStyle(2, 0, style));
    }
}
見ての通り、Update()メソッドで行のインデクス(簡単のため0固定とした)を受け取った Presenter が、更新された A 列とB列の値に基づいてスタイルを選んで、セルの位置とともにビューに返すという流れになる。 これを満たす IForm2 と Presenter のコードはこんな感じ
public interface IForm2
{
    //・・・略・・・
    void GridDataSource(List list);
    void SetGridStyle(int col, int row, CellStyle styleId);
}

public class Form2Presenter
{
    //・・・略・・・
    public void Update(int rowIndex)
    {
        var rowData = this.list[rowIndex];
        var cellStyle = rowData.C < 0 ? 
                CellStyle.Negative : CellStyle.NonNegative;

        this.view.SetGridStyle(2, rowIndex, cellStyle);
    }
}
やり方はいくつかあるが、ここでは色を System.Drawing.Color で直接指定する代わりに、列挙値 CellStyle を定めて使っている。この CellStyle 定数と実際にセルに設定する DataGridViewCellStyle オブジェクトのマッピングを保持しておくクラスも別途必要だが、自明なので省略。 この辺りまで書くとテストも通る。 後は、View と Presenter を関連付けるだけ。
public partial class Form2 : Form, IForm2
{
    //…略…
    private void dataGridView2_CellEndEdit(
        object sender, DataGridViewCellEventArgs e)
    {
        this.presenter.Update(e.RowIndex);
    }
    public void SetGridStyle(int col, int row, CellStyle styleId)
    {
        this.dataGridView2[col, row].Style = CellStyleMap.StyleOf(styleId);
    }
}
前回と同様、View オブジェクト(Form2)は受身で丸投げなクラスで、余りテストの必要性が高くないほんの少量のコードを残して、その他の振る舞いのコードを Presenter に移した。 こんな風に、一見いかにも GUI の最表層みたいな振る舞いでも、フォーム=View を薄く薄くしていく事で、妥当な網羅性を備えた UnitTest が書けるようになる。

2011年1月23日日曜日

CIのプラクティス

以下、『継続的インテグレーション入門』にのってるプラクティスのメモ

「始めよう」からのプラクティス
  • 変更を起点としてビルドを実行する
「CIの紹介」からのプラクティス
  • 頻繁にコードをコミットする
  • ビルドできないコードをコミットしない
  • ビルド失敗を速やかに修復する
  • 開発者テストを自動化する
  • 全てのテストとインスペクションを合格させる
  • プライベートビルドを実行する
  • ビルドが失敗したコードを取得しない

「変更を起点としたビルドの実行」からのプラクティス
  • ビルドを自動化する
  • コマンド1つでビルドを実行する
  • ビルドスクリプトをIDEから分離する
  • ソフトウェア資産を集中化する
  • 一貫したディレクトリ構造を作成する
  • 失敗しやすいビルドプロセスから始める
  • 複数環境へのデプロイに対応する
  • インテグレーションビルドマシンを使用する
  • CIサーバを使う
  • 手動インテグレーションビルドを実行する
  • 短時間でビルドを実行する
  • 段階的にビルドを実行する

継続的DBインテグレーションのプラクティス
  • DBインテグレーションを自動化する
  • ローカル環境でサンドボックスを使う
  • バージョン管理リポジトリを使ってDB資産を共有する
  • 開発者にDBを変更する権限を与える
  • DBAを開発チームの一員にする

継続的テストのプラクティス
  • 単体テストを自動化する
  • 結合テストを自動化する
  • システムテストを自動化する
  • 機能テストを自動化する
  • 開発者テストを分類する
  • 実行時間が短いテストを先に実行する
  • 不具合に対してテストを書く
  • 結合テストを再実行可能にする
  • 一つのテストケースに一つのアサーションを書く

継続的インスペクションのプラクティス
  • コードの複雑度を下げる
  • 継続的にデザインレビューを実施する
  • コード監査による組織標準の維持
  • コードの複製を減らす
  • コード網羅率を評価する

継続的デプロイのプラクティス
  • 動作するソフトウェアを常にリリースできるようにする
  • リポジトリの資産にラベル付けをする
  • クリーンな環境を構築する
  • 個々のビルドにラベルを付ける
  • 全てのテストを実行する
  • ビルドフィードバックレポートを作成する
  • リリースのロールバックを可能にする

継続的フィードバックのプラクティス
  • 継続的フィードバック手段を利用する

GUI コードのUnitTest の基本形

こんなフォームがあるとする。


ツールボックスからコントロールを持ってきて置いただけの状態だが、これを
右のボタンを押すとメッセージボックスが開いて、OK すると文字列"OK"、Cancel すると文字列"Cancel"が、左のテキストボックスに表示される
ようにしたい。

さて、この作業を TDD でやるとどうなるか。

GUI アプリは UnitTest できないものと考えがちな人は、やはりここでもメッセージボックスに伴うユーザ・インタラクションを理由に UnitTest を諦める。

実は、こういった場合の対処法は割と昔から研究されて、パターンとして広く知られているものも既にいくつかある。

基本的な方針は、最小限のコードを残して、振る舞いに関する責務をテスタビリティの高い別のオブジェクトに移動してしまうというもの。

そうやって、極薄にしたフォーム・コード(UnitTest はオプション)と、振る舞いを含む実質的な UI ロジック(カバレッジ100%)に分けることで UI 層全体としてのコード・カバレッジを満足のいくものにする。

いろいろな変種パターンがあるが、さしあたり以下のように単純に実装してみる。
  • Form1 = view
    • あくまでも受動的に動くフォーム・クラス。
    • Presenter の指示により MessageBox を表示するものの、何も考えずに結果を Presenter に返すだけ。
    • イベントは Presenter に丸投げする。ただし無駄なパラメータは渡したりしない。また、フォーム上のコントロールのプロパティへのアクセッサを、必要最小限な分だけもつ。
  • Form1Presenter = presenter
    • 次のような UI の振る舞いを担う。
      • View にメッセージボックスを表示させて、結果を受け取る。
      • 受け取った結果に応じた文字列を View に表示させる。

また、Presenter から Form1 へのアクセスは、以下のようなインターフェイスを通じて行う。
public interface IForm1
{
string ResultText { get; set; }
bool AskOkOrCancel();
}
※Presenter も interface を実装するような形にもできるが、オプション。

まずは先にテストコードから
[TestFixture]
public class Form1PresenterTest
{
private Form1Presenter presenter;
private Mock<IForm1> mock;

[SetUp]
public void SetUp()
{
this.mock = new Mock<IForm1>();
this.presenter = new Form1Presenter(mock.Object);
}
[Test]
public void HandleButtonClick_OK()
{
TestHandleButtonClick(true, "OK");
}
[Test]
public void HandleButtonClick_Cancel()
{
TestHandleButtonClick(false, "Cancel");
}
public void TestHandleButtonClick(bool isOk, string resultText)
{
//arrange
mock.Setup(v => v.AskOkOrCancel()).Returns(isOk);
//act
presenter.HandleButtonClick();
//assert
mock.VerifySet(v => v.ResultText = resultText);
}
}
※モックはMoqを使った
  • ビューに聞いてこさせたユーザの意図(isOk)に応じて、期待通りの文字列(resultText)が選択され、ビューに設定されることを検証している。
  • 見ての通り MessegeBox もコントロール・オブジェクトも関係ないコードになっている。
  • 実際には、いっぺんにテスト・コードを書いてしまわないで、ちょこっとテストを書いては本体コードを書くというような形になる。
で、その本体コードは以下
public class Form1Presenter
{
private readonly IForm1 view;
public Form1Presenter(IForm1 view)
{
this.view = view;
}
public void HandleButtonClick()
{
this.view.ResultText =
this.view.AskOkOrCancel() ? "OK": "Cancel";
}
}

ここまで書けば取りあえずテストが通る。あと残ったのは、放置していた Form1 を含む Presenter との連携コード。

こんな感じでフォームを実装する。
public partial class Form1 : Form, IForm1
{
private Form1Presenter presenter;

public Form1()
{
InitializeComponent();
}
public bool AskOkOrCancel()
{
return DialogResult.OK == MessageBox.Show(
"OK or Cancel", "", MessageBoxButtons.OKCancel);
}
public string ResultText
{
get { return this.textBox1.Text; }
set { this.textBox1.Text = value; }
}
internal void Attach(Form1Presenter presenter)
{
this.presenter = presenter;
}
private void button1_Click(object sender, EventArgs e)
{
this.presenter.HandleButtonClick();
}
}
この他、フォームを表示するところ(Program.csあたり)で、view を Presenter と関連付けるコードが必要だが割愛。

こんな風に、実フォームでは MessageBox.Show() 等のユーザ・インタラクションと、コントロールへの必要最小限のアクセッサのみを書く。

なんだか、もとのお題が小さすぎるから、コードを切り出したにもかかわらずフォームのコードが増えてしまっているが、実際の業務要件を満たすようなフォームだと、イベント・ハンドラに全部書くようなスタイルよりスッキリしたコードに、ちゃんとなる。

こうしたフォーム・コードは、コード量も多くならないし更新の度合いも少ないし、テストの必要性はそれほど高くない。UnitTest を省略していい部分だと思うが、どうしても DeveloperTest を書きたければ TypeMock か Moleを使えばいい。後付でも問題ないし、テスト・コードも極簡単なものですむ。

さらにフォームのコードを少なくするやり方もあるが、次の機会に。

2011年1月20日木曜日

GUI アプリのフォームの UnitTest

UI 層のオブジェクトの UnitTest は簡単じゃない。
それは否定しない。

ただ、確かに一定の難易度があるにはあるけど、それを何とかする工夫が、かなり昔から研究され、いくつかはパターンとして提唱されて既にかなり広く知れ渡っている。


それにも関わらず、巷の底辺プロジェクトでは、未だに「GUI 層に関しては専用の UI テスト・ツールでも使わない限り、UnitTest は不可能」なんて迷信が未だに根強い。(UI テスト・ツールを使ったテストを、UnitTest の代替物と考えている時点で駄目なんだが・・・)

まあ、4・5年前までは雑誌とかでもそんな感じで言われてたし、未だにその頃の記事が技術系のサイトで閲覧できてたりするから、悪習が減らないのはそういった陳腐化した情報のせいもあるかもしれない。

困った事には、そうした底辺プロジェクトでは何でもかんでも UI 要素のイベント・ハンドラ・コードに書いてフォームを巨大化させるのが常だから、全ソースの半分以上がフォームのコードだったりする。

その上更に、大半の仕様変更がフォームにも影響を与えるものだったりするから、更新回数でいうとフォームのソースが 9割くらいにも達する。そういった、本来は最も UnitTest コードを書くべき部分でサボっておいて、大して変更頻度も高くない部分のカバレッジについて上がったの下がったの言ってるのを現場で見ていると、何とも切なくなってくる。

取り合えず、まず基本はフォームのコードを分割する事。

ユーザ・インタラクションや Windows のメッセージループが必要になる層(以下、View と呼ぶ)と、そうでない層に分ける。View をどこまで薄くするかという技法上の選択肢はあるが、とにかく薄くする。で、残りの部分について、View のインターフェイスに対しておもむろにモック・ツールを適用して、あとは普通に xUnit を使う。

ここまででも UnitTest としては、そこそこの網羅率になる。更にカバレッジを完璧に仕上げたかったら isolation ツール(.net なら TypeMock や Moleなど)を使えば、View についても UnitTest が書けるが、これはオプションと考えて良いと思う。

後で、実際のコード例を挙げてみる。

2011年1月18日火曜日

JSTQB認定テスト技術者資格試験のシラバス

去年の夏の終わり頃、JSTQB という団体が認定するテスト技術者資格の試験を受けた。

Foundation Levelという事で、上級者向けの Advanced Level (まだ始まっていない)とはおそらく違ってそれほどハードルは高くなく、プロならほとんどが受かる難易度だと思う。勉強の材料は、JSTQB のサイトで配布されているシラバスを使った。これをよく読めば大体受かるはず。

実は、このシラバスがすごく良く出来ていて、受験者だけが読むのでは少しもったいない気がした。

短い分量に、用語、基礎知識、各種テクニックから教訓まで、非常に上手くまとめられている。

テスターはもちろんの事、開発者から PM、仕様担当者まで、広めの範囲の関係者一同で読み合わせて、認識を共有したりすると良いと思った。

2011年1月17日月曜日

コピペ・プログラミングの善悪の境界

コピペ・プログラムは悪い事だと言われる。

コピペ・プログラマは駄目人間だとも言われる。

一方で、実際の現場ではコピペ・プログラミングは現実によく行われている。

リーダが「追加が決まった例の機能は、コピペで済むからラッキーだね」なんて言って、PM と一緒に嬉しがったりする。

当のプログラマも、「任務遂行のためならコピペも辞さない俺って、なんて冷徹なプロだろう」てな感じで、どこか得意げだったりする。

どう言う事か?コピペは良いのか悪いのか。

より正しく言うと、悪いのはコピペ自体ではなく、コピペにより生ずる重複コードの放置だと言える。古来より、共通コードはサブルーチン化すべしと言われてきたし、近年においても Merciless な Refactoring が強く推奨されている。

要は、結果的に重複が解消されて、保守性が下がる事もリスクが増える事もなくなれば、コピペそのものは別にどうって事ない。

もちろん現場の緊急事態においては、コピペ解消に要する数分~数十分を惜しんで保守性を犠牲にしリスクを高め、従って後になって無駄にコストばかり膨れ上がるという高利の負債を受け入れてもなお、一時も早くコミット/リリースせざるを得ない状況もある。

しかしだからと言って、TODO コメントで重複コードである旨を表示して、後続のプログラマの注意を喚起するくらいの事ができないわけはない。

それすらやらないという事こそ、もう言い逃れのできない不作為、無知、鈍感と言わざるを得ない。プログラムの仕事が分かってないという事になるのではないか。

★まとめ
  • コピペしない ← OK
  • 作業の流れで一旦コピペしても、重複は残さない ← OK
  • やむを得ず重複を残したが、他人が怪我しないように手は打った ← ギリOK
  • コピペでコードを重複させましたが、何か? ←


★豆知識
  • かなり古い本だが『AntiPatterns』でも、"Cut-And-Paste Programming"として、Clipboard Coding、Software Propagationといった別名と共に紹介されている。
  • Refactoring』 では、Code Smellのうちの"Code Duplication"として紹介されている。
  • 以下、元祖 wikiwiki から
    • OnceAndOnlyOnce:「書くべきコードは一度だけ、ただ一度きりのみ書きましょう」と言う、おそらく最も有名な重複防止の標語。
    • Refactoring Mercilessly:昔から XP で言われているプラクティス。特にコードの重複の解消を念頭においていると考えても良い。
    • Duplicated Code:言わずと知れたコードの重複。CodeSmell(駄目なコードの兆候)の最たるものとされている
    • Copy And Paste Programming:ずばり今回のテーマ。冒頭で一応、プログラミング手法の一つとして中立的に紹介された後、なぜこれが駄目なのかと延々と批判が続く

2011年1月16日日曜日

アジャイル・ワナビーの観察 1

Agile Manifestoover を挟んで左辺と右辺を対置し、右辺より左辺に高い価値を置くという形式になっている。

Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan

ただし原文を読むと分かるとおり、右辺の価値を認めた上で更に左辺の方がより重要だと言っているわけで、右辺を害悪や無価値なものと断じているわけではない。だから共にプラスの価値とした上での比較論、バランスの問題とも捉えられる。

従って、右辺の重みを減らすなら、少なくともその効用が減少した分以上は、左辺に由来する効用によって補償されていなければならず、でなければプロジェクトに負の影響が生じてしまう。

さてアジャイル開発者とは、投下したコストから得られる効用の比率が、右辺より左辺の方が高いと考える人であり、その具体的な手法を提示しているのが各アジャイル・プロセスといえるだろう。

但し、その手法=プラクティスは旧式の開発作法に比べ簡単だとは一概に言えず、それなりの知識と理解はもちろんの事、練習や工夫、或いは集中力が求められたりする(開発者としてはやり甲斐があるが)。

ところが、よくあるワナビな現場やプロジェクトでは、左辺の効力を増加させるための努力によってではなく、単に右辺を等閑視する事によってアジャイル開発になる(=生産性・品質が向上し変化に迅速に対応できる)なんて短絡的に勘違いしている人が未だに多い。

以下、個別に見てみる。差し当たり、左辺に関するプラクティスの巧拙については割愛し、右辺がなおざりにされる状況だけを記述する。

プロセスが閑却されるケース
今時、ルールでガチガチに固めた単に監査のためだけにしかならないような重量プロセスもどうかと思うが、軽量プロセスって言葉もあるとおり、アジャイルだからといってプロセス不要って事にはなるわけがない。

にも関わらず、なんちゃってアジャイルな現場では、この肝心のプロセスすら無視される。むしろ完全にその場しのぎの行き当たりばったりの仕事が「臨機応変」とさえ捉えられてしまう。

で、たまに組織の上層部の思いつきで、「暫定」標準プロセスが適用されたりするが、長引くデスマの中で有耶無耶にされ、反省も(従って改善も)されないから、永遠に「下手の考え休むに似たり」の悪しきオリジナリティから卒業できない。

反復型なのか非反復型なのかも判別できない、グダグダでノッペリした開発作業が、終わりの見えないまま続いたりする。

(tools に関しては「ツールを減らせばアジャイルに近づく」的な勘違いは、特に見られない。但し、いわゆるアジャイル系・ツールの誤用・過信は非常に多い。これは、ここでのテーマと違うので割愛。)

文書が閑却されるケース
文書の方が有効なコミュニケーション場面ですら、口頭=喋りで全てを伝えたがる悪癖に染まった現場も多い。伝える側は、無駄な文書化の手間が省けたと最初は思うが、何度も別の相手に同じ事を伝えている事に気づいて、初めて愚策だったと悟る(鈍感な人は、それすらいつまでも気づかないが)。

また、後のリファクタ・軌道修正が困難な箇所の設計すら個人の脳内で完結し、"Working software" が出来上がって来るまで他人のチェックが入らないため、後で一同頭をかきむしる事になるのもこのケース。(そもそもワナビな現場では、ユニットテストが後回しで、CIもロクに実現されていないから、そもそもアジャイルの意味での"Working software"と言えるのか疑問でもある。)

顧客交渉が閑却されるケース
最低限の契約交渉すらないというのは、つまりプロジェクト初期においては単なる安請け合い、末期には単に怒った顧客の言いなりに過ぎないケースがほとんどで、「協働」の本来の姿とはかけ離れている。

初期の交渉がテキトーだから、気が付いたときには既に顧客はイライラあるいは激怒し始めており、理性的にスコープを定める事ができなくなっていたりする。結局はプロジェクト外の上層部の長が出向いて、改めて不利な立場で交渉せざるを得ない羽目に陥る。

計画が閑却されるケース
ここまで記述してきたような、プロセスもなくスコープも定まっていないプロジェクトだと、従うべきプランなんて存在しようもなく、その場その時のアドホックな状況に反射的に反応しているだけとなる。

一応、後の変更を前提とした暫定プランが策定されたりもするが、ノウハウの蓄積の無い未熟な現場では合理的判断の根拠も無く、単なる思考停止の所産だったりする。


・・・というのが wannabe agile な現場でよく見かける愚行の一端。

====
http://agilemanifesto.org/を見ると 2001 とあるから、そろそろ10年になるらしい。

既にアジャイル・プロセスを導入して成功している現場に定住している人から見ると、上述のような現場が未だにあることに驚くかもしれないが、一般的には意外と多い普通の状況だったりする。自分もリーマンショック以降、初めて知る事になったわけだが・・・。

C# のアンチイディオム

ソフトウェア開発の様々なテーマについて、それぞれパターンやイディオムやベストプラクティスがあるけど、まずはアンチパターンを避ける事が優先度が上で順序も先だと常々思う。

というわけで、書いてはいけない C#コードを『Effective C#』と『More Effective C#』から抜粋してみた("m"が付いた番号が "More"の方)。

Item 09: Avoid Conversion Operators in Your APIs
  • 変換演算子の定義は避ける事。

Item 26: Avoid Returning References to Internal Class Objects
  • オブジェクトが保持している別のオブジェクトを外に晒すのは避ける事
  • 特にコレクションなんかで、C#に限らず散々言われ続けてきた悪いコーディング

Item 16: Avoid Creating Unnecessary Objects
  • 無駄なオブジェクトの生成を避ける事
  • 文字列の構築での string の使用 ⇒ StringBuilder を使う事
  • 高頻度で呼ばれるメソッド内でのオブジェクト生成 ⇒ メンバ変数や定数への格上げを検討する事

Item 32: Avoid ICloneable
  • ICloneableの実装は避ける事
  • パッと見の印象ほどには意外と使えないインターフェイスだったりする
  • どうしても使うときは、基底クラスでコピーコンストラクタを定義した上で、sealed クラスのみで使う事。

Item 33: Use the new Modifier Only to React to Base Class Updates
  • new モディファイアの使用は避ける事
  • 外部のライブラリに含まれる基底クラスの変更により、それを継承している派生クラスで定義の衝突が生じるような稀なケースなどもあるが、そのときでもなるべく避ける事。

Item 34: Avoid Overloading Methods Defined in Base Classes
  • 基底クラスで宣言されたメソッドをオーバーロードするのは避ける事
  • こんなコードで、、、
    class B1 {}
    class D1: B1 {}
    class B2 { void Foo(D1 p) {...} }
    class D2: B2 { void Foo(B1 p) {...} }
    、、、D2.Foo() に D1 オブジェクトを渡すと、どっちが実行されるか意外と迷う。更に generics が絡むともっと面倒になる。

Item m07: Do Not Create Generic Specialization on Base Classes or Interfaces
  • generic メソッドを特化するオーバロードは避ける事
  • 例えば以下のようなコードで、、、
    class Base {}
    class Derived : Base {}
    class Foo {
    public static void DoSomething(Base b) { ... }
    public static void DoSomething(T b) { ... }
    }
    、、、DoSomething() に Derived インスタンスを渡すとどちらが実行されるか、意外と分かりにくい。DoSomething(Base b)を加える代わりに DoSomething(T b)の中で型チェックをすると、分かり易さも使い勝手も向上する。

Item m33: Avoid Modifying Bound Variables
  • クロージャの中でのローカル変数の変更は避ける事
  • 遅延実行絡みの分かりにくいエラーが生じやすい

Item m35: Never Overload Extension Methods
  • 拡張メソッドのオーバーロードは避ける事
  • 別々の namespace に異なる実装を書くと、拡張メソッドをオーバーロードした感じになるが、拡張メソッドの使い方としては間違い
  • 別の識別子で別途定義すべき

Item m39: Avoid Throwing Exceptions in Functions and Actions
  • シーケンスを操作する LINQ コードの中での例外送出は避ける事

Item m41: Avoid Capturing Expensive Resources
  • クロージャがリソースをつかみっぱなしになるのを避ける事
  • クロージャが、IDisposable なローカル変数を参照するコードを書くと、クロージャの生存期間や遅延実行がからんで面倒な事になりがち

Item m48: Avoid Calling Virtual Functions in Constructors
  • コンストラクタで仮想関数を呼ばない事

Item m15: Avoid Calling Unknown Code in Locked Sections
  • 未知のコードを lock ブロックの中で実行しない事
  • 例えば、パラメータで渡されたりイベントに追加されたデリゲートや、オーバーライドされた仮想メソッドなどが、デッドロックを発生させる事がある

Item m24: Declare Only Nonvirtual Events
  • virtual なイベントは避けること
  • ほとんど意味が無く誰も得しない

Item m47: Limit Array Parameters to Params Arrays
  • 可変引数以外では、配列を受け取るメソッドシグネーチャは避ける事
  • covariance のせいで実行時に面倒くさいエラーが起こりがち
  • シーケンスを渡すときは配列ではなく、IEnumerable を使う
  • 中身を変更するときはIEnumerable を返す

中には FxCop とかで検出可能なものもあるらしいが、そうでないものも含めてコーディング規約とかガイドラインにも載せて、開発メンバで共有できるようにしたい。

2011年1月14日金曜日

後付テストに関する覚書

後付テストについて思う事を、モヤモヤとか「何だかなぁ」といった感じを交えて、敢えてあまり整理しないまま書き連ねてみる。

手段と目的を取り違えているケース
実は、単に「NUnit」とか「カバレッジ」とか「自動化」とか言ってみたいだけだろって現場も、いまだに多かったりする。

xUnit という道具を、どのタイミングで、どのように使えば、どんな仕組みによって、どんな効用が得られるかを、全然掴まないまま不毛な実践に走るケースがままある。

こういう現場に限って、文字通り取って付けたような後付テストに走って、投下した作業コストに関わる損得もほとんど見えていないまま、目先のコードカバレッジに一喜一憂する。

こうした実りの無い作業が、経験者の意見が届かないプロジェクト外の上層部から強制されたりする現場もたまにあるから恐ろしい。

「納期が迫ってるからテストコードは後回し」な現場の場合:
ほぼ間違いなく、テスタビリティも同様に後回しになっている。

特に C# の場合、何も考えずにコーディングすると、メソッドのデフォルトが 非virtual という一見ささいな言語の特徴から、テスタビリティが絶望的なレベルにまで落ち込む。

しかもこういう現場では、得てして本体コードに手を入れるリファクタリングは事実上許されていなかったりもする。

こんな状況で、単に順序が違うだけなんて高をくくって、テスト駆動開発がもたらすものと同じ効果を後付テストに期待したところで、数倍のコストをかけて数分の一の効用も得られないという不毛な事に必ずなる。

コードカバレッジによる後付テスト進捗把握の是非:
各クラスを正味の単体でホワイトボックス検証するテストコードならば、迷わずコード・カバレッジで網羅性を測れば良いが、普通は後付テストなんかしてる時点でそんなイイ感じのプログラムには程遠かったりする。

対象クラスの隔離のためのモッキングが活用できるレベルまで、本体コードのテスタビリティが十分に高ければ話は別だが、そうでもない限り後付テストをコードカバレッジで測るのは不合理。(テスタビリティの低さは補助的なツールである程度カバーできるが、C# の場合結構な金が掛かる。)

また、そうした全然モッキングが使えないような低テスタビリティの条件下で後付テストを強行すると、あるテスト対象メソッドの呼び出しが、複数のアーキテクチャ・レイヤを跨いだクラス群の芋づる式のメソッド呼び出しを引き起こす(ItegrationTestなら正にこれが正解だが)。

こうなってしまうと、テスト対象以外のメソッド・コードも含まれてしまうので、正味のカバレッジが全然反映されなくなる。(この他にも、本来のテストの関心とは関係ないデータのセットアップや時間の掛かるサービスの呼び出しを強いられたりするような、様々なテスト・アンチパターンが生じる。)

では、後付テストには価値がないのか
上述のように単体×ホワイトボックスのテストが難しい時は、無理して テストファーストもどきのテストコードを書いてカバレッジを測るよりも、HOW ではなく WHAT に着目して機能テスト(FunctionalTest)を書く法が費用対効果の面で遥かにマシ。

但し、コードカバレッジではなく、機能要件(ユースケース、ユーザストーリ、フィーチャ、etc...)に着目してテスト項目書を起こし、これをベースにカバレッジを把握するべき。

後付機能テストの効用
テスト駆動開発における ユニットテスト は、第一義的には生産性向上のための手段。

生産性向上の結果として、品質にまわす余力が生じて品質向上が得られるというのは、副産物的としては大いに有りだが、ユニットテストの直接的な効用として品質保証を期待するのは見当違い。

一方、後付の自動 FunctionalTest は、より直接に品質に対して効果を挙げる。

まとめ
テスタビリティが低いまま、どうしても後付テストを書かざるを得ないときは、
  • 適切な境界を定めてブラックボックスの観点でテストすること
  • HOW ではなくてWHATに着目し、機能をこそ網羅的にテストすること
  • コードカバレッジではなく、機能仕様を単位としたテストコーディングにより網羅性を測ること
  • 後付のブラックボックステストなのだから、必ずしも本体と同じ言語にこだわる必要は無い。他のスクリプト言語や 非 xUnit ツールも適宜検討すること
いや、余りまとまってないが・・・

2011年1月5日水曜日

C#で迷ったときのための備忘録

以下、『Effective C#』と『More Effective C#』から、
「A より Bを使いましょう」って感じで対比して書いてある項目を、抜書きしてみた。
Item NN が前者で C# 4.0、Item mNNが後者で C# 3.0。

More Effective C#More Effective C#


Item 01: Use Properties Instead of Accessible Data Members
パブリック・フィールドよりプロパティを使いましょうという当然な話。

Item 02: Prefer readonly to const
runtime 定数と compile-time 定数の違い。極限られた場合を除いて、普通は前者を選択するに越したことは無いとのこと。

Item 03: Prefer the is or as Operators to Casts
安全かつ効率的という事で強く推奨。

Item 04: Use Conditional Attributes Instead of #if
Conditional 属性はメソッド単位でしかつけられないが、むしろそのおかげで良好な構造化が保て、#if/#endif の濫用による可読性低下を防止できる。

Item 08: Prefer Query Syntax to Loops
for/while などの手続型構文よりも、宣言型の Query 構文を使うべし。Linqのメソッドも場合により可。

Item 12: Prefer Member Initializers to Assignment Statements
ローカル変数の宣言と初期化と同じで、保守性が高い。

Item 22: Prefer Defining and Implementing Interfaces to Inheritance
昔からあるオブジェクト指向プログラミングのプラクティス。

Item 30: Prefer Overrides to Event Handlers
ちょっと意外だけど、どちらも使える状況でさえあれば、よく考えてみると Override の方が簡単な上に自由度が高いという話。

Item m09: Prefer Generic Tuples to Output and Ref Parameters
『More ~』の方なので、C#4.0のTupleでなく C#3.x 環境で、Generics を用いた自作のクラスの話題。今の携わってる案件がC#3.5なので、使える。

Item m11: Use the Thread Pool Instead of Creating Threads
.Net が提供してくれてる Thread Pool の方が、使いやすくて効率がいいとの事。

Item m22: Prefer Defining Methods to Overloading Operators
まあ、明らかにメソッドよりも演算子オーバーロードの記述性が高いなんて場面は、滅多にないしね。

Item m38: Prefer Lambda Expressions to Methods
ラムダ式の方が、より小さい要素に分解したり、それらを組み合わせたりするのに便利。関数型言語に馴染みがあれば断然読みやすいし。

Item m44: Prefer Storing Expression<> to Func<>
式を保存したり複雑に組み合わせたりするときは、FuncよりExpressionの方が便利という話。

にしても、前回からずいぶんと間が空いてしまった・・・