連載
開発をもっと楽にするNAgileの基本思想

第4回 「プチ・パラダイムシフトせよ!」

福井コンピュータ株式会社 小島 富治雄(Microsoft MVP for Visual Developer - Visual C# Jul. 2005 - Jun. 2007)
2007/01/17
Page1 Page2 Page3 Page4

■■2. 滝を心配する健二■■

(眞鎮と滝が別室に向かったのを確認して)滝さん、悩んでいるみたいだね。簡単にはうまくいかないものみたいだ。

 

 

そうだな。

   

それにしても、なんて真摯なんだろう。まっすぐに困難に向かっている。彼女を見ていると、アジャイルに対するかつてのわだかまりが解けていくようだ。

   

うむ。そう感じるか。

   

でも、あんなに明るかった滝さんが落ち込んでいるのは、見ていてつらいな。何とか彼女が成功するといいんだけど。

   

……健二。心配は要らない。滝はきっとやり遂げるだろう。

“She's the one.”
(彼女はIT業界の救世主だ)

それはちょっと大げさじゃないかな。救世主だなんて……。

……まあ、お前にもいずれ分かるだろう。

■■3. ソフトウェア開発の目的とは何か■■

滝よ。では、プチ・パラダイムシフトを行うための練習ぢゃ。

 

 

はい。

   

よし。ではまず問おう。抽象的な質問で悪いがの。

 新製品を開発するとしよう。これまでにない新しいものの開発ぢゃ。開発を開始するに当たって、開発者がまず考えなければならないことは何だろう?

   

え? うー……まず……。まず、どんな新しい技術があって、どう使えるのかを考えます。開発環境とか、新たなテクノロジとか……。

   

それが開発者にありがちな態度なんぢゃ。いきなり「どうやって作ろうか?」と考えてしまう。違う。むしろ、

「まずそれを考えてはならない」。

 視点を変えるのぢゃ。ソフトウェア開発は何のためにやるのだった? 目的は?

   

はい……顧客の問題を解決するための手段です。

   

ではまず考えることは、「どうやって作ろうか?」ではなかろう。初めに考えることは、

「顧客の問題は何か?」

ということぢゃ。

   

……はい。

   

よいか。……例えを出そう。これからお前が受験するとしよう。目の前に試験の問題と解答用紙が配られ、試験が開始されたとしよう。試験問題を解くうえで、まずやらなければならないことは何ぢゃ?

   

……分かったような気がします。まず必要なことは、問題をよく把握することです。

   

そうぢゃ。ソフトウェア開発で問題についてよく考えぬまま「どうやって作ろうか?」と思い悩むのは、受験でいうと、「問題文を読まずにどう解答を書こうかと思い悩む」ようなものぢゃ。正しい答えを導き出すのに適したやり方とはいえぬ。

   

はい。

   

滝よ。まず、問題について考えるのぢゃ。

   

はい。

   

しかる後に、こう考えるのぢゃ。

「開発しようとしているソフトウェアは顧客のどの問題に対する解か?」

   

はい。

   

分かるかの? では次ぢゃ。

■■4. プログラミングでの視点の変換■■

プログラミングの作業に入ったとしよう。ここでは例として……そうぢゃな。簡単な電卓でも作ってみようか。

 

 

電卓ですか?

   

そうぢゃ。実際にやってみようかの?

   

はい。ではVisual Studioを立ち上げて、電卓を作ってみます。

   

簡単な足し算ができるだけのものでよい。始めよう。

   

はい。では、TDD(Test Driven Development:テスト駆動開発)*2で。

*2 N*ツールによるTDDについては『.NET Tools』などを参照のこと。

 単体テストの実行は、Visual Studio Team SystemとNUnitを併用してみますね*3

*3 Visual Studio Team SystemやNUnitによる単体テストの実行方法については『VSTSの単体テスト機能は本当に使えるのか?』などを参照のこと。
   

うむ。コード・カバレッジの表示は、Visual Studio Team SystemとNCoverExplorerの併用としよう。

【コラム】NCoverExplorerとは

N*ツールの1つにNCoverというものがある。これは.NET用のオープン・ソースのコード・カバレッジ・ツールだ。そして、NCoverExplorerは、NCoverの分析結果をGUI によってより分かりやすく表示できるアドイン・ツールだ。 NCoverと NCoverExplorerを使用することで、単体テストによって実際にどのソース・コードがテストされたのかをハイライト表示させたり、どのくらいの割合のソース・コードがテストされたのかをパーセント表示させたりできる。テストがどのくらいのコードをカバー(網羅)しているかを分析/表示できるので、「コード・カバレッジ・ツール」と呼ぶわけだ。 NCoverとNCoverExplorerをVisual Studioから簡単に使用するには、N*ツールの1つであるTestDriven.NETをVisual Studio(Team System以外でももちろん大丈夫)へのアドインとしてインストールするのが簡単だ。こうすることで、NUnitやNCoverExplorerをVisual Studioから直接呼び出せるようになる。また、Visual Studio Team Systemで作成した単体テストをNUnitで走らせるようなこともできる。なお、Visual Studio Team System(Team SuiteやTeam Edition for Software Architects、Team Edition for Software Developers、Team Edition for Software Testers)にも NCoverExplorerと同様のコード・カバレッジ機能が付属している。

(さっそくペア・プログラミングでTDDを行う2人。まずは、テストを書き始める。テストを書いてはVisual Studio Team SystemやNUnitでテスト。それからテストが通るようにコーディング。テストが通ったらVisual Studio TeamSystemやNCoverExplorerでコード・カバレッジを確認。次の機能追加の前に必要に応じてリファクタリング、を繰り返す)

   

(小一時間がたって)……うむ。良いようぢゃな。ここまでとしよう。

出来上がった電卓(Windowsフォーム)
 
using Microsoft.VisualStudio.TestTools.UnitTesting;
using 電卓Lib;

namespace 電卓が動作する
{
  [TestClass]
  public class 数キーが使える
  {
    電卓 電卓;

    [TestInitialize()]
    public void 初期化()
    { 電卓 = new 電卓(); }

    [TestMethod]
    public void 数のキーを押していくと表示されていく()
    {
      Assert.AreEqual<string>("0", 電卓.表示);
      電卓.数のキーを押す(0);
      Assert.AreEqual<string>("0", 電卓.表示);
      電卓.数のキーを押す(1);
      Assert.AreEqual<string>("1", 電卓.表示);
      電卓.数のキーを押す(2);
      Assert.AreEqual<string>("12", 電卓.表示);
      電卓.数のキーを押す(0);
      Assert.AreEqual<string>("120", 電卓.表示);
    }

    [TestMethod]
    public void 十桁まで数が入るがそれより多くは入らない()
    {
      電卓.数のキーを押す(1);
      電卓.数のキーを押す(2);
      電卓.数のキーを押す(3);
      電卓.数のキーを押す(4);
      電卓.数のキーを押す(5);
      電卓.数のキーを押す(6);
      電卓.数のキーを押す(7);
      電卓.数のキーを押す(8);
      電卓.数のキーを押す(9);
      電卓.数のキーを押す(0);
      Assert.AreEqual<string>("1234567890", 電卓.表示);
      電卓.数のキーを押す(1);
      Assert.AreEqual<string>("1234567890", 電卓.表示);
    }
  }

  [TestClass]
  public class 足し算ができる
  {
    電卓 電卓;

    [TestInitialize()]
    public void 初期化()
    { 電卓 = new 電卓(); }

    [TestMethod]
    public void 足し算キーとイコールキーで足し算ができる()
    {
      電卓.数のキーを押す(1);
      電卓.数のキーを押す(2);
      電卓.数のキーを押す(3);
      Assert.AreEqual<string>("123", 電卓.表示);
      電卓.足すキーを押す();
      Assert.AreEqual<string>("123", 電卓.表示);
      電卓.数のキーを押す(4);
      電卓.数のキーを押す(5);
      Assert.AreEqual<string>("45", 電卓.表示);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("168", 電卓.表示);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("168", 電卓.表示);
    }

    [TestMethod]
    public void 連続した足し算もできる()
    {
      電卓.数のキーを押す(8);
      電卓.数のキーを押す(9);
      Assert.AreEqual<string>("89", 電卓.表示);
      電卓.足すキーを押す();
      Assert.AreEqual<string>("89", 電卓.表示);
      電卓.数のキーを押す(2);
      Assert.AreEqual<string>("2", 電卓.表示);
      電卓.足すキーを押す();
      Assert.AreEqual<string>("91", 電卓.表示);
      電卓.数のキーを押す(5);
      電卓.数のキーを押す(6);
      電卓.数のキーを押す(1);
      Assert.AreEqual<string>("561", 電卓.表示);
      電卓.足すキーを押す();
      Assert.AreEqual<string>("652", 電卓.表示);
      電卓.数のキーを押す(2);
      Assert.AreEqual<string>("2", 電卓.表示);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("654", 電卓.表示);
    }
  }

  [TestClass]
  public class クリアキーが使える
  {
    電卓 電卓;

    [TestInitialize()]
    public void 初期化()
    { 電卓 = new 電卓(); }

    [TestMethod]
    public void いきなりクリアキーを押すと0のまま()
    {
      電卓.クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
    }

    [TestMethod]
    public void 数の入力後にクリアキーを押すと0に戻る()
    {
      電卓.数のキーを押す(4);
      電卓.数のキーを押す(4);
      電卓.クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
    }

    [TestMethod]
    public void 足し算で加数の入力直後にクリアキーを押すと0に戻り加数を入れ直すことができる()
    {
      電卓.数のキーを押す(3);
      電卓.足すキーを押す();
      電卓.数のキーを押す(5);
      電卓.クリアキーを押す();
      電卓.数のキーを押す(7);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("10", 電卓.表示);
    }

    [TestMethod]
    public void 足し算で加数の入力直後にクリアキーを押すと0に戻りそのままイコールキーを押すと被加数が表示される()
    {
      電卓.数のキーを押す(1);
      電卓.足すキーを押す();
      電卓.数のキーを押す(2);
      電卓.クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("1", 電卓.表示);
    }
  }

  [TestClass]
  public class 全クリアキーも使える
  {
    電卓 電卓;

    [TestInitialize()]
    public void 初期化()
    { 電卓 = new 電卓(); }

    [TestMethod]
    public void いきなり全クリアキーを押すと0のまま()
    {
      電卓.全クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
    }

    [TestMethod]
    public void 数の入力後に全クリアキーを押すと0に戻る()
    {
      電卓.数のキーを押す(2);
      電卓.全クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
    }

    [TestMethod]
    public void 足し算で加数の入力直後に全クリアキーを押してしまうと0に戻り足し算が取り消されてしまう()
    {
      電卓.数のキーを押す(9);
      電卓.足すキーを押す();
      電卓.数のキーを押す(2);
      電卓.全クリアキーを押す();
      電卓.数のキーを押す(3);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("3", 電卓.表示);
    }

    [TestMethod]
    public void 足し算で加数の入力直後に全クリアキーを押すと0に戻りそのままイコールキーを押しても0が表示される()
    {
      電卓.数のキーを押す(7);
      電卓.足すキーを押す();
      電卓.数のキーを押す(1);
      電卓.全クリアキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("0", 電卓.表示);
    }
  }

  [TestClass]
  public class 表示更新ハンドラが呼ばれる
  {
    電卓 電卓;
    string 表示文字列 = string.Empty;

    [TestInitialize()]
    public void 初期化()
    {
      電卓 = new 電卓();
      電卓.表示更新 += 表示;
    }

    [TestMethod]
    public void 足し算中に表示更新されるたびに表示更新ハンドラが呼ばれる()
    {
      Assert.AreEqual<string>("", 表示文字列);
      電卓.数のキーを押す(1);
      Assert.AreEqual<string>("1", 表示文字列);
      電卓.足すキーを押す();
      電卓.数のキーを押す(2);
      Assert.AreEqual<string>("2", 表示文字列);
      電卓.数のキーを押す(3);
      Assert.AreEqual<string>("23", 表示文字列);
      電卓.イコールキーを押す();
      Assert.AreEqual<string>("24", 表示文字列);

    }

    void 表示(string 表示文字列)
    {
      this.表示文字列 = 表示文字列;
    }
  }
}
電卓のテストのソース・コード(C#)
 
namespace 電卓Lib
{
  public class 電卓
  {
    public const int 最大表示文字列長 = 10;
    public delegate void 表示ハンドラ(string 表示文字列);
    public event 表示ハンドラ 表示更新;

    string display = "0";
    string 被演算 = null;
    bool   演算リセット済み = false;

    public string 表示
    {
      get { return display; }
      set
      {
        if (value.Length <= 最大表示文字列長 && value != display)
        {
          display = value;
          if (表示更新 != null)
            表示更新(display);
        }
      }
    }

    public void 数のキーを押す(int 数)
    { 数の追加(数); }

    public void 全クリアキーを押す()
    {
      クリアキーを押す();
      被演算 = null;
      演算リセット済み = false;
    }

    public void クリアキーを押す()
    { 表示 = "0"; }

    public void 足すキーを押す()
    {
      イコールキーを押す();
      被演算 = 表示;
    }

    public void イコールキーを押す()
    {
      if (被演算 != null)
      {
        表示   = 合計(被演算, 表示);
        被演算 = null;
      }
      演算リセット済み = true;
    }

    string 合計(string 被演算数, string 演算数)
    { return (int.Parse(被演算数) + int.Parse(演算数)).ToString(); }

    void 数の追加(int 数)
    {
      if (演算リセット済み)
      {
        表示 = 数を表す文字列の正規化(数.ToString());
        演算リセット済み = false;
      }
      else
      {
        表示= 数を表す文字列の正規化(表示 + 数.ToString());
      }
    }

    static string 数を表す文字列の正規化(string displayText)
    {
      int zeroNumber = 0;
      for (int index = 0; index + 1 < displayText.Length; index++)
      {
        if (displayText[0] == '0')
          zeroNumber++;
      }
      return (zeroNumber > 0) ? displayText.Substring(zeroNumber)
                              : displayText;
    }
  }
}
テストによって開発が駆動された電卓のソース・コード(C#)
   

はい。いまのテストの状況は、次のとおりですね。もちろん全部のテストが通ってグリーンになっています。

NUnitによるテストの結果
左側のツリーがテストの一覧。失敗したテストはレッド、成功したテストはグリーンで表示される。 この場合は、すべてのテストが成功している。
 
NCoverExplorerによるコード・カバレッジ・テストの結果
テストによって、電卓Libの中のソース・コードの何%が実行されたかが表示される。つまり、テストがソース・コード全体のどれだけをカバーしているか、その割合(=コード・カバレッジ)が表示される。 この場合は100%。
 
Visual Studio Team Systemによるテストの結果
テストの一覧が表示され、NUnit同様、失敗したテストはレッド、成功したテストはグリーンで表示される。 この場合はすべてのテストが成功している。
 
Visual Studio Team Systemによるコード・カバレッジ・テストの結果
NCoverExplorer同様、テストがソース・コード全体のどれだけをカバーしているか、その割合(=コード・カバレッジ)が表示される。 この場合は100%。
   

よかろう。では、少し考えてみよう。

 

 INDEX
  開発をもっと楽にするNAgileの基本思想発
  第4回 「プチ・パラダイムシフトせよ!」
    1.滝の悩み
  2.ソフトウェア開発の目的とは何か
    3.視点を変えよ 〜プチ・パラダイムシフト〜
    4.アジャイル開発をやることとは
 
インデックス・ページヘ  「開発をもっと楽にするNAgileの基本思想」


Insider.NET フォーラム 新着記事
  • 第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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間