2015年7月28日火曜日

Test First ?

以前、テストに基づいて仕様を考えることを試してみた結果という観点での内容の文章を書きましたが、これはそれほど難しい考え方ではないということを皆さんも薄々気がついていることだと思います。
ただ、重厚長大な形式主義や単なる習慣が、こういった逆転の発想を打ち消してしまうのは少々もったいないようにも思います。

依然として、要件をまとめて、機能仕様を作成し、さらに詳細設計書まで落とし込んでやっと楽しい実装に入れるという流れも、そろそろ限界を迎えてるのではないかと、いや、とっくに限界なんだろうと考えるわけです。
なぜなら、プロジェクト後半にもなるとせっかく作成した先の成果物は、だんだんと現実から乖離してメンテナンスもままならず、役に立たなくなることがあまりにも多い。
最終的にはどうなるのか?というと、実装者の裁量にまかされるわけです。
本末転倒な話です。

さて、では、視点を変えてテスト項目から洗い出してゆくとどうなるのか?
結局は同じことなのです。
ユーザ視点になるとテストの項目で表され、開発者の視点で見ると仕様書になるわけです。
つまり、これは表裏一体。結局、同一、同じものを言っているわけです。
両者ともにウォーターフォールのV字型機構で対応して表され、インプットとアウトプットで対になるわけですから、ごく自然なことだと思います。

そのことのひとつの証明として何日間かかけてドメインを中心軸として、左右対称の形を描くユニットテスト、モックアップなどを取り上げてきたわけです。
いずれの思想も根底にあるのは、通常の習慣とは逆にモノゴトを観察する知恵なのです。

2015年7月27日月曜日

オニオンスライスのオートメーション

ふだん単体テストのオートメーションにあまりなじみのない方のために、少し具体的な話をしてみようと思います。
そして例によって具体例は先週の続きです。
以下のレコードをデータベースから取得して画面に表示するためのコンテキストをテストします。

<朝食>
     <食べたものリスト>
          <食べたもの>トースト</食べたもの>
          <食べたもの>ハムエッグ</食べたもの>
          <食べたもの>ひよこ豆とレタスとトマトのサラダ</食べたもの>
     </食べたものリスト>
     <飲み物>コーヒー</飲み物>
</朝食>

1)まずは、期待値を構成します。
listと飲み物はprivateスコープです。
var expected = new 朝食();

このオブジェクトはコンストラクタの中で次のように初期化されます。
this.list = new 食べたものリスト()
list.Add( new 食べたもの("トースト") );
list.Add( new 食べたもの("ハムエッグ") );
list.Add( new 食べたもの("ひよこ豆とレタスとトマトのサラダ") );
this.Set飲み物 ( "コーヒー" );

2) 次に被検クラスを起動して、返される値をキャッチします。
var target = ある朝に食べた朝食() ;
朝食 actual = target.Find();

3)最後に期待値と実測値が同じであるか判定します。
for ( 朝食 a : actual ) {
     for ( 朝食 e : expected ) {
          assertEquals( e.Get食べたもの, a.Get食べたもの );
          assertEquals( e.Get食べたもの, a.Get食べたもの );
          assertEquals( e.Get食べたもの, a.Get食べたもの );
     }
}
assertEquals( expected.Get飲み物, actual.Get飲み物 );

ここではじめてに期待したオブジェクトとデータベースから返却された実測値が同一であること、つまり、期待に沿ったものであるかを判定しています。
assertでかかれた比較がイコールで結ばれればテストは成功なので、グリーンシグナルとなるわけです。
ただし、正確に言うと、Listは投入された要素の順番が保証されないので、ここはもっと別の記述になるはずですが、テストの流れをシンプルにご紹介するために、あえてこのように書きましたことを注意してください。

こうやって見てみると意外と簡単ですね。
とは言え、このテストではデータベースに直接接続していますから、本来はもっと工夫が必要ですし、これでは不充分です。
加えて仕様が変化したときに、当然、このテストコードでは整合しなくなるわけですから、もっと柔軟な展開も頭の中に入れておかなければなりません。
と、いろいろ考えることは多々ありますが、それでも、この方法には価値あることが少なからずあると思います。
それを知るには実際的な体験が必要です。

よくテストコードのメンテナンスが大変だ、という意見も聞かれますが、それはテストとしての構造設計がうまくできていないことに原因があることが大半です。
変化に強い実装コードのノウハウは、そのままテストコードの柔軟性にも同じように展開できるはずです。平面的な構造設計だけでは、そもそも実装コードのメンテナンスもままなりません。ぜひ、このような視点に注意を払って挑戦してみてください。
そこではじめて単体テストのオートメーションの価値に気がつくと思います。

2015年7月24日金曜日

オニオンスライスの単体テスト

昨日はヘキサゴナル・アーキテクチャの紹介でした。
この実装パターンは実はモックアップの導入だけではなく、ほかの部分でも効果を発揮します。今回はそのことについて少し書こうと思いますが。

しかしながら、賛否両論の多いアイディアでもあります。

昨日、モックアップは本番実装の鏡影だということを書きましたが、ということは、ほぼ同じような特性を持ったエンティティクラスにも展開が可能だということが容易に推測できます。

それは、つまり、ユニットテストにおいてです。
たとえば、本番に使用するエンティティとして、昨日使用した 朝食クラス を使います。
このクラスはデータベースの検索結果を格納して、データベースのアクセスレイヤーを構成するモデル -> 上位のパーシステンス -> そして、画面直下のプレゼンテーション層までハンドリングされる、データの保持という役割をもったオブジェクトです。

それでは、プレゼンテーションの下層を位置づけるメソッドをテストすることを考えてみます。画面の背後で動作するこのコンテキストは、任意の朝食データを検索して返す というように動作するはずです。
このコンテキストの期待動作を確かめるにあたって、その正当性を判定するには、返されるはずの朝食オブジェクトの内容と同一のデータを保持するオブジェクトを期待値クラスとして定義すると思います。
これは、つまりユニットテストの期待値に相当します。データベースから返される実測値は、本番実装の朝食エンティティクラスのオブジェクトです。
この2つのオブジェクトが同一であれば… 同じ内容のデータを保持していて、AssertEqualで結ばれれば被検対象のコンテキストは正しく動作し、グリーンシグナルが点るはずです。

ここで気がついた方はするどいです。
被検対象のコンテキストを軸に(つまり、ここはドメインとなります)expected と actual はまったく同様のデータになる、という特性が得られます。
これがオニオンスライス、または ヘキサゴナル・アーキテクチャの特性でもあります。
ドメインは常に中心軸として捉えられ、その左右の線対称の部分に、expected のインプット(期待するデータ)と actual(実測結果)が配置され、同一の重量配分の元にバランスします。したがって、テストが成功したことを表します。
これがユニットテストにおける、ひとつの合理性とその実践アイディアです。

おそらく、なんて面倒な! と感じる方もいらっしゃるかもしれません。
そのために賛否両論が巻き起こるテーマとなり得るわけです。

このテクニックが現場の実装で成り立つのか? という議論は、少々本質を逸脱すると思いますので、それはまたの機会に。

2015年7月23日木曜日

朝食はオニオンスライス

今日は昨日の題材を使ってオニオンスライス・パターンを考えてみたいと思います。
オニオンスライスは後ほど説明するとして、目指すのはモックアップの作成です。
こんなことを想定してみます。

・明日までに任意の日に食べた朝食の内容を画面に表示するようなプレゼンが見たい。
・ただし、データベースがまだ構築されていない。
・しかしながらサンプル画面を作るのではなく、そのまま本番に流用できる精度が欲しい。
・なぜなら時間がないし、手戻りを生み出したくないから。

本当に勝手なものです。
この程度のことであれば、サクッと画面を作ってボタンか何かを押したタイミングで画面に情報が表示されるような「サンプル画面」の実装を作ってしまえるでしょう。
そこを、ほぼ同じような手軽さで、ある程度の構造を持ち、すぐに本番に流用できるようなメカニズムを考えてみましょう。
パラメータやデータベースのアクセスレイヤーは、今回の本質ではないので割愛します。
それでは、思い出す意味で、ボタンを押して画面に展開するデータは昨日提示したオブジェクトを使用します。

<朝食>
     <食べたものリスト>
          <食べたもの>トースト</食べたもの>
          <食べたもの>ハムエッグ</食べたもの>
          <食べたもの>ひよこ豆とレタスとトマトのサラダ</食べたもの>
     </食べたものリスト>
     <飲み物>コーヒー</飲み物>
</朝食>

こんな感じです。
このオブジェクトは本番用に使うとしてモックアップのデータオブジェクトのクラスを考えます。

class 朝食モックアップ extends 朝食 { … }
こんな感じです。
ついでに、朝食クラスはこんな風に定義します。

class 朝食 implements I朝食

モックアップは、本番用の朝食クラスを継承して同じ構成の朝食モックアップを定義します。
当然ながらコンストラクタはこのようになります。

public 朝食モックアップ() { super() }
つまり、実態は本番と同じということになります。
これを返却用のオブジェクトとして使用することにします。

次にビヘイビア(ふるまい)を表す検索用オブジェクトを考えてみます。
まず、本番用はこのようになります。

class ある朝に食べた朝食()  implements I食事 { … }

そして、こんな検索メソッドを持ちます。

public virtual I朝食 Find() { return 本来はデータベースから取り出すのだ! }

次にモックアップ用のビヘイビアを定義します。

class ある朝に食べた朝食モックアップ() extends ある朝に食べた朝食() { … }

本番用のビヘイビアを継承するわけです。
したがって、検索メソッドはオーバーライドされ、朝食を表すモックアップエンティティを返すように定義します。

public overrides I朝食 Find() {
     return new 朝食モックアップ()
}

この部分で、つまり、朝食モックアップのコンストラクタの中で、画面にプレゼン用として表示すべきデータを与えて初期化します。
ここまでで本番用とモックアップ用の2種類の検索メカニズムを定義しました。
2種類とはいえ、構造的にはまったく同様のことを表現しています。
これを比喩的なメタファーとして、オニオンスライスと言います。
または、ちょうど鏡を挟んで線対称として捉えることができることから、ヘキサゴナル・アーキテクチャと呼ばれたりもします。
本質は、モックアップは本番の鏡影として表します。

さて、最終段階として画面に結果として表示するコンテキスト(文脈)の部分を定義します。

class I朝食 朝食Repository(I食事 behavior) { … }

このコンテキストはこんな風に使います。
まずは、モックアップを使う場合。

var context = new 朝食Repository( new ある朝に食べた朝食モックアップ() );
var 結果 = context.Find();

これで、モックアップの朝食を表すエンティティが返されるので、それを使って画面に描きます。これで明日のプレゼンは乗り切ることができますね。
本番に切り替えるときは、以下のようになります。

var context = new 朝食Repository( new ある朝に食べた朝食() );
var 結果 = context.Find();

パラメータとして渡すビヘイビアを変更するだけです。
画面の中も変更する必要もないし、ビジネスロジックも変更する必要はありません。
そもそも本番とモックアップを分岐させる If DEBUG のようなロジックさえ存在しません。
コンテキスト、ビヘイビア、エンティティの構造に置き換えられてしまったのです。
このように大局的な視点でロジックを構造に置き換える作業は、データベースシステムだけではなく、制御などの分野でも有効です。
ぜひ、試してみてください。

2015年7月22日水曜日

朝食は頭の体操

いきなりですが、あなたの今朝の朝食を教えてください。

冒頭から不躾な質問で申し訳ありませんが、これをオブジェクトとして表してみましょう。
参考までに自身の今朝の朝食はこんなふうに表現してみます。

<朝食>
     <食べたものリスト>
          <食べたもの>トースト</食べたもの>
          <食べたもの>ハムエッグ</食べたもの>
          <食べたもの>ひよこ豆とレタスとトマトのサラダ</食べたもの>
     </食べたものリスト>
     <飲み物>コーヒー</飲み物>
</朝食>

簡単ですね。
当然ながら、個々のセンスや捉え方によって表現はいろいろあると思います。
もちろん、それでよいわけです。
ここで示した表現は、食べたもの という視点を集合で捉えて、すなわち、コレクションとして表してします。あえて何か特記するならそれだけです。

では、今度は、これをクラスに置き換えてみます。

class 朝食 { … }
これだけです。最小の構成です。

少し工夫を加えて汎用的にしてみます。

class 朝食 extends 食事 { … }

superクラスはこんな風に表してみます。

class 食事 implements I食事 { … }

こうすることによって昼食と夕食を表すことができますね。
もちろん、人によっては、上に提示した概念モデルに <時刻></時刻> のようなタイムスタンプを付与したり、<いつ></いつ> のような更なるオブジェクトの汎用表現を加えるかもしれません。もちろん、それもOKです。

今度は、もう少し視点を拡げてコンテキストを表現します。つまり、ふるまいの部分を与えます。たとえば、食べる、摂取する、という行為を概念モデルとして考えます。
こんな感じはどうでしょう?

class 食べるコンテキスト { … }

上記のクラスのコンストラクタで、さきほどの朝食クラスを生成してインジェクトします。

食べるコンテキスト c = new 食べるコンテキスト( new 朝食() );
c.Execute();

これにより、コンテキストに食事インタフェースの規約を実装したクラスを与えることにより、表現が汎用的になりました。

言ってみれば、これは頭の体操です。
いろいろなものをモデルに置き換えてみましょう。

毎朝の通勤ルート
今週末に観に行く予定の映画
今夏の長期的気象予想
などなど…

なんでもよいです。
ほんの少しの時間が出来たときにでも、頭の体操をしつつ柔軟な思考を持つべく練習をしましょう。

ポートフォリオマネージメント

システムやソフトウェアを作成するにあたり、最初にやるべきこととして要求の聞き取りがあると思います。お客様が目指したまだ形のないモノを作成するにあたり、この作業の実施はとても重要な期間でもあります。
この要求は、具体性と実現性を検証されて、やがて要件定義へと結実します。
この過程で私たちはいったいどんなことに注意をはらうでしょうか?
お客様の声に耳を傾け最大限聞き漏らすまいと努力をするでしょうか?
あるいは、なんとか抜けのない資料を作成するべく力を注ぐでしょうか?

どれも重要なことではありますが、固執すべきではありません。
ここで注意しなければならないのは形式ではなく「何か」を掬い上げるのにどのような仕事が効果を上げるのか? というざまざまな改善ポイントが隠されていることを積極的に察知することだと思います。

果たして、ビジネスがどこに向かおうとしているのか?

これは極めて重要な命題です。もちろん、これはプロダクト・オーナーの目的であるわけですが、私たちモノ作りに従事する立場からも大きな関心ごとであるはずです。なぜなら 「見通し」 が重要だからです。見通しとは、つまり、計画であり、もっと正確に言うならばライフサイクルを大きく決定づける動機でもあります。
これらの材料から、私たちは優先順位の提案をし、開発を段階的に進めていくことに一定の価値を見つけることが出来るかもしれません。
これは、きっと方向性のミクロな視点なのだと思います。

では、もっと大きな視点で、パースペクティブを示すことができる点があるとすれば
それは、きっと 何を作るか? ではく、何を解決するのか? もっと言ってしまえばどんな悩みを解決するのか? という観点に行き着くのだろうと思います。

2015年7月17日金曜日

エクセルの概念モデル

X軸とY軸の表現の集積は、誰にも直観的でわかりやすいものだと思います。
たまに、表現の枠組みを打開すべくセルを連結して、ひとつ下の階層を表してやることは誰にでも経験があることだろうと思います。
これは、つまり表の限界です。当然ながら表は二次元配列が基本なので、それよりも下の階層や、あるいは「Z軸」の要素を表そうと思えば、これは最早、表の限界を超えることになるでしょう。
しかし、我々エンジニアはエクセルを単なる表として捉えるのは少々乱暴すぎると思います。
もう少し本質に迫る必要がありそうに思えます。
では、表を分解して行の視点で捉えるとします。すると、行は1行のコレクションを表すことになります。

List<Row>
こんな感じです。

次に、行が保持する要素は? というと…

同じように List<Column> という表現になると思います。
これでセルの集合を表すことができました。

セルまで行き着いたところで、このセルがどのようにして表になり得るのか? を表します。

<Rows>
     <Row>
          <Columns>
               <Column>セルに格納するデータ</Column>
          </Columns>
     </Row>
</Rows>

ここまで到達すればオブジェクトに簡単にマッピングできますね。
つまり、これはノードとエレメント、親と子の関係でもあるわけです。
ここで思慮深く観察したいのは、あくまでも二次元配列のベクトルで捉えるのではなく、入れ子のイテレーションです。こうすることにより、より抽象度が高まることが実感できると思います。
良いデータ表現というのは、ノードの再帰的表現に他ならないのです。
もし、データの関連をオブジェクトで表そうと思えば、ルートノードは必ずひとつになるはずです。もし、そうならなかったならスコープを逸脱した設計になることがすぐにわかると思います。と、同時に人が頭脳で捉えられる臨界点を超えてしまうことにもなるでしょう。