OOPSLA 발표장 옆에는 논문들을 전시해 놓고, 작성자와 토론할 수 있는 공간이 있었다. 그중에 “Embedded Domain-Specific Language“에 관한 논문이 있었는데, 그 당시 DDD에 대해서도 몰랐었고 왠지 특정 영역에서만 사용하는 언어가 뭐가 중요하지라는 생각에 그냥 지나쳤다. (더군다나 Embedded 라는 단어도 거부감이 느껴졌다.)
하지만 최근 Ruby를 공부하면서 Domain-Specific Language에 많은 관심이 생겼고, Java에서 DSL을 어떻게 사용할 수 있을까 고민하면서 이 논문을 다시 읽어보게 되었다.
Mock mainframe = mock(Mainframe.class);
Mock auditing = mock(Auditing.class);
Agent agent =
new Agent( QUANTITY,
(MainFrame)mainframe.proxy(),
(Auditing)auditing.proxy() );
public void testBuysWhenPriceEqualsThreshold() {
mainframe.expects(once())
.method("buy").with(eq(QUANTITY))
.will(returnValue(TICKET));
auditing.expects(once())
.method("bought").with(same(TICKET));
agent.onPriceChange(THRESHOLD);
}
public void testDoesNotBuyIfMainframeUnavailable() {
mainframe.stubs().method("buy")
.will(throwException(
new NotAvailableException());
auditing.expects(never()).method("bought");
agent.onPriceChange(THRESHOLD);
}
도저히 자바 문법으로 보이지 않는 JMock의 테스팅 기법(“call-chain” syntax)은 “Testing with Mock Object”라는 영역을 자바 문법안에 포함시킨 훌륭한 예임이 분명하다.
JMock이 이런 형태를 갖추기 까지는 여러 단계를 거쳐왔다. 관련 내용은 논문을 읽어보기를 권한다.
가장 기본 개념은 다음과 같다.
- Separate syntax and interpretation into layers
- Use, and abuse, the host language
문법을 정의하기 위해 인터페이스를 사용한다. 각각의 인터페이스는 하나의 구문(clause)을 정의하고 다음 구문을 정의하는 인터페이스를 리턴한다.
또한 선택사항인 구문을 정의하기 위해서 인터페이스 상속을 사용한다.
Builder를 통해 문법 인터페이스를 구현한다.
자바(host language)의 언어적 장점을 활용한다. (GC, reflection, dynamic proxied 등)
반면 EDSL 구현에 있어서 자바의 규칙을 과감히 깰 필요가 있다. OOP에서 피하는 “train-wreck” (ex order.getParty().getAddress().getPhoneNumber()) 활용, 선언적 성향이 되기 위해 클래스와 메소드 명명 형식 파괴 등 특정 영역의 사용성을 증대시키기 위한 노력이 필요하다.
4 Comments
그 문서를 읽고, 요거이 읽으면 도움이 됩니다…^^
ExpressionBuilder
http://martinfowler.com/bliki/ExpressionBuilder.html
예. 사실 마틴 파울러의 블로그에서 접하고 다시 한번 읽게된 Paper 입니다. ^^
유연한 사고와 체계화시키는 능력은 정말 대단한거 같습니다.
저희도 몇분 모여서 사내 스터디를 하는데, 따지크님 스터디랑 교류가 있으면 좋겠네요. 저희는 주로 목요일날 자녁에 하는데, 언제하시나요?
저희는 수요일에 진행하고 있습니다.
아직은 초보 루비 문법을 익히고 있는 정도입니다. 기회되면 같이 경험 공유하는 자리를 마련해보는 것도 잼있을거 같네요.