第18章 開発

18.1. 方法論の概要

以下の図は、OptaPlanner ソースコードの全体的な構造を示します。

methodologyOverview

上の図では、設定とランタイムクラスの明確な境界を理解することが重要です。

開発体系には、以下が含まれます。

  • 再利用: 例は、統合テスト、ストレステスト、およびデモで再利用されます。ドキュメントのイメージはスライドで再利用されます。
  • 一貫した用語: 各例には App クラス (実行可能なクラス)、Dao (Data Access Object)、Panel (swing UI) が使われています。
  • 一貫性した構造: 各例では同じパッケージが使われています (domainpersistenceappsolver、および swingui)。
  • 現実世界の有用性: 例ではすべての機能が使用されています。ほとんどの例は、実在する制約を使用した実在するユースケースで、多くの場合、実在するデータが使用されています。
  • 自動テスト: ユニットテスト、統合テスト、パフォーマンス不具合テスト、およびストレステストがあり、テスト対象は広範囲です。
  • フェイルファーストと理解可能なエラーメッセージ: 無効な状態は、できるだけ早く確認されます。

18.2. 開発ガイドライン

  1. フェイルファーストには段階がいくつかあります (重大度は、下になるほど悪くなります)。

    1. コンパイル時の失敗。たとえば、String または Integer が必要な場合に、Object をパラメーターとして取りません。
    2. 起動時の失敗。たとえば、設定パラメーターに正の int が必要な場合に負の値を設定すると失敗します。
    3. ランタイム時の失敗。たとえば、リクエストで 0.0 から 1.0 までの二重階層が必要な場合に、1.0 より大きい値を設定すると失敗します。
    4. アサーションモードにおけるランタイム時の失敗 (検出のパフォーマンスコストが高い場合)。たとえば、低水準の反復後に必ず変数 A を B の 平方根にする必要がある場合は、アサートフラグが true に設定されている場合に限りそれを確認します (通常は EnvironmentMode で制御)。
  2. 例外メッセージ

    1. 例外メッセージには、以下のように、関連する変数の名前およびステータスが含まれます。

      if (fooSize < 0) {
          throw new IllegalArgumentException("The fooSize (" + fooSize + ") of bar (" + this + ") must be positive.");
      }

      出力では、問題が明確に説明されています。

      Exception in thread "main" java.lang.IllegalArgumentException: The fooSize (-5) of bar (myBar) must be positive.
          at ...
    2. 可能な限り、例外メッセージにはその背景が含まれます。
    3. 修正方法が明らかではない場合は、例外メッセージにアドバイスが含まれます。アドバイスは通常、行が変わり、 maybe という単語から始まります。

      Exception in thread "main" java.lang.IllegalStateException: The valueRangeDescriptor (fooRange) is nullable, but not countable (false).
      Maybe the member (getFooRange) should return CountableValueRange.
          at ...

      maybe という単語は、そのアドバイスがすべてのケースで正しいことが保証できないことを示しています。

  3. ジェネリック型。しばしば、Solution クラスがジェネリック型パラメーターとしてサブシステムに渡されます。PlanningEntity クラスがジェネリック型パラメーターとして渡されることはほとんどありません。