.NET Framework 4.0のCode Contractsを組込み開発で活用する


今、ある講演向けに、再度、Visual Studio 2010、.NET Framework 4.0の新機能をじっくり見てます。昔私はオブジェクト指向とかモデル駆動型開発とか、CMMとかで組込みソフトウェア開発プロセス改善をやっていたこともあり、ソフトウェアの品質や生産性が上がりそうなトピックスを見ると、直ぐに体が反応してしまいます。


次のポストは、UMLから組込み機器向けのC/C++コードを生成する方法を紹介しようと思っていたのですが、Code Contractに惹きつけられてしまったので、そちらを紹介します。


昔々、Bertrand Meyerさんが、“Design By Contract”(以下DBCと略します)という概念を提唱しました。(所謂、「契約による設計」ってやつですな)


DBCを簡単に紹介すると、コードを利用する側に対して、このコードを利用する場合、



  • 事前条件(Pre Condition):こういう条件が整っている時に、このコードは正しく動きますよ。

  • 事後条件(Post Condition):このコードが正しく動いたら、こういう条件になりますよ。

  • 不変条件(Invariant):このコードが動いてもこの条件は変化しないよ。

という表明であり、逆にコードを実装する側にとっては、この3種類の条件を満たすよう実装しなければならない、というプラクティスです。
こうすることによって、コードの仕様が明確になる、実装側と利用側のコミュニケーションが良くなる、バグが減って品質が上がり、生産性が上がる、というメリットを得ることができます。よく見かける(見かけないか普通?)、C++やJavaのassertを使って、実装のデバッグの利便性を高めているのは、道具は使っているけれど、DBCではないのでご注意。


そしてDBCを.NET上で積極的に活用できるように、.NET Framework 4.0に、Code Contractsという機能が追加されました。


ちょっと紹介すると、






using System;
using System.Diagnostics.Contracts;


class CFoo {
    ….
    [ContractInvariantMethod]    // Invariantを使う場合に必要
    public int MethodFoo(int x)
    {
        Contract.Requires(x!=0&&this.Something>0); // 事前条件。引数は非ゼロ、Somethingプロパティは正
        Contract.Ensures(Contract.Result<int>()!=0);// 事後条件。戻り値は、非ゼロ
        Contract.Invariant(this.Something!=0);      // Somethingプロパティは非ゼロ
        ….
    }


こんな感じになります。詳細は、
http://msdn.microsoft.com/ja-jp/library/dd264808.aspx
をご覧いただくとして、Code Contractsを記述すると、以下の3つのケースで、品質を上げるのに寄与することになります。




  • 動的テスト時


  • 静的テスト時


  • ドキュメンテーション

これ、TDDのPracticeを廻すのに凄く便利だと思うのですが、残念ながら、Managedコードでしか使えないんですね。


で、これでこのポストを終わらせてしまうと、タイトルに対して嘘をついたことになってしまうので、これから組込みの濃い世界に踏み込んでいきます。私が思うに、Desktop向けやWeb向けのソフトウェアは、開発環境や実行環境がリッチなので、障害解析は比較的楽なのに対して、組込み機器向けソフトウェアは実行環境が何よりプアなので、DBCの様な仕組みがあれば非常に助かると思うんですよね。


さて、組込み機器開発の場合、Windows目線で分類すると、以下のケースが考えられます。




  1. Windows Embedded CE系 Native VC++


  2. Windows Embedded CE系 Managed(.NET Compact Framework)


  3. Windows Embedded Standard系 Native C++


  4. Windows Embedded Standard系 Managed(Full .NET)


  5. 非Windows Platform C/C++


  6. 非Windows Platform それ以外

このうち、4は、.NET Framework 4.0とまったく同じなので、そのまま使えるので、ここではおいておきます。


2の場合は、そうですねぇ、Compact Frameworkでは、Code Contractsはサポートしていませんね。まぁ開発環境がリッチなのと、ソースコードレベルでは、Full .NETと互換性があるので、デスクトップでCode Contractsを使って、そのソースコードを流用する方法がありでしょうか。


6の場合は、私のブログのスコープからは外れているので、ここでは取り上げません。


気を取り直して、1、3、5の場合で使えそうなテクニックを紹介します。5の場合、選択したHWプラットフォームがよっぽど特殊でない限り、C/C++は、ANSI等の言語標準に従っているはずです。ですから、コンパイルするだけなら、Visual StudioのVC++ Native Compilerでもコンパイルは可能です。コンパイルができれば、VC++ CLIの機能を使えば、VC++ Managed Codeから、VC++ Native Codeにアクセスできるので、Code Contractsを使う方策が見えてきます。


ちなみにCLIとは、Common Language Infrastructureの略です。
VC++は、C#やVBと同じく、.NET Frameworkの豊富なライブラリーを利用できるManagedプログラミングと、昔ながらのC/C++と同じくメモリ管理等、すべて自分の責任で処理を行うNativeプログラミングの二種類があります。
C#やVBが、COMやWin32といったNativeプログラムで書かれたAPIにアクセスする場合、COM Interop等の機能を使わなければならないのに対して、VC++は、ManagedコードとNativeコードを、プログラム上は境界なく行き来できるんですね。デバッグでも、ステップ実行しながらManagedの制御文とNativeの制御文を、行きつ戻りつ、できます。これを可能にしているのがCLIの機構です。


当然、VC++のManagedコードでCode Contractsは使えるので、Managedコードで、VC++ NatviceコードのメソッドをコールするWrapperを作り、そこに、Code Contractsを埋め込んでやれば良いわけです。






using namespace System;
using namespace System::Diagnostics::Contracts;


class CFoo {
public:
    ….
    [ContractInvariantMethod]    // Invariantを使う場合に必要
    int MethodFoo(int x)
    {
        Contract::Requires(x!=0&&this->Something>0); // 事前条件。引数は非ゼロ、Somethingプロパティは正
        Contract::Ensures(Contract::Result<int>()!=0);// 事後条件。戻り値は、非ゼロ
        Contract::Invariant(this->Something!=0);      // Somethingプロパティは非ゼロ
        ….
    }


ちなみに、VC++ Managedの場合はこんな感じ。


このManagedコードのWrapperに対して、テストコードを書けば、Visual Studio 2010のTest Managementに組み込むことも可能になります。当然テスト対象のC/C++コードモジュールが必要とする下位モジュールを置き換えるStubも必要になりますが、この形にしておけば、より扱いやすPC上で、組込み向けソフトウェアのロジックテストができるようになるわけです。組込み向けのソフトウェアは最終的には、実機上で動くのですが、自由度の利く開発環境で十分テストする事は非常に重要です。昔(といっても2年前)、ETロボコンのLego Mindstorms RCXロボット向けのSoftware Factory(残念ながらVS2005向け)を作ったことがあって、ここで書いたようなEmulatorを実際に開発しました。(当時はCode Contractsが無かったので使ってはいませんが…)。時間があれば、今年のLego Mindstorms NXTロボット向けに、Windows上で動くEmulatorを開発してみたいところです。


・・・ここまで読んできて、「でもさぁ、Stub書いて、Managed Wrapper書いて、あれ書いてこれ書いて・・・手間が増えてやりたくない・・・」、と思ってないですか?
コードから書き始めて、コードオンリーな開発の場合、その通り!!なのですが、UML等を使ったモデリングによる設計をコーディングの前にやっておけば、StubやManaged Wrapper、テストドライバーなどなど、モデルからの生成が可能です。やりかたは?、そう、このブログで説明している、UMLへのプログラムからのアクセスや、Preprocessed Text Templateの活用なんですねぇ。


と、最近のポストに上手くつなげて、今回はこれでおしまい。

Comments (1)

  1. sasaminn より:

    検索をかけるとCode Contractsの使い方というか、コードの書き方は色々と出てくるんですが、いまいちありがたみがピンときていません。「契約による設計」という概念に立脚したものなら、まずは技術的なことよりも、この概念自体を理解した方がよさそうですね。

Skip to main content