web-dev-qa-db-ja.com

不変条件を確保する方法、そしてそれは正しい質問でさえありますか?

チームは次のような構造を作成しました(擬似コード):

struct Rectangle {
    int left, right, top, bottom;
}

プロジェクトの半分後、チームは、コードの3分の2がこの構造をtop < bottomの座標で埋め、残りの3分の1がtop > bottomを使用していることに気付きました。

要件は、座標がさまざまな場所(UI、インポートされたファイルなど)からシステムに入力され、さまざまな座標系にあることです。誰もがこれを知っていましたが、これまでのところ、人々は必要に応じてコード内のtopbottomをアドホックに交換していました。 Rectangleクラスは、座標系が選択されている場合にのみ交差などの一般的な操作を実装できるため、これは保守できなくなり、バグが発生します。

  1. 彼らはどうやってこれを防ぐことができたのでしょうか? (これは技術的な解決策を求めているのでしょうか、それとも人々とベストプラクティスの問題でしょうか?)
  2. top > bottomが常にあり、長方形が放出および消費される無数の場所が壊れないように、コードベースを修正するための最良のステップは何でしょうか?

契約/不変条件を実施するライブラリ?広く使用されているアプローチAFAIKではなく、CSクラスでのみ学習しました。ユニットテスト?ユニットは問題ありません、消費するコードは間違っています。ドキュメンテーション?これをコーディングする前に考えなかった人々もそれを読まないでしょう。

1
marczellm

彼らはどうやってこれを防ぐことができたのでしょうか? (これは技術的な解決策を求めているのでしょうか、それとも人々とベストプラクティスの問題でしょうか?)

まず最初に、より良いモデルを使用すれば、あいまいさを回避できた可能性があります。長方形は、ペア(xy)(または(topleft)あいまいさをさらに減らすために)、幅と高さ。

長方形に上下がある構造に固執する場合でも、ここで契約する必要はありません。 _top < bottom_(またはその逆)例外を使用してまたはアサーションクラス内であることを簡単に保証できます。言い換えると:

  • クラスの内部に誰もアクセスさせないでください。 getBottomsetBottomはOKです(または、言語にプロパティがある場合は、さらに優れています)。パブリックフィールドbottomを持つことは間違っています。

    これが、たとえば、C#のガイドラインでパブリックフィールドが禁止されている理由です。値を他のクラスに公開する場合は、プロパティを使用します。

  • setBottomに、不正なデータを入力させない特定のコントロールがあることを確認してください。不正なデータを入力しようとする場合、例外をスローすることが適切な対応です。

    上下が次々と変わる場合に対応しなければならない場合がありますのでご注意ください。たとえば、_top: 3, bottom: 7_の長方形は、10ポ​​イント下に移動します。 topを3+ 10に設定すると、13> 7であるため、例外がスローされます。クラスの使用法によっては、shiftBy(x, y)メソッドなどがある場合があります。

_top < bottom_などのルールは通常のビジネスルールです。同様に、クラスProductは、価格をゼロまたは負にすることはできないことを示すルール(特定のドメインでゼロまたは負の価格が意味をなさない限り)、およびクラスTemperatureを含む必要があります。値 -273.15°C未満 は許可されないことを指示するルールが必要です。

これらのルールはすべて、クラス自体に属しています。これは、ルールを後で変更する必要がある場合、ルールを変更する必要がある場所はクラスだけであることも意味します。

契約について言えば、CSクラスに限定されません。 たとえば 、. NETエコシステムは、コードコントラクト(不変条件を含む)を非常に簡単に宣言できるだけでなく、コントラクトの静的チェックのための非常に強力なツールも含んでいます。

エッフェル塔などの他のいくつかの言語にも契約があり、 言語のリスト全体 は非常に印象的です。

.NETで実装されているように、コントラクトの利点はその伝播です。 -300°Cの値で温度クラスを初期化する場合、例外を取得するために実行時まで待つ必要はありません。静的チェック中にエラーが発生します(場合によっては、ほぼ取得することを意味します)。すぐにIDE無効な値を入力すると)。

便利ですが、説明している状況を回避するために必要ありません。単純な例外/アサーションで十分です。

コードベースを修正して、常に上>下、および長方形が放出および消費される無数の場所が壊れないようにするための最良の手順は何でしょうか?

それは難しいことです。私はあなたが以前に問題を見つけていないことに驚いています(まあ、 多分それほど驚くことではない )。不一致が原因で、コードがときどきクラッシュし始めると思います。たとえば、長方形の面積を計算するコードがtop <bottomと想定し、top> bottomの長方形が指定されている場合、呼び出し元は、厳密に期待しているときに負の面積を受信すると、例外がスローされる可能性があります。ポジティブ。

とにかく:

  • アプリケーションの一部がtop <bottomであると想定し、他の部分がその逆を行い、両方が相互作用しない場合は、この方法で維持するか(適切な例外、アサーション、またはコードコントラクトを追加しながら)、またはjustパーツの1つを切り替えて、他の規則を使用します(実際には非常に難しい場合があります)。

  • それ以外の場合は、例外を設定してテストを実行します(テストがない場合は、 幸運 )。テストが正しく行われると、不一致のほとんどの発生が表示されます。もちろん、不一致はコンポーネント間のインターフェイスのレベルでも発生する可能性があり、単体テストでは検出されません。インターフェイスを手動でチェックし、そこに例外を追加すると役立つ場合があります(インターフェイスのあいまいさを軽減します)。

試す価値のあるもう1つの手法は、位置、幅、高さを含む新しい長方形表現を作成することです。完了したら、位置に上を使用するか下を使用するかを確実に理解しながら、コードを段階的に新しい表現に移行できます。このようにして、既存のコードを壊したり、移行中にチームの速度を低下させたりすることはありません。完了したら、古い長方形の構造を削除できます。

7