메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

혁신적인 아키텍처와 창발적 설계: Groovy로 DSL 작성하기

효율적인 관용적 패턴 활용

Neal Ford, 소프트웨어 아키텍트, IBM
Neal Ford사진
Neal Ford는 글로벌 IT 컨설팅 업체인 ThoughtWorks의 소프트웨어 아키텍트이자 Meme Wrangler이다. 애플리케이션, 교육용 자료, 매거진 기사 및 비디오/DVD 프리젠테이션을 설계 및 개발하며 다양한 기술과 관련된 서적의 저자 또는 편집자이기도 하다. 최근에 출판된 책으로는 The Productive Programmer가 있다. 대규모 엔터프라이즈 애플리케이션의 설계 및 빌드에 많은 관심을 가지고 있는 그는 전세계의 개발자 컨퍼런스에서 국제적으로 인정 받고 있는 연사로도 활동하고 있다. 그의 웹 사이트를 살펴보자.

요약:  내부 DSL(Domain-Specific Language)을 Java™ 언어로 작성할 수 있기는 하지만 구문이 제한적이기 때문에 작성하기가 까다롭습니다. JVM 기반의 다른 언어를 사용하여 내부 DSL을 작성하는 것이 더 효과적입니다. 이 혁신적 아키텍처 및 창발적 설계 기사에서는 내부 DSL을 작성하는 데 사용할 수 있는 몇 가지 기능과 Groovy를 사용할 때 발생할 수 있는 문제에 대해 살펴봅니다.

이 연재 자세히 보기

원문 게재일:  2010 년 8 월 17 일 번역 게재일:  2011 년 5 월 10 일
난이도: 중급 원문:  보기 PDF:  A4 and Letter (46KB | 11 pages)Get Adobe® Reader®
페이지뷰:  1770 회
의견:  


지난 달 기사에서는 코드에 공통 설계 관용구로 정의된 DSL(Domain-Specific Language)을 사용하여 관용적 패턴을 다듬는 방법을 보여 주는 예제를 살펴보았다. ("Composed method and SLAP에서 관용적 패턴 개념을 소개했다.") DSL은 선언적이고 "일반" 소스 코드보다 읽기가 쉬울 뿐만 아니라 사용자가 다듬어 놓은 패턴과 주위 코드를 쉽게 구별할 수 있기 때문에 패턴을 캡처하는 데 유용한 매개체이다.

DSL 작성을 위한 언어 기술에서는 암묵적으로 코드에 대한 랩핑 컨텍스트를 제공하는 효과적인 방법을 자주 사용한다. 다시 말해서, DSL에서는 코드 가독성을 높이기 위해 기본 언어의 기능을 사용하여 부수적인 구문을 "숨기려고" 시도한다. DSL을 Java 언어로 작성할 수 있기는 하지만 Java 언어는 컨텍스트 숨기기를 지원하는 구문이 충분하지 않을 뿐만 아니라 구문 규칙이 엄격하기 때문에 이 기술에 적합하지 않다. 하지만 다른 JVM 기반 언어를 사용하여 이 격차를 메울 수 있다. 이 기사와 다음 기사에서는 DSL 빌딩 팔레트를 확장하여 Java 플랫폼에서 실행되는 효율적인 언어를 포함시키는 방법에 대해 살펴볼 것이며, 먼저 Groovy부터 살펴본다(참고자료 참조).

이 시리즈의 정보

시리즈의 목적은 소프트웨어 아키텍처 및 설계와 관련하여 자주 논의되지만 정의를 명확하게 내리기 어려운 개념에 대한 신선한 관점을 제공하는 것이다. Neal Ford는 구체적인 예제를 통해 실제 애자일 개발 환경에서 경험하게 되는 혁신적 아키텍처창발적 설계에 대한 견고한 기초 지식을 제공한다. 중요한 아키텍처 및 설계 결정을 최후의 결정 순간까지 미룸으로써 소프트웨어 프로젝트에 해가 되는 불필요한 복잡성을 방지할 수 있다.

Groovy에는 DSL을 쉽게 작성할 수 있도록 지원하는 몇 가지 기능이 있다. 용량에 대한 지원은 DSL의 공통 요구사항이다. 7인치, 4마일, 13일 등과 같이 숫자는 항상 필요하다. Groovy에서는 오픈 클래스를 통해 숫자 용량에 대한 직접 지원을 추가할 수 있다. 오픈 클래스를 사용하면 기존 클래스를 다시 열어서 클래스의 메소드를 추가, 제거 또는 변경할 수 있다. 이 메커니즘은 강력하면서도 위험하다. 다행스럽게도 이 메커니즘을 안전하게 구현할 수 있는 방법이 있다. Groovy에서는 카테고리ExpandoMetaClass라는 두 종류의 구문은 오픈 클래스에 사용할 수 있다.

카테고리를 통한 오픈 클래스

카테고리 개념은 Smalltalk 및 Objective-C와 같은 언어에서 빌려온 것이다(참고자료 참조). 카테고리는 use 블록 지시문을 사용하여 하나 이상의 오픈 클래스가 포함된 코드의 호출에 대한 랩퍼를 작성한다.

카테고리는 예제를 통해 이해하는 것이 가장 효과적이다. 목록 1의 테스트 예제에서는 필자가 String에 추가한 새 메소드인 camelize()를 보여 준다. 이 메소드는 밑줄로 구분된 문자열을 카멜 표기법으로 변환한다.


목록 1. camelize() 메소드를 보여 주는 테스트

class TestStringCategory extends GroovyTestCase {
    def expected = ["event_map" : "eventMap", 
            "name" : "name", "test_date" : "testDate", 
            "test_string_with_lots_of_breaks" : "testStringWithLotsOfBreaks",
            "String_that_has_init_cap" : "stringThatHasInitCap" ]

    void test_Camelize() {
        use (StringCategory) {
            expected.each { key, value ->
                assertEquals value, key.camelize()
            }
        }
    }
}

목록 1에서는 먼저 원래 문자열과 변환된 문자열이 포함된 expected 해시를 작성한 다음 맵을 반복하는 StringCategory를 랩핑한다. 이 경우 각 키가 카멜 표기법으로 변환될 것이다. 여기에서는 use 블록 내에서 클래스의 새 메소드를 호출하기 위한 특별한 작업이 없다는 점에 유의해야 한다.

StringCategory에 대한 코드는 목록 2에 있다.


목록 2. StringCategory 클래스

class StringCategory {

  static String camelize(String self) {
    def newName = self.split("_").collect() { 
      it.substring(0, 1).toUpperCase() +  it.substring(1, it.length())
    }.join()
    newName.substring(0, 1).toLowerCase() +  newName.substring(1, newName.length())      
  }
}

카테고리는 정적 메소드가 포함된 일반 클래스이다. 정적 메소드에는 적어도 하나의 매개변수가 있어야 하며 이는 확장 중인 유형이다. 목록 2에서는 단일 정적 메소드를 선언하고 있으며, 이 메소드는 String 매개변수를(일반적으로 self라는 이름을 사용하지만 원하는 이름을 사용할 수도 있음) 사용한다. 그리고 이 매개변수는 메소드를 추가할 클래스를 나타낸다. 메소드 본문에는 문자열을 밑줄로 구분된 문자열로 분할한(split("_") 메소드가 이 작업을 수행함) 후 문자열을 다시 수집하여 대문자가 적용된 문자열로 결합하는 Groovy 코드가 있다. 마지막 행에서는 리턴된 문자열의 첫 번째 문자가 소문자인지 확인한다.

StringCategory를 사용할 경우에는 use 블록 내에서 액세스해야 한다. use 블록의 소괄호 내에서 여러 카테고리 클래스를 쉼표로 구분해서 사용할 수 있다.

다음은 오픈 클래스를 사용하여 DSL에서 용량을 표시하는 또 하나의 예제이다. 이제 간단한 약속 일정을 구현한 목록 3의 코드를 살펴보자.


목록 3. 간단한 일정 DSL

def calendar = new AppointmentCalendar()

use (IntegerWithTimeSupport) {
    calendar.add new Appointment("Dentist").from(4.pm)
    calendar.add new Appointment("Conference call")
                 .from(5.pm)
                 .to(6.pm)
                 .at("555-123-4321")
}
calendar.print()

목록 3에서는 "Fluent interfaces"의 Java 예제와 동일한 기능을 구현한다. 하지만 구문이 개선되었으며 Java 코드로 구현할 수 없는 여러 가지 기능이 포함되어 있다. 예를 들어, Groovy에서는 add() 메소드의 인수와 같이 소괄호를 생략할 수 있는 부분이 있다. 그리고 5.pm을 호출할 수도 있다. Java 개발자에게는 이 표현이 낯설 것이다. 이는 Integer 클래스를 열고(Groovy에서는 모든 숫자가 자동으로 유형 랩퍼 클래스를 사용하므로 5는 실제로 Integer임) pm 특성을 추가하는 하나의 예이다. 목록 4에서 이 오픈 클래스를 구현한 클래스를 보여 준다.


목록 4. IntegerWithTimeSupport 클래스 정의

class IntegerWithTimeSupport {
    static Calendar getFromToday(Integer self) {
        def target = Calendar.instance
        target.roll(Calendar.DAY_OF_MONTH, self)
        return target
    }

    static Integer getAm(Integer self) {
        self == 12 ? 0 : self
    }

    static Integer getPm(Integer self) {
        self == 12 ? 12 : self + 12
    }
}

이 카테고리 클래스에는 Integer에 대한 세 가지 새 메소드 즉, getFromToday(), getAm()getPm()이 있다. 이들 메소드는 실제로는 메소드가 아니라 새 특성이다. 이들을 새 특성으로 작성한 이유는 Groovy의 메소드 호출 처리 방법과 관련되어 있다. 매개변수가 없는 Groovy 메소드를 호출할 경우에는 비어 있는 괄호를 사용하여 해당 메소드를 호출해야 하는데 이 방법을 통해 Groovy에서는 특성 액세스와 메소드 호출을 구별할 수 있다. 확장을 메소드를 작성했다면 DSL에서 ampm 확장을 호출해야 하며(예: 5.pm()) 결과적으로, DSL의 가독성이 떨어진다. 가독성 향상이 DSL을 사용하는 주된 이유 중 하나이기 때문에 불필요한 부분을 제거한 것이다. 대신 Groovy에서는 확장을 특성으로 작성하여 이를 수행할 수 있다. 특성을 선언하는 구문은 Java 언어와 마찬가지로 get/set 메소드 쌍을 사용한다. 하지만 소괄호 없이 이러한 메소드를 호출할 수 있다.

이 DSL에서는 시간이 측정 단위이므로 3.pm에 대해 15를 리턴해야 한다. 용량을 지원하는 DSL을 작성할 경우에는 사용할 단위를 결정해야 하며 그런 다음 선택적으로 DSL에 추가하여 가독성을 높일 수 있다. 지금은 DSL을 사용하여 도메인 관용적 패턴을 캡처하고 있다. 이는 곧 개발자가 아니더라도 읽을 수 있다는 것을 의미한다.

지금까지 일정 DSL에서 시간을 구현하는 방법을 살펴보았다. 목록 5의 Appointment 클래스는 간단하다.


목록 5. Appointment 클래스

class Appointment {
  def name;
  def location;
  def date;
  def startTime;
  def endTime;

  Appointment(apptName) {
    name = apptName
    date = Calendar.instance
  }

  def at(loc)  {
    location = loc
    this
  }

  def formatTime(time) {
    time > 12 ? "${time - 12} PM" : "${time} AM"
  }

  def getStartTime() {
    formatTime(startTime)
  }

  def getEndTime() {
    formatTime(endTime)
  }

  def from(start_time) {
    startTime = start_time
    date.set(Calendar.HOUR_OF_DAY, start_time)
    this
  }

  def to(end_time) {
    endTime = end_time
    date.set(Calendar.HOUR_OF_DAY, end_time)
    this
  }

  def display() {
    print "Appointment: ${name}, Starts: ${formatTime(startTime)}"
    if (endTime) print ", Ends: ${formatTime(endTime)}"
    if (location) print ", Location: ${location}"
    println()
  }
}

Groovy를 전혀 모르더라도 Appointment 클래스를 어렵지 않게 읽을 수 있을 것이다. Groovy에서는 메소드의 마지막 행이 메소드의 리턴값이다. 따라서 at(), from()to() 메소드의 마지막 행(this의 리턴값)이 이 클래스의 fluent-interface 호출이 된다.

카테고리를 사용하면 기존 클래스를 제어된 방식으로 변경할 수 있다. 이러한 변경 사항의 범위는 use() 절에 정의된 렉시컬 블록으로 엄격하게 제한된다. 하지만 오픈 클래스의 추가된 메소드의 범위를 확장하려는 경우도 자주 발생하며, 이러한 경우에 Groovy의 ExpandoMetaClass를 사용할 수 있다.


Expando를 통한 오픈 클래스

Groovy의 원래 오픈 클래스 구문에서는 카테고리만 사용했다. 하지만 Groovy 웹 프레임워크를 개발한 Grails(참고자료 참조)는 카테고리의 기본적인 범위가 너무 제한적이라는 점을 발견하고 오픈 클래스의 대체 구문인 ExpandoMetaClass를 개발했다. Expando를 사용할 때는 클래스의 메타클래스(Groovy가 사용자 대신 작성)에 액세스하여 특성과 메소드를 추가한다. 목록 6에서는 expando를 사용하는 일정 예제를 보여 준다.


목록 6. Expando 오픈 클래스를 사용하는 일정

def calendar = new AppointmentCalendar()

calendar.add new Appointment("Dentist")
             .from(4.pm)
calendar.add new Appointment("Conference call")
             .from(5.pm)
             .to(6.pm)
             .at("555-123-4321")
        
calendar.print()

목록 6의 코드는 카테고리에 필요한 use 블록이 없다는 점을 제외하면 목록 3과 거의 비슷하다. Integer에 대한 변경 사항을 구현하기 위해 메타클래스에 액세스한다(목록 7 참조).


목록 7. Integer에 대한 expando 정의

Integer.metaClass.getAm = { ->
  delegate == 12 ? 0 : delegate
}                              

Integer.metaClass.getPm = { ->
  delegate == 12 ? 12 : delegate + 12
}                                

Integer.metaClass.getFromToday = { ->
  def target = Calendar.instance
  target.roll(Calendar.DAY_OF_MONTH, delegate)
  target
}  

카테고리 예제에서와 마찬가지로 이번에도 Integerampm이 메소드가 아니라 속성으로 필요하므로(따라서 소괄호를 사용해서 액세스하지 않아도 됨) 메타클래스에 새 특성을 Integer.metaClass.getAm으로 추가한다. 이러한 코드 블록에서 매개변수를 사용할 수 있기는 하지만 여기에서는 매개변수가 필요하지 않다. (따라서 코드 블록의 맨 앞에 ->만 있다.) 코드 블록 내에서 delegate 키워드는 메소드를 추가하고 있는 클래스의 인스턴스를 참조한다. 예를 들어, getFromToday 특성에서 새 Calendar 인스턴스를 작성한 다음 delegate 값을 사용하여 Integer의 현재 인스턴스에 지정된 날짜 수만큼 일정을 이동한다. 5.fromToday를 실행하면 일정이 5일 앞으로 이동한다.


카테고리와 expando 중에서 선택하기

카테고리와 expando가 동일한 종류의 표현 기능을 제공한다면 어느 것을 선택해야 할까? 카테고리의 최대 장점은 렉시컬 블록의 기본 범위 제한이다. 언어의 핵심 클래스를 근본적으로(아마도 뛰어나게) 변화시키는 것은 공통 DSL 안티패턴이다. 카테고리는 수정사항의 적용 범위를 제한한다. 이와는 달리 Expando는 기본적으로 글로벌하다. 따라서 expando 코드를 실행하면 변경사항이 애플리케이션의 나머지 부분에도 표시된다.

일반적으로 카테고리를 주로 사용한다. 부작용이 발생할 수 있는 중요한 클래스를 변경할 경우에는 변경 사항의 범위를 제한하는 것이 좋다. 카테고리를 사용하여 변경사항의 범위를 한정적으로 제한할 수 있다. 하지만 동일한 카테고리를 사용하여 점점 더 많은 코드를 랩핑하고 있다면 expando를 사용하는 것이 좋다. 일부 변경사항은 광범위하게 적용할 필요가 있으며, 블록 내에서 이러한 변경사항을 모두 적용하면 코드가 매우 복잡해질 수 있다. 일반적으로 한 카테고리에서 세 개 이상의 서로 다른 코드 묶음을 랩핑하고 있다면 expando로 작성하는 것이 좋다.

마지막으로 하나 더 언급할 내용이 있다. 그것은 바로 여기에서는 테스트가 선택사항이 아니라는 것이다. 수많은 개발자가 코드의 많은 부분에 대한 테스트를 선택사항으로 생각하고 있는 것처럼 보인다. 하지만 기존 클래스를 변경하는 모든 코드는 종합적인 테스트를 거쳐야 한다. 핵심 클래스를 수정하는 기능은 강력하기도 하고 매우 좋은 문제점 해결 방법을 제공하기도 한다. 하지만 힘에는 책임이 따르기 마련이며, 이 책임이 바로 테스트이다.


실전 예제

관용적 패턴을 캡처하는 방법으로서 DSL에 대해 논의한 지금까지의 내용이 조금 추상적으로 보일 것이기에 이제 마지막으로 실전 예제를 살펴보자.

easyb(참고자료 참조)는 Groovy 기반 작동 주도 개발 테스트 도구이다. 이 도구를 사용하면 비개발자에게 친근한 산문과 코드를 결합하여 테스트를 구현하는 시나리오를 작성할 수 있다. 목록 8에서 예제 easyb 시나리오를 볼 수 있다.


목록 8. 큐를 테스트하는 easyb 시나리오

package org.easyb.bdd.specification.queue

import org.easyb.bdd.Queue

description "This is how a Queue must work"

before "initialize the queue for each spec", {
    queue = new Queue()
}

it "should dequeue item just enqueued", {
    queue.enqueue(2)
    queue.dequeue().shouldBe(2)
}

it "should throw an exception when null is enqueued", {
    ensureThrows(RuntimeException.class) {
        queue.enqueue(null)
    }
}

it "should dequeue items in same order enqueued", {
    [1..5].each {val ->
        queue.enqueue(val)
    }
    [1..5].each {val ->
        queue.dequeue().shouldBe(val)
    }
} 

목록 8의 코드에서는 큐의 적절한 작동을 정의한다. 각 선언 블록은 it로 시작하며, 뒤를 이어 문자열 설명과 코드 블록이 있다. it에 대한 메소드 정의는 다음과 같다. 여기서, spec은 테스트를 설명하며, closure는 코드 블록을 가지고 있다.

def it(spec, closure)

목록 8의 마지막 테스트에서는 다음 코드 행을 사용하여 dequeue() 호출의 리턴값을 확인한다.

queue.dequeue().shouldBe(val)

그러나 Queue 클래스를 살펴보면 shouldBe() 메소드가 없다는 것을 알 수 있다. 이 메소드의 출처는 어디일까?

it() 메소드의 정의를 보면 카테고리를 사용하여 기존 클래스를 확장하는 부분이 있다. 목록 9에서는 it() 메소드의 선언을 보여 준다.


목록 9. it() 메소드의 선언

def it(spec, closure) {
    stepStack.startStep(listener, BehaviorStepType.IT, spec)
    closure.delegate = new EnsuringDelegate()
    try {
        if (beforeIt != null) {
            beforeIt()
        }
        listener.gotResult(new Result(Result.SUCCEEDED))
    use(BehaviorCategory) {
            closure()
        }
        if (afterIt != null) {
            afterIt()
        }
    } catch (Throwable ex) {
        listener.gotResult(new Result(ex))
    }
    stepStack.stopStep(listener)
}

메소드의 중간 부분에서 매개변수로 전달된 closure 블록이 BehaviorCategory 클래스 내에서 실행된다. 목록 10에서 이와 관련된 발췌 부분을 볼 수 있다.


목록 10. BehaviorCategory 클래스의 일부

static void shouldBe(Object self, value, String msg) {
    isEqual(self, value, msg)
}

private static void isEqual(self, value, String msg) {
    if (self.getClass() == NullObject.class) {
        if (value != null) {
            throwValidationException(
                "expected ${value.toString()} but target object is null", msg)
        }
    } else if (value.getClass() == String.class) {
        if (!value.toString().equals(self.toString())) {
            throwValidationException(
                "expected ${value.toString()} but was ${self.toString()}", msg)
        }
    } else {
        if (value != self) {
            throwValidationException("expected ${value} but was ${self}", msg)
        }
    }
}

BehaviorCategoryObject를 확장하는 메소드를 가지고 있는 카테고리이며 오픈 클래스의 뛰어난 장점을 보여 준다. 새 메소드를 Object에 추가하면 애플리케이션의 모든 인스턴스에서 해당 메소드에 액세스할 수 있기 때문에 shouldBe() 메소드를 모든 클래스에(Queue 포함) 쉽게 추가할 수 있다. 핵심 Java 코드로는 이 작업을 수행할 수 없으며, 수행한다고 하더라도 여러 면에서 복잡할 것이다. 이번에도 카테고리를 사용하므로 앞에서 언급한 대로 Object에 대한 변경사항의 범위는 easyb DSL에 있는 use 절의 본문으로만 제한된다.


결론

필자는 다듬어 놓은 관용적 패턴을 코드의 나머지 부분에서도 적극 활용하려고 한다. 그리고 DSL은 이 목표를 달성하는 데 적합한 경쟁력 있는 메커니즘을 제공한다. Java 언어와는 달리 DSL 작성 기능을 지원하는 언어에서 DSL을 훨씬 쉽게 작성할 수 있다. 조직 내의 외적 요인으로 인해 비Java 언어를 사용하기가 어렵더라도 포기하지 마라. Spring 프레임워크와 같은 도구에서는 Groovy나 Clojure와 같은 대체 언어에 대한 지원이 늘어나고 있다(참고자료 참조). 이러한 언어를 사용하여 컴포넌트를 작성한 다음 Spring을 통해 애플리케이션의 적절한 위치에 컴포넌트를 주입할 수 있다. 대체 언어를 지나치게 보수적으로 대하는 조직이 많기는 하지만 Spring과 같은 프레임워크를 통해 손쉽게 확장할 수 있는 방법이 있다.

다음 기사에서는 몇 가지 JRuby 예제를 통해 DSL을 사용하여 도메인 관용적 패턴을 개발하는 방법을 살펴보면서 언어의 표현 기능을 얼마나 많이 확대할 수 있는지 보여 줄 것이다.


참고자료

교육

  • The Productive Programmer(Neal Ford 저, O'Reilly Media, 2008년): 이 시리즈의 다양한 주제를 확장해 놓은 Neal Ford의 최신 저서이다.

  • Practically Groovy: Groovy의 실제 사례를 살펴보는 이 developerWorks 시리즈에서는 Groovy를 성공적으로 적용하는 시점과 방법에 대해 배울 수 있다.

  • Grails 마스터하기: 이 developerWorks 기사 시리즈를 통해 Grails에 대해 자세히 알아보자.

  • "Drive development with easyb"(Andrew Glover 저, developerWorks, 2009년 11월): 이 튜토리얼에서는 easyb를 통해 개발자와 다른 관계자의 의사소통을 향상시키는 방법에 대해 설명한다.

  • Objective_C: 이 Wikipedia 기사에서는 예제와 함께 카테고리의 기원에 대해 설명한다.

  • developerWorks Java 기술 영역: Java 프로그래밍과 관련된 모든 주제를 다루는 여러 편의 기사를 찾아보자.

제품 및 기술 얻기

  • Groovy: Groovy는 수많은 엔터프라이즈 Java 에코시스템에서 지원되는 최신 동적 Java 언어이다.

  • Grails: Grails는 Ruby on Rails의 영향을 받아 Groovy 기반으로 작성된 웹 프레임워크이다.

  • easyb: easyb는 이 기사에서 다룬 여러 가지 기술을 사용하는 Groovy로 구현된 작동 주도 개발 테스트 도구이다.

  • Clojure: Clojure는 JVM에서 실행되는 순수 함수 언어로 개정된 최신 Lisp 언어이다.

토론

  • My developerWorks 커뮤니티에 참여하자. 개발자가 이끌고 있는 블로그, 포럼, 그룹 및 Wiki를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다.

필자소개

Neal Ford사진

Neal Ford는 글로벌 IT 컨설팅 업체인 ThoughtWorks의 소프트웨어 아키텍트이자 Meme Wrangler이다. 애플리케이션, 교육용 자료, 매거진 기사 및 비디오/DVD 프리젠테이션을 설계 및 개발하며 다양한 기술과 관련된 서적의 저자 또는 편집자이기도 하다. 최근에 출판된 책으로는 The Productive Programmer가 있다. 대규모 엔터프라이즈 애플리케이션의 설계 및 빌드에 많은 관심을 가지고 있는 그는 전세계의 개발자 컨퍼런스에서 국제적으로 인정 받고 있는 연사로도 활동하고 있다. 그의 웹 사이트를 살펴보자.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=자바
ArticleID=657288
ArticleTitle=혁신적인 아키텍처와 창발적 설계: Groovy로 DSL 작성하기
publish-date=08172010
author1-email=nford@thoughtworks.com
author1-email-cc=jaloi@us.ibm.com

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.