私は最近、コマンドとクエリメソッドの両方であるメソッドをリファクタリングしていました。
それを1つのコマンドメソッドと1つのクエリメソッドに分離した後、コマンドを呼び出してクエリから値を取得するコード内の複数の場所があり、これはDRYの原則に違反しているようです。
しかし、その一般的なコードをメソッドにラップすると、そのメソッドはコマンドとクエリの両方になります。これは受け入れられますか?
私は最近、コマンドとクエリメソッドの両方であるメソッドをリファクタリングしていました。
それを1つのコマンドメソッドと1つのクエリメソッドに分離した後、コマンドを呼び出してクエリから値を取得するコード内の複数の場所があり、これはDRYの原則に違反しているようです。
しかし、その一般的なコードをメソッドにラップすると、そのメソッドはコマンドとクエリの両方になります。これは受け入れられますか?
回答:
相反する設計原則の間で考慮すべきトレードオフが常にあります。それを解決する方法は、原則の背後にある根本的な理由を見ることです。この場合、コマンドを実行せずにクエリを実行できないことは問題ですが、クエリを実行せずにコマンドを実行できないことは、通常は無害です。クエリをスタンドアロンで実行する方法がある限り、特に次のような場合、クエリ結果をコマンドに追加しない理由はありません。
QueryResult command()
{
// do command stuff
return query();
}
私は以前にCommand-Query-Separation(CQS)について聞いたことがありませんが、それは単一の責任の原則(SRP)に関連していると思われます。 。
コマンドコードが20行のコードで、クエリコードがさらに30行で、すべてが1つの関数本体にある場合、SRPに違反していることは明らかであり、CQSも想定しているため、これらの2つのロジックは互いに分離する必要があります。
ただし、架空の例では、コードの多くの場所でDRYに違反しないように、コマンドとクエリを組み合わせるラッパーメソッドを作成する可能性が最も高くなります。これもSRP(およびおそらくCQS)違反とは見なしません。これは、ラッパーが責任を1つだけ持っているためです。コマンドをクエリと組み合わせて、より簡単に使用できるより高いレベルの抽象化を作成することです。
ラッパーメソッドは完全に許容できるソリューションだと思います。それを説明するために、例をさらに一歩進めましょう。1つではなく2つのクエリを実行し、それに基づいてコマンドアクションを実行する必要がある場合はどうでしょうか。したがって、2行のコードは6または8になります。一方と他方の間にデータの検証/チェックがあったとすると、15行のコードになります。15行を複数のファイルに振り分けるのではなく、それをすべて行うラッパーを作成することを2度考えますか?
DRYは、より根本的なニーズを解決するため、より重要です。冗長で効果的に無駄な労力を回避します。これは基本的なことです-それを理解するためにプログラマである必要はありません。
CQSは、結果を追跡する効果をサポートしていない言語で、その結果と影響の両方に対して実行されるコードを理解することの困難さへの対応です。しかしながら:
これは小さなユニットから大きなプログラムを作成するための基礎であるため、その結果のためにコードを実行する必要性は避けられません。
数学や理論的なコンピューターサイエンス以外では、プログラムを実行することの価値は、それが目に見えて私たちに何ができるかによって決まるため、その効果のためにコードを実行する必要性も避けられません。
同じコードでエフェクトを生成して結果を生成する必要性は避けられません。実際には、どちらか一方だけではなく、エフェクトと構成性の両方が必要だからです。
人間の助けなしでは効果を追跡するのが難しいという問題の実際の解決策は、もちろん、コンピュータで 人間を助けることです!例外とランタイム強制コントラクトが(非)ソリューションを構成するランタイム値(配列インデックスの有効性など)間の複雑な関係の追跡についても、同様のことが言えます。
結論として、CQSのような「ソリューション」は、現実に基づく健全な原則に従ってプログラムを設計することの邪魔になるだけです。DRYに行く。