VB.NETでも契約プログラミングをしたい(その2)
はじめに
というわけで今回はすこし間隔が開きましたが契約プログラミングのお話です。
契約プログラミングその1でリンクだけ紹介したあのマニュアルを一通り読み終わったので、それについて書きたいと思います。
イントロダクション
契約とは何かとものっそいざっくり言うと、『何を渡して、何を得るか』です。 つまり、引数の型や返り値の型も契約と見なせます。
Integer
型を受け取るメソッドのString
をぶち込んでは正しく処理なんかできません。
VBですとOption Strict Off
で亜空間型変換*1を行ってくれるのでString
からInteger
に正常に変換できるなら正しく処理を行えますが、正しく処理を行えるかどうかなんて実行時にしか分からない訳です。
逆にDecimal
型が欲しいのにDouble
なんか返されても困る訳です。
エラーは可能な限り早期に検出するのが.NETなどの静的型付けな環境での一般的な認識となっています。 すなわち可能ならコンパイル時に、実行時の場合にしか分からない場合でも早期に検出してエラーを送出すべきです。
また、契約プログラミングはその『エラーの早期検出』を補助する役割を持つ訳です。
そう考えるとVB.NETのOption Strict Off
と契約プログラミングはかなり相性が悪い事が分かります。
つまり、
まずはOption Strict Off
はクソ。Option Strict On
にしましょう。話はそれからです。
クッソ適当な分類
かなりの行数を割いてOption Strict Off
をディスった次はようやく Code Contract のお話です。
Code Contracts を大まかに分類すると、以下の三つに分けられます。
- 呼び出し側が満たすべき引数の条件(事前条件)
- 呼び出された側が満たすべき返り値の条件(事後条件)
- 呼び出された側が満たすべき内部状態の条件(内部状態条件)
この3つの条件を専用のAPIでコード中に記述する事で静的コードチェッカが認識できるようマークします。 そして、条件が満たされる事が証明できない場合にはコンパイル時に警告を出す事が出来るようになります。
また、実行時に条件が満たされない事が検出された場合にはただちに例外がスローされ、契約を満たさない不届き者を早期に排除出来るようになるわけです。
事前条件とアセンブリモード
とりあえず、試しに Code Contracts を導入すると決めた場合にまずは決めなくてはならなくてはならない事が1つあります。
それは事前条件の形式と形式によって決定されるアセンブリモードです。
- リリースビルド時に引数検査を含める
- No
- Usage1:
- 常に
Require
を使用する - ランタイムチェックをデバックビルド時のみ有効にする
- 常に
- Usage1:
- Yes
- リリースビルド時に ccrewriter などのツールを使用する
- Yes
- Usage2:
- パブリックメソッドの引数検査に
Require(Of Exn)(...)
を使用する - もしくは
Require
を使用する - 常にランタイムチェックを有効にする
- オプションでパブリックメソッドの事前条件をアセンブリに出力する
- パブリックメソッドの引数検査に
- Usage2:
- No
- Usage3:
if -then - throw
(レガシー形式)形式の検査をリリースビットで行う- 引数検査を手動で継承する
if -then - throw
形式の検査はEndContractBlock()
メソッドでマークする- もしくは
Require
メソッドを使用する - ランタイムチェックはデバックビルド時のみ有効にする
- Usage3:
- Yes
- リリースビルド時に ccrewriter などのツールを使用する
- No
そんでもって、Usage1 or 2 の場合はアセンブリモードにStandard Contract Requires
を指定し、Usage3 の場合はCustom Parameter Validation
を指定してやればOKというわけなのです。
こいつは一度決めてしまうと簡単に切り替えられないので*2、決定するときはある程度は慎重に判断してください。
おわりに
今回は取り敢えず Code Contract 導入以前と言うことで、アセンブリモードの軽い紹介と対応する引数チェックの形式について軽く紹介できました。
続く