コンシステンシとUse Right Tool For Right Jobのどちらが重要ですか?
6820 ワード
この争いはテストの時に発生した.
背景は次のとおりです.
1つのインタフェースには、めちゃくちゃなビジネス関連の方法がたくさんあります.その中には、次の4つの方法があります.
もちろん、このデザインはちょっとよくありません.もっと良いのは、
しかし、様々な理由で、この設計を採用することはできません(主にこのように変更すると、変更が大きくなります.このシステムにはwsdlコードジェネレータがあり、このジェネレータはインタフェースの長さに変態の要求があります).だから間に合わせにします.
PerAccountTaxLawBucketsクラスを作成します.このクラスは401 kと403 gに追加の論理処理があります.
うん.いくつかのコードが重複しています.主にこのインタフェースの設計が悪いからです.幸いなことに、重複が少ないので、間に合いましょう.
次はテストコードを書きます.まず401 kに対するコードの書き方を見てみましょう.pairはjmockを使っています.
他のテストもjmockでexpectationを設定し、perAccountオブジェクトから対応する関数を呼び出します.
次に,401 kと403 gの論理はほぼそっくりであり,メソッド名のみが異なることに気づく.だからコードの重複を避けるために、私とpairはabstract classで共通性を抽出することにしました.次に、異なる点を2つのサブクラスで表します.pairのコードはこうです.
私はgetRemainingName()とgetRemainingの重複があまり好きではありません.easymockで書くことをお勧めします.
これにより、重複が減少し、コードがよりきれいに感じられます.
実は、この例は問題を簡略化した.実際のそのプログラムは、getRemaining()、apply()のほかに、restore()や他のいくつかの方法もあり、401 kと403 gは方法の名前が違う以外は同じです.
しかし、pairはeasymockで直接この案を銃殺したと聞いた.pairの観点:
一貫性を保つためにjmockを使うべきです.easymockの使用は、会社の他のプログラマーに理解上の困難をもたらします.△私のいくつかのtest caseはeasymock亜を使っていると思います.
この言い方に対して、私は少しどう言ったらいいか分かりません.私のこれまでの観点は、use the right tool for the right jobです.
ツール甲が機能1,2,3,4を行うことができれば、ツール乙は機能3,4,5,6を行うことができる.では、私は一致性を保つために甲だけを使うか、乙だけを使うように強制することはありません.一方、1つの会社の標準的なComplexToolが機能1,2,3,4,5,6をすることができ、1つの業界標準のSimpleTool(java.util.HashMapなど)が機能1をすることができ、私は機能2,3,4,5,6を必要としないので、SimpleToolを選択します.
まして、技術を強調する会社では、easymockやjmockを使わないのではないかと心配しています.なにしろjmockもeasymockも30分で身につくはずの冬冬だろ?
実は、このような一致性を強調する問題について、私はもう同僚と何度も意見が分かれています.もう1つは、社内で作ったMyPropertyFactory frameworkでclass pathのpropertyファイルの内容を読み取ることが多いことです.私が独立して開発したモジュールはClassLoaderを直接使用しましたloadResourceAsInputStream().そこで、同僚は一貫性を理由に私にMyPropertyFactoryを使用するためにコードを変更するように要求した.具体的な詳細は次のdisagreeで説明します.
では、一致性とuse the right toolは本当に矛盾しているのだろうか.どうやって両者のバランスを取るのですか?
背景は次のとおりです.
1つのインタフェースには、めちゃくちゃなビジネス関連の方法がたくさんあります.その中には、次の4つの方法があります.
interface TaxLawBuckets {
double getRemaining401k();
double getRemaining403g();
void apply401k(double amount);
void apply403g(double amount);
}
もちろん、このデザインはちょっとよくありません.もっと良いのは、
interface TaxLawBuckets {
TaxLawBucket get401k();
TaxLawBucket get403g();
}
interface TaxLawBucket {
double getRemaining();
void apply(double amount);
}
しかし、様々な理由で、この設計を採用することはできません(主にこのように変更すると、変更が大きくなります.このシステムにはwsdlコードジェネレータがあり、このジェネレータはインタフェースの長さに変態の要求があります).だから間に合わせにします.
PerAccountTaxLawBucketsクラスを作成します.このクラスは401 kと403 gに追加の論理処理があります.
interface TaxLawBuckets {
private double bucket_401k;
private double bucket_403g;
private TaxLawBuckets globalBuckets;
public double getRemaining401k(){
return Math.min(bucket_401k, globalBuckets.getRemaining401k());
}
public double getRemaining403g() {
return Math.min(bucket_403g, globalBuckets.getRemaining403g());
}
public void apply401k(double amount) {
bucket_401k -= amount;
if(bucket_401k<0) throw new SystemException(...);
globalBuckets.apply401k(amount);
}
public void apply403g(double amount) {
bucket_403g -= amount;
if(bucket_403g<0) throw new SystemException(...);
globalBuckets.apply403g(amount);
}
// globalBuckets。
}
うん.いくつかのコードが重複しています.主にこのインタフェースの設計が悪いからです.幸いなことに、重複が少ないので、間に合いましょう.
次はテストコードを書きます.まず401 kに対するコードの書き方を見てみましょう.pairはjmockを使っています.
public class PerAccountTaxLawBucketsTest extends MockObjectTestCase {
Mock bucketsMock = mock(TaxLawBuckets.class);
TaxLawBuckets globalBuckets = bucketMock.proxy();
PerAccountTaxLawBuckets perAccount = new PerAccountTaxLawBuckets(100, 100, globalBuckets);
public void testGetRemaining401kReturnsTheMinimal() {
bucketsMock.expects(once()).method("getRemaining401k").will(return(200));
assertEquals(100, perAccount.getRemaining401k());
}
...
}
他のテストもjmockでexpectationを設定し、perAccountオブジェクトから対応する関数を呼び出します.
次に,401 kと403 gの論理はほぼそっくりであり,メソッド名のみが異なることに気づく.だからコードの重複を避けるために、私とpairはabstract classで共通性を抽出することにしました.次に、異なる点を2つのサブクラスで表します.pairのコードはこうです.
public abstract class AbstractPerAccountTaxLawBucketsTest extends MockObjectTestCase {
Mock bucketsMock = mock(TaxLawBuckets.class);
TaxLawBuckets globalBuckets = bucketMock.proxy();
PerAccountTaxLawBuckets perAccount = new PerAccountTaxLawBuckets(100, 100, globalBuckets);
public void testGetRemainingReturnsTheMinimal() {
bucketsMock.expects(once()).method(getRemainingName()).will(return(200));
assertEquals(100, getRemaining(perAccount));
}
...
abstract String getRemainingName();
abstract double getRemaining(TaxLawBuckets buckets);
abstract String getApplyName();
abstract void apply(TaxLawBuckets buckets, double amount);
...
}
public class PerAccount401kTestCase extends AbstractPerAccountTaxLawBucketsTest {
String getRemainingName() {
return "getRemaining401k";
}
double getRemaining(TaxLawBuckets buckets) {
return buckets.getRemaining401k();
}
String getApplyName() {
return "apply401k";
}
void apply(TaxLawBuckets buckets, double amount) {
buckets.apply401k(amount);
}
}
public class PerAccount403gTestCase extends AbstractPerAccountTaxLawBucketsTest {
String getRemainingName() {
return "getRemaining403g";
}
double getRemaining(TaxLawBuckets buckets) {
return buckets.getRemaining403g();
}
String getApplyName() {
return "apply403g";
}
void apply(TaxLawBuckets buckets, double amount) {
buckets.apply403g(amount);
}
}
私はgetRemainingName()とgetRemainingの重複があまり好きではありません.easymockで書くことをお勧めします.
public abstract class AbstractPerAccountTaxLawBucketsTest extends TestCase {
MockControl bucketsMock = MockControl.createControl(TaxLawBuckets.class);
TaxLawBuckets globalBuckets = bucketMock.getMock();
PerAccountTaxLawBuckets perAccount = new PerAccountTaxLawBuckets(100, 100, globalBuckets);
public void testGetRemainingReturnsTheMinimal() {
bucketsMock.expectsAndReturn(getRemaining(globalBuckets), 200);
bucketsMock.replay();
assertEquals(100, getRemaining(perAccount));
bucketsMock.verify();
}
...
abstract double getRemaining(TaxLawBuckets buckets);
abstract void apply(TaxLawBuckets buckets, double amount);
...
}
public class PerAccount401kTestCase extends AbstractPerAccountTaxLawBucketsTest {
double getRemaining(TaxLawBuckets buckets) {
return buckets.getRemaining401k();
}
void apply(TaxLawBuckets buckets, double amount) {
buckets.apply401k(amount);
}
}
public class PerAccount403gTestCase extends AbstractPerAccountTaxLawBucketsTest {
double getRemaining(TaxLawBuckets buckets) {
return buckets.getRemaining403g();
}
void apply(TaxLawBuckets buckets, double amount) {
buckets.apply403g(amount);
}
}
これにより、重複が減少し、コードがよりきれいに感じられます.
実は、この例は問題を簡略化した.実際のそのプログラムは、getRemaining()、apply()のほかに、restore()や他のいくつかの方法もあり、401 kと403 gは方法の名前が違う以外は同じです.
しかし、pairはeasymockで直接この案を銃殺したと聞いた.pairの観点:
一貫性を保つためにjmockを使うべきです.easymockの使用は、会社の他のプログラマーに理解上の困難をもたらします.△私のいくつかのtest caseはeasymock亜を使っていると思います.
この言い方に対して、私は少しどう言ったらいいか分かりません.私のこれまでの観点は、use the right tool for the right jobです.
ツール甲が機能1,2,3,4を行うことができれば、ツール乙は機能3,4,5,6を行うことができる.では、私は一致性を保つために甲だけを使うか、乙だけを使うように強制することはありません.一方、1つの会社の標準的なComplexToolが機能1,2,3,4,5,6をすることができ、1つの業界標準のSimpleTool(java.util.HashMapなど)が機能1をすることができ、私は機能2,3,4,5,6を必要としないので、SimpleToolを選択します.
まして、技術を強調する会社では、easymockやjmockを使わないのではないかと心配しています.なにしろjmockもeasymockも30分で身につくはずの冬冬だろ?
実は、このような一致性を強調する問題について、私はもう同僚と何度も意見が分かれています.もう1つは、社内で作ったMyPropertyFactory frameworkでclass pathのpropertyファイルの内容を読み取ることが多いことです.私が独立して開発したモジュールはClassLoaderを直接使用しましたloadResourceAsInputStream().そこで、同僚は一貫性を理由に私にMyPropertyFactoryを使用するためにコードを変更するように要求した.具体的な詳細は次のdisagreeで説明します.
では、一致性とuse the right toolは本当に矛盾しているのだろうか.どうやって両者のバランスを取るのですか?