.NET Tools
5.唐突な仕様変更に対応する (株)ピーデー 川俣 晶2003/04/26 |
![]() |
|
唐突な仕様変更
プログラム開発において、最初に「これこれこういう機能を作ってくれ、頼む」と言われてその通りに作って終わりになるとは限らない。非常に高い確率で、「そこはこう変更してくれ」と言われる。しかも、どんな変更を要求されるか予測できない場合も多い。最初の要求を実現するために書かれたソース・コードは、簡単に変更を余儀なくされてしまうのである。
この最大データ・サイズ記録クラスに対しても、このような機能変更の要求が出てきた。「最大データ・サイズを要求した顧客のみを記録するだけでは不十分だ。『要求された大きなデータのベスト10』を記録してほしい」と、そんなことを言われたとしよう。そんな仕様変更をいまごろいわれても……、と思いながらも、それを実装することになったとしよう。つまり、最大データ・サイズ記録クラスはこれまでのように1個の整数値ではなく、10個の整数値を保存しなければならない。しかし、すでに最大データ・サイズ記録クラスは、コードのあちこちから参照されているため、中身を書き換えて、もし挙動が変わってしまったりすると、面倒なことが起きる。「動いているものには触らない」というポリシーを持っているプログラマーも多いと思う。だが、それを書き換えねばならなくなったとしたら……。
機能追加によって新規に増えるメソッドはともかく、既存のメソッドの挙動が変わることは絶対に避けたい。しかし、どうすればそれが実現できるだろうか。
1つの方法が、コードを書き換えた後で、NUnitで確認するという方法だ。テスト・メソッドは、実装の詳細とは関係なく、メソッドの表面的な挙動だけをチェックしている。ならば、どんどん書き換えても、テストさえパスすれば、挙動は変わっていないと見なせる。テストはすべて自動化されているので、実行するのは簡単である。いちいちファイルを指定するのが面倒なら、引数にファイルを指定して起動するバッチを作ることもできる。Nunit-Guiは開くと前回読み込んだDLLを自動的に開くので、それを活用するのもよいだろう。また、VS.NETのプロジェクト設定の中で、プロジェクト実行時にNunit-Guiを実行してしまうように設定することも可能である。
これにより、安心してプログラムの書き換えに着手できる。つまり、NUnitと“Test First”は、すでに稼働しているコードを書き換えるための勇気を与えてくれるのである。
以下が書き直したコードである。
|
|
10個のデータを記録するようにしたMaxDataSizeRecorderクラス(C#版) |
|
|
10個のデータを記録するようにしたMaxDataSizeRecorderクラス(VB.NET版) |
要求された機能の追加にあまり手間を掛けたくなかったので、安易な解決方法を採ってみた。System.Collections.ArrayListクラスのSortメソッドを使って、上位10人のポイントを並べ替えるような仕組みを作ってみたのである。Sortメソッドは配列にも用意されているが、ソート計算時には新しいスコアを入れて11人になり、固定長である配列には合わないような気がして、あえて可変長のArrayListクラスを使ってみたのである。
さっそくNUnitで確認して、テストをパスするまでコードを手直しした。すでに最大データ・サイズ記録クラスを使用しているプログラム・コードにおいても、致命的な問題は起こしていないはずだ。
なお、新規に作成するクラスやpublicなメソッドに関しても、本当ならテスト・メソッドを用意すべきだが、今回は説明の都合上割愛した。
もっと手直しをしよう
上のコードはあまりきれいではない。特にArrayListクラスを使った結果、キャストがあちこちに入り込んでいる(もっともVB.NET版のコードにはキャストはないのだが……。「Option Strict On」で使うと、VB.NETでもキャストは必要になる)。何とかならないものかと思ったが、よく考えると、コレクションの長さを変えないで処理する方法があることに気付いたとしよう。新しいポイントを追加するときに、ベスト10に入るかどうかだけ確認して、入るときには、第10位の人の代わりに新しく追加する人を入れて、それからソートしてしまえばよいわけだ。これなら固定長なので、配列で処理できる。配列で処理できればキャストは不要だ。このほかpublicなメンバ変数などもすべて書き直してみた。書き直した結果がこれだ。
|
|
ArrayListクラスをやめて配列により10個のデータを記録するようにしたMaxDataSizeRecorderクラス(C#版) |
|
|
ArrayListクラスをやめて配列により10個のデータを記録するようにしたMaxDataSizeRecorderクラス(VB.NET版) |
見比べていただけばすぐ分かると思うが、相当大胆な変更だ。しかし、プログラムの働きという意味では、前のコードでも問題はなかったはずだ。従って書き換えの結果は、コードがきれいになっただけである。「動いているものには触るな」というポリシーを持つ人なら、きっと手を出さないだろう。しかし、自動テストの環境がしっかり作られていれば、実装内容の書き換えは決してリスクの高い行為ではない。それよりも、必要に応じてきめ細かくコードの内容を変更していく勇気が与えられるのは非常に重要だ。
現実のソフトウェア開発では、仕様変更は必ず発生するものであり、何度も変わり続ければコードはどんどん読みにくくなる。読みにくくなったコードを読みやすいように書き直すことは、開発をスムーズに進めるためには必要な作業なのである。このようなコードの修正は「リファクタリング」と呼ばれるが、何の準備もなくいきなりコードを書き換えればバグはやすやすと入り込む。簡単に素早く何度でも自動テストを実行できる環境を用意することによって、バグが入り込みにくいコード修正が可能になるのである。
まとめ
さて、NUnitの効用が何となく見えてきただろうか。NUnitは自動テストを行う方法を提供する。自動テストは、コードを書き換える勇気を与えてくれる。コードを書き換える精神的負担や時間が軽減されれば、ソフトウェアの質を高めることが容易になる。例えば、同じ処理をコードの別の個所に見つけたら、それを1カ所にまとめることができる。そうすれば、保守性も高くなるし、コードも短くシンプルになって分かりやすさにもプラスになる。筆者の過去の経験からいっても、自動テストを作成した方が、いろいろな意味でプログラマーの負担が軽いように感じられる。
自動テストは、ちょっと見た目には遠回りに思えるかもしれない。だが、自動テストとは、道路をきちんと舗装するようなものだ。いったん舗装してしまえば、何倍ものスピードで、しかも軽い負担で走ることが可能になる。NUnitという手軽なツールもあることだし、ぜひ試してみてはどうだろうか?
今回の解説は、あくまでNUnitの使い方の入り口にすぎない。また、Test Firstの先にはTest-Driven Developmentというキーワードもあるらしい。いまこそ、あらためてテストについて注目してみてもよいのではないだろうか?
![]() |
INDEX | ||
[.NET Tools] | ||
NUnit入門 Test Firstのススメ [NUnit 2.0対応版] | ||
1.NUnitの環境を準備する | ||
2.何はさておき、最初にテストを書こう | ||
3.空のメソッドを書いてNUnitを実行してみる | ||
4.プログラム本体を実装する | ||
![]() |
5.唐突な仕様変更に対応する | |
![]() |
![]() |
「.NET Tools」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
![]() |
|
|
|
![]() |