VB.NETでも契約プログラミングをしたい(その2)

はじめに

jyuch.hatenablog.com

というわけで今回はすこし間隔が開きましたが契約プログラミングのお話です。

契約プログラミングその1でリンクだけ紹介したあのマニュアルを一通り読み終わったので、それについて書きたいと思います。

イントロダクション

契約とは何かとものっそいざっくり言うと、『何を渡して、何を得るか』です。 つまり、引数の型や返り値の型も契約と見なせます。

Integer型を受け取るメソッドのStringをぶち込んでは正しく処理なんかできません。 VBですとOption Strict Offで亜空間型変換*1を行ってくれるのでStringからIntegerに正常に変換できるなら正しく処理を行えますが、正しく処理を行えるかどうかなんて実行時にしか分からない訳です。

逆にDecimal型が欲しいのにDoubleなんか返されても困る訳です。

エラーは可能な限り早期に検出するのが.NETなどの静的型付けな環境での一般的な認識となっています。 すなわち可能ならコンパイル時に、実行時の場合にしか分からない場合でも早期に検出してエラーを送出すべきです。

また、契約プログラミングはその『エラーの早期検出』を補助する役割を持つ訳です。 そう考えるとVB.NETOption Strict Off契約プログラミングはかなり相性が悪い事が分かります。

つまり、Option Strict Offはクソ。 まずはOption Strict Onにしましょう。話はそれからです。

クッソ適当な分類

かなりの行数を割いてOption Strict Offをディスった次はようやく Code Contract のお話です。

Code Contracts を大まかに分類すると、以下の三つに分けられます。

  • 呼び出し側が満たすべき引数の条件(事前条件)
  • 呼び出された側が満たすべき返り値の条件(事後条件)
  • 呼び出された側が満たすべき内部状態の条件(内部状態条件)

この3つの条件を専用のAPIでコード中に記述する事で静的コードチェッカが認識できるようマークします。 そして、条件が満たされる事が証明できない場合にはコンパイル時に警告を出す事が出来るようになります。

また、実行時に条件が満たされない事が検出された場合にはただちに例外がスローされ、契約を満たさない不届き者を早期に排除出来るようになるわけです。

事前条件とアセンブリモード

とりあえず、試しに Code Contracts を導入すると決めた場合にまずは決めなくてはならなくてはならない事が1つあります。

それは事前条件の形式と形式によって決定されるアセンブリモードです。

  • リリースビルド時に引数検査を含める
    • No
      • Usage1:
        • 常にRequireを使用する
        • ランタイムチェックをデバックビルド時のみ有効にする
    • Yes
      • リリースビルド時に ccrewriter などのツールを使用する
        • Yes
          • Usage2:
            • パブリックメソッドの引数検査にRequire(Of Exn)(...)を使用する
            • もしくはRequireを使用する
            • 常にランタイムチェックを有効にする
            • オプションでパブリックメソッドの事前条件をアセンブリに出力する
        • No
          • Usage3:
            • if -then - throw(レガシー形式)形式の検査をリリースビットで行う
            • 引数検査を手動で継承する
            • if -then - throw形式の検査はEndContractBlock()メソッドでマークする
            • もしくはRequireメソッドを使用する
            • ランタイムチェックはデバックビルド時のみ有効にする

そんでもって、Usage1 or 2 の場合はアセンブリモードにStandard Contract Requiresを指定し、Usage3 の場合はCustom Parameter Validationを指定してやればOKというわけなのです。

こいつは一度決めてしまうと簡単に切り替えられないので*2、決定するときはある程度は慎重に判断してください。

おわりに

今回は取り敢えず Code Contract 導入以前と言うことで、アセンブリモードの軽い紹介と対応する引数チェックの形式について軽く紹介できました。

続く

*1:積極的な暗黙的型変換の事

*2:コードの書き換えが面倒という意味で