Posts Tagged ‘DSL’

DSL (Domain Specific Language)

Tuesday, October 30th, 2007

DSL(Domain Specific Language), DDD(Domain Driven Design)라는 개념이 나온지 3, 4년이 지났고 이미 현실에서 다양하게 구현되어 사용되고 있지만 여전히 DSL에 대한 정의 자체부터 많은 논란이 되고 있다. 단어 자체로는 ‘특정 문제 영역에 맞는 언어’라는 의미이지만, 보는 입장에 따라, 그리고 구현되는 방식에 따라 다양한 형태로 정의될 수 있다.

DSL에 대해서 가장 잘 정리된 글은 마틴 파울러의 포스트 DomainSpecificLanguage (번역)에서 볼 수 있다. 실제로 이번 OOPSLA 컨퍼런스에서는 Domain-Specific Modeling에 관한 워크샵이 있었고 Domain Specific Languages - Another Silver Bullet? 패널 토의를 통해 DSL에 대한 다양한 논의가 이루어졌다. (위 링크를 통해 워크샵에서 발표된 다양한 paper를 다운 받을 수 있다.)

개인적으로는 워크샵은 일요일 오전에 잠깐 참여했지만, coffee break 시간에 마틴 파울러와 다른 참가자들의 논쟁을 직접 들을 수 있었다. DSL이 도메인 전문가(domain expert)의 입장에서 작성이 가능하려면 high-level 언어(엑설?)로 작성되고 이를 code generation을 통해 일반 언어로 변환해야 한다. 하지만 이 경우는 코드 최적화가 어렵고 프로그래머가 직접 작성하는 DSL에 비해서 유연성이 떨어질 수 있다. 프로그래머가 직접 작성하는 DSL의 경우도 Internal DSL과 External DSL에 따라 테스트 용이성이나 통합 비용 등에 차이가 날 수 있다. Java의 경우 대표적인 Internal DSL에 JMock을 들 수 있다. 이와 관련해서는 이전에 작성한 포스트 Embedded Domain-Specific Language를 참고하길 바란다.

만일 DSL에 대한 개념이 잘 잡히지 않는다면 이 동영상(Introduction to Domain Specific Languages)을 보는 것도 좋을 것 같다. 마틴 파울러의 경우는 Ruby를 DSL로 선호하는데 작성이 쉽고 가독성이 좋기 때문이라고 한다. 실제로 도메인 전문가가 직접 코드를 작성하지 않더라도 코드를 이해할 수 있다면 정확한 문제 해결에 큰 도움을 받을 수 있다. 만일 금융이나 보험 관련 프로젝트를 진행하는데 해당 전문가가 JUnit을 이해하고 같이 테스트 케이스를 만들 수 있다면 정확히 무엇을 테스트해야 하는지 어떤 절차로 개발을 진행해야하는지 직접적인 도움을 얻을 수 있을 것이다. Ruby로 작성된 코드는 일반 자연어를 읽는 것과 같이 쉽게 이해되기 때문에 코드를 바탕으로 도메인 전문가와 프로그래머가 아이디어를 공유하기 좋다고 할 수 있다.

또한 3, 4년 전에 비해서 현재 DSL이 좀 더 실용적으로 다가 올 수 있는 이유로 AOP와 프레임워크의 발전을 들 수 있다. 우선 AOP의 경우 서비스 모듈 또는 컴포넌트는 DSL로 작성하고 이의 통합에 AOP를 활용할 수 있다. 각각의 모듈은 모델의 역할을 충실히 수행하고 그 외의 로깅이나 모니터링 등의 cross concern은 AOP로 통합해서 관리하는 방법을 생각해볼 수 있다. 또한 Spring과 같은 프레임워크는 Dynamic Language를 지원해주기 때문에 쉽게 External DSL을 활용할 수 있다. 통합 프레임워크를 기반으로 그 위에 각각의 도메인 영역을 구현한 DSL을 올려놓는 방법도 생각해 볼 수 있다. 앞으로는 DSL을 위한 프레임워크가 개발될 것이다. 직접 실행할 수 없더라도 UML 기반으로 코드를 생성해주는 형태도 DSL이라 할 수 있고, 앞으로 DSL 개발을 도와줄 다양한 툴이 소개될 것으로 기대된다.

마지막으로 웹 개발에도 DSL을 적용하려는 사례도 많이 소개됐다. WSL(Web Specific Language)의 대표적인 경우로 CMS(Content Management System)를 들 수 있다. 아마 대부분의 큰 규모의 사이트에서는 각자 CMS를 개발해서 사용하고 있을 것이다. 사이트 운영자가 직접 컨텐츠를 등록하거나 조작할 수 있게 관리 페이지를 제공하는 경우가 많은데, DSL 개념을 통해 접근한다면 좀 더 쉽게 동적이고 유연한 CMS 기능을 제공할 수 있을 것이다. 사실 HTML 자체가 계층적이면서 실수하기 쉬운 언어이기 때문에 WSL 제공이 어려울 수 있다. 이를 극복하기 위해서 WebDSL과 같은 다양한 시도가 진행되고 있다.

DSL은 고객을 중요시하고, 상호작용을 증대시키며, 비지니스에 초점을 맞춘 개념이다. 각각의 도메인마다 새로운 언어를 만든다면 매우 비생산적이겠지만 도메인 전문가와 개발자 모두 만족할 수 있는 DSL을 사용한다면 복잡한 특정 영역의 문제들을 빠르고 정확하게 해결할 수 있는 새로운 패러다임이 될 수 있다고 생각한다.

Embedded Domain-Specific Language

Tuesday, January 9th, 2007

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
  • 문법을 정의하기 위해 인터페이스를 사용한다. 각각의 인터페이스는 하나의 구문(clause)을 정의하고 다음 구문을 정의하는 인터페이스를 리턴한다.

    또한 선택사항인 구문을 정의하기 위해서 인터페이스 상속을 사용한다.

    Builder를 통해 문법 인터페이스를 구현한다.

  • Use, and abuse, the host language
  • 자바(host language)의 언어적 장점을 활용한다. (GC, reflection, dynamic proxied 등)

    반면 EDSL 구현에 있어서 자바의 규칙을 과감히 깰 필요가 있다. OOP에서 피하는 “train-wreck” (ex order.getParty().getAddress().getPhoneNumber()) 활용, 선언적 성향이 되기 위해 클래스와 메소드 명명 형식 파괴 등 특정 영역의 사용성을 증대시키기 위한 노력이 필요하다.