일관성 및 Use Right Tool For Right Job 중 무엇이 중요합니까?
7040 단어 작업
배경은 다음과 같습니다.
하나의 인터페이스에는 여러 가지 엉망진창인 업무와 관련된 방법이 있는데 그 중에서 네 가지 방법이 있다.
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 클래스를 만듭니다. 이 클래스는 401k와 403g에 대한 논리적 처리를 추가합니다.
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。
}
그래.몇몇 코드가 중복되다.주로 이 인터페이스를 잘 설계하지 못했기 때문이다.다행히 중복이 많지 않으니 아쉬운 대로 하자.
다음은 테스트 코드를 쓰겠습니다.먼저 401k에 대한 코드를 어떻게 쓰는지 봅시다.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 대상에서 대응하는 함수를 호출합니다.
다음은 401k와 403g의 논리가 거의 똑같고 방법명만 다르다는 것을 알아차렸다.그래서 코드가 중복되는 것을 피하기 위해서, 나와pair는 abstract class로 공통성을 추출하기로 결정했다.그리고 두 개의 자류로 서로 다른 점을 대표한다.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()와 다른 몇 가지 방법이 있는데 401k와 403g은 방법 이름이 다른 것을 제외하고는 모두 같다.
그러나pair는 easymock으로 이 방안을 총살했다는 말을 듣자마자 곧바로 총살했다.pair의 관점:
일치성을 유지하기 위해서 우리는 반드시 jmock을 써야 한다.easymock을 사용하면 회사의 다른 프로그래머들에게 이해에 어려움을 줄 수 있다.(나는 내 테스트 케이스 몇 개가 모두 easymock아를 사용한다고 매우 겸허하게 생각한다.)
이 견해에 대해 나는 어떻게 말해야 할지 좀 모르겠다.나의 지금까지의 관점은 모두use the right tool for the right job이다.
만약 공구갑이 기능 1, 2, 3, 4를 할 수 있다면 공구을은 기능 3, 4, 5, 6을 할 수 있다.그럼 일치성을 유지하기 위해 갑만 쓰거나 을만 쓰도록 강요하지는 않겠습니다.만약에 회사 표준의ComplexTool이 기능 1,2,3,4,5,6, 업계 표준의SimpleTool(예를 들어java.util.HashMap)을 할 수 있다면 나는 기능 2,3,4,5,6을 필요로 하지 않는다. 그러면 나는SimpleTool을 선택할 것이다.
더군다나 기술을 강조하는 회사에서 여러분들이 easymock이나 jmock을 사용하지 않을까 봐 걱정되는 것은 정말 필요합니까?아무래도 jmock이든 easymock이든 30분이면 파악할 수 있는 겨울이죠?
사실 일치성을 강조하는 문제에 관해서 나는 이미 동료들과 몇 차례 의견 차이가 있었다.또 한 번은 회사에서 내부적으로 만들어진 MyProperty Factory 프레임워크로class path 안의property 파일 내용을 읽는 경우가 대부분이다.제가 한 번 독립적으로 개발한 모듈은 ClassLoader를 직접 사용했습니다.loadResourceAsInputStream().그래서 동료는 일치성을 이유로 MyPropertyFactory를 사용하기 위해 코드를 변경해 달라고 요구했다.세부 사항은 다음 disagree에서 설명할게요.
그렇다면 일치성과use the right tool은 정말 모순되는 것일까?너는 어떻게 둘 사이의 균형을 이룰 수 있니?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
개인 FLEX 지식 라이브러리 작업 노트[size=large]1、 이 방법은 TileWindows 팝업 창에 있습니다. TitleWindows의 maxWidth와 maxHeight를 지정하지 않으면 최대 값이 화면 전체에 깔립니다. 페이지의minHeigh...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.