domain specific languages with groovy

57
Domain-Specific Languages With Groovy Chun-Kil Kang [email protected] , Twitter: @gilbirdk

Upload: chun-kil-kang

Post on 10-Jun-2015

2.054 views

Category:

Technology


4 download

DESCRIPTION

Domain Specific Language를 그루비로 만드는 법

TRANSCRIPT

Page 1: Domain Specific Languages With Groovy

Domain-Specific Lan-guages With Groovy

Chun-Kil [email protected], Twitter: @gilbirdk

Page 2: Domain Specific Languages With Groovy
Page 3: Domain Specific Languages With Groovy
Page 4: Domain Specific Languages With Groovy

Expressing Requirements...

Page 5: Domain Specific Languages With Groovy

해결책은 ? DSL !

• 표현력이 월등 more expressive

• 공통의 관심사 common metaphore

• 전문가 domain expert 의 도움• 비즈니스 로직과 애플리케이션 코드 분리• 순환적 라이프사이클

Page 6: Domain Specific Languages With Groovy

DSL 이란 ?

• DSL: Domain-Specific Language– “Little Language”

• Wikipedia– DSL 은 특정 작업의 사용 목적으로 설계한

프로그램 언어 .

• DSL 은 개념을 언어 구문으로 만들 수 있는 특정 범주의 지식에 한정된 언어이다 .

Page 7: Domain Specific Languages With Groovy

DSL ...

• 온 세상이 DSL–기술어 Technical Dialects

–표기법 Notations

–비즈니스 용어 Business Languages

Page 8: Domain Specific Languages With Groovy
Page 9: Domain Specific Languages With Groovy

^[\w-\.]+@([\w-]){2,4}$

Page 10: Domain Specific Languages With Groovy
Page 11: Domain Specific Languages With Groovy
Page 12: Domain Specific Languages With Groovy
Page 13: Domain Specific Languages With Groovy

DSL 의 특징• DSL 은 언어이다 .• 특정 지식의 범주를 다룬다 .• 형식을 가지고 있다 . ( 문자 or 그림 )• 결과를 산출한다 .– 객체 설정 , 데이터 구조 표현

• 내부 혹은 외부에 존재– 호스트 언어에 임베드 (E-DSL )– Standalone (custom parser)

• 어떤 질적 속성을 가짐– 가독성 readability– 가속성 writability – 유용성 usability– 검증성 testability– 확장성 extensibility

Page 14: Domain Specific Languages With Groovy

Why Groovy?!

Page 15: Domain Specific Languages With Groovy

HelloWorld.javaimport java.util.*;

public class HelloWorld{  public static void main( String[] args ) {     List langs = new ArrayList();

    langs.add( "Groovy" );     langs.add( "Grails" );     langs.add( "Griffon" );

     Collections.sort(langs );

     for( Iterator it = langs.iterator(); it.has-Next(); )        System.out.println( "Hello " + it.next() );  }}

Page 16: Domain Specific Languages With Groovy

HelloWorld.groovy

['Groovy', 'Grails', 'Griffon'].sort().each {    println "Hello $it"}

Page 17: Domain Specific Languages With Groovy

읽기 쉬운 코드 ? (Java)

Page 18: Domain Specific Languages With Groovy

읽기 쉬운 코드 ? (Groovy)

Page 19: Domain Specific Languages With Groovy

왜 Groovy 인가 ?

• 왜 Groovy 인가 ?–내부 / 임베드 DSL 생성 가능–임베드 DSL 은 Java 애플리케이션에 손쉽게

내장가능– DSL 로 커버 못하는 영역은 Groovy 사용

• Custom parser 는 ?– lexer/parser 는 구현 , 유지보수 및 사용이 복잡–추가 구현 힘듬• 복잡한 구문 구현 어려움

Page 20: Domain Specific Languages With Groovy

실세계 Groovy 적용 예• 보험 정책 위험도 계산 엔진• 은행 계좌 규칙• 대출 승인 규칙• 인력 자원 : 직원 스킬 표현• 바이러스 백신 시뮬레이션• 시나리오에 따른 마켓 데이터 생성• ...

Page 21: Domain Specific Languages With Groovy

Groovy DSLs

Page 22: Domain Specific Languages With Groovy

MarkupBuilder

new groovy.xml.MarkupBuilder().invoices { invoice(id: "4") { line("product 1") line("product 2") }}

<invoices> <invoice> <line>product 1</line> <line>product 2</line> </invoice></invoices>

Page 23: Domain Specific Languages With Groovy

Groovy DSLs

• XMLBuilder• HTMLBuilder• AntBuilder• SwingBuilder• Grails• Griffon• Gradle• Grape

Page 24: Domain Specific Languages With Groovy

Groovy 가 제공하는 것들

Page 25: Domain Specific Languages With Groovy

Java vs. Groovy

• Java– Class 행동–컴파일러가 모든 규칙 인지–행동은 바이트코드로 고정

• Groovy– Class 와 MetaClass 행동• 동적 언어

–컴파일러는 행동에 대하여 모름–행동은 완전히 실행시간에 동적임

Page 26: Domain Specific Languages With Groovy

Groovy MOP

• Meta Object Protocol

• 모든 것은 MOP 을 통함–메소드 호출 , 속성 액세스 , 연산자 ...–그래서 Groovy 는 “동적 언어”

• 완전하게 실행시간에 Groovy 코드를 커스터마이즈 가능함– 1+1=1 ? 가능함 ! 어떻게 ?

Page 27: Domain Specific Languages With Groovy

런타임 시스템 후킹• GroovyObject

– invokeMethod()– get/setProperty()

• Categories

• MetaClass– invokeConstructor() / method() / staticMethod()– invokeMissingMethod() / invokeMissingProperty()– get/setProperty()

• ExpandoMetaClass– Integer.metaClass.plus = { Integer i ->

1 }

Page 28: Domain Specific Languages With Groovy

연산자 오버로딩• + a.plus(b)• - a.minus(b)• * a.multiply(b)• / a.divide(b)• % a.modulo(b)• | a.or(b)• & a.and(b)• a[b] a.getAt(b)• a<<b a.leftShift(b)

• 환율 연산• 30.won + 15.euro

• 거리• 12.kilo.meters +

3.meters

• 병렬 , 작업 흐름• taskA & taskB | taskC

• 계좌 기입• account << 10.won• account += 10.dollar

Page 29: Domain Specific Languages With Groovy

속성에 숫자 추가• category로 숫자에 메소드와 속성 추가 가능

• class MyCategory { static Distance getMeters(Integer n) { new Distance(n, Distance.METER) }}

• use (MyCategory) { println 3.meters}

Page 30: Domain Specific Languages With Groovy

ExpandoMetaClass

• Grails 에서 ExpandoMetaClass 공헌

• Integer.metaClass.getMeters = { -> new Distance(delegate, Dis-tance.METER)}

• println 3.meters

Page 31: Domain Specific Languages With Groovy

융통성 있는 문법• 괄호 생략

– move left– monstor.move x: 3.meters, y: 4.meters– compare indicator: ’NIKEI’, withFund: ’XYZ’– account.debit amount: 30.won, in: 3.days

• 리스트와 맵 문법 내장– List

• [1, 2, 3, 4]

– Map• [a:1, b:2, c:3]

– Range• Monday..Friday

Page 32: Domain Specific Languages With Groovy

트리 구조 빌더• 트리 구조 데이터 생성 가능• 클로저를 마지막 인자로 받는 메서드 체인 호출 구조

– new MarkupBuilder().invoices { invoice( id: “4”) { line “product 1” line “product 2” }}

• 손쉽게 자신만의 빌더 생성 가능 !

Page 33: Domain Specific Languages With Groovy

BuilderSupport

• Implement BuilderSupport

• 구현 해야 하는 메서드createNode(name)createNode(name, map)createNode(name, value)createNode(name, map, value)nodeCompleted(parent, node)postNodeCompletion(parent, node)

Page 34: Domain Specific Languages With Groovy

커스텀 제어 구조• 클로저 closure를 메서드 파라메터로 전달

– unless( account.balance<0, {account.debit 10.dollars})

• 단축 표기법– unless (account.balance < 0) { account.debit 10.dollars}

• 무엇이든 만들어 보세요 !– withLock(aLock) { ... }– transactional { ... }– async { ... }– execute(within: 50.seconds) { ... }

Page 35: Domain Specific Languages With Groovy

RobotBuilder

def wallE = new RobotBuilder().robot('Wall E') { forward( dist: 20) left( rotation: 90) forward( speed: 10, duration: 5)}

wallE.go()

Page 36: Domain Specific Languages With Groovy

Builder 최종 인스턴스 구조robot

forward

dist: 20

left

rotation: 90

forward

speed: 10, duration: 5

Page 37: Domain Specific Languages With Groovy

FactoryBuilderSupport

class RobotBuilder extends FactoryBuilderSupport {

{

registerFactory( 'robot', new

RobotFactory())

registerFactory( 'forward', new ForwardMove-

Factory())

registerFactory( 'left', new LeftTurnFac-

tory())

};

}

Page 38: Domain Specific Languages With Groovy

Robotclass Robot {

String name

def movements = []

void go() {

println "$name 로봇 동작합니다 ..."

movements.each { movement ->

println movement

}

}

}

Page 39: Domain Specific Languages With Groovy

ForwardMove, LeftTurn

class ForwardMove {

def dist

String toString() { " 이동 ! 거리 ... $dist" }

}

class LeftTurn {

def rotation

String toString() { " 좌회전 ! 이동각 ... $rotation

도 " }

}

Page 40: Domain Specific Languages With Groovy

AbstractFactorypublic abstract class AbstractFactory implements Factory {

public boolean isLeaf() { return false; } public boolean onHandleNodeAttributes( FactoryBuilderSupport builder, Object node, Map attributes) { return true; } public void onNodeCompleted( FactoryBuilderSupport builder, Object parent, Object node) { } public void setParent( FactoryBuilderSupport builder, Object parent, Object child) { } public void setChild( FactoryBuilderSupport builder, Object parent, Object child) { }}

Page 41: Domain Specific Languages With Groovy

RootFactory

class RobotFactory extends AbstractFactory {

def newInstance( FactoryBuilderSupport builder,

name, value,

Map attrs) {

new Robot(name: value)

}

void setChild( FactoryBuilderSupport builder,

Object parent,

Object child) {

parent.movements << child

}

}

Page 42: Domain Specific Languages With Groovy

LeftTurnFactory

class LeftTurnFactory extends AbstractFactory {

boolean isLeaf() { true }

def newInstance( FactoryBuilderSupport builder,

name,

value, Map attrs) {

new LeftTurn()

}

}

Page 43: Domain Specific Languages With Groovy

ForwardMoveFactory

class ForwardMoveFactory extends AbstractFactory {

boolean isLeaf() { true }

def newInstance( FactoryBuilderSupport builder, name,

value,

Map attrs) {

new ForwardMove()

}

...

Page 44: Domain Specific Languages With Groovy

ForwardMoveFactory

...

boolean onHandleNodeAttributes( FactoryBuilderSupport

builder,

Object node, Map attrs)

{

if( attrs.speed && attrs.duration) {

node.dist = attrs.speed + attrs.duration

attrs.remove( 'speed')

attrs.remove('duration')

}

true

}

}

Page 45: Domain Specific Languages With Groovy

RobotBuilder

Wall E 로봇 동작합니다 ...이동 ! 거리 ... 20좌회전 ! 거리 ... 90 도이동 ! 거리 ... 15

Page 46: Domain Specific Languages With Groovy

DSL 애플리케이션 통합

Page 47: Domain Specific Languages With Groovy

통합 매커니즘• Java 6 : JSR-223 / javax.script.*

• Groovy 자체 메커니즘– GroovyShell– GroovyClassLoader

• Spring 2.0 dynamic language beans– Lang namespace– POGO customizer

Page 48: Domain Specific Languages With Groovy

Java 6 스크립팅 API

• scripting.dev.java.net 에서 Groovy 엔진 JAR 제공– CLASSPATH 에 포함시킬 것 !

• ScriptEngineManager manager = new ScriptEngineMan-ager();

ScriptEngine gEngine = manager.getEngineByName(“groovy”);

String result = (String)gEngine.eval(“’Foo’*2”);

Page 49: Domain Specific Languages With Groovy

GroovyShell

• expression 과 스크립트를 evaluate

• 바인딩을 통하여 값 입 / 출력

• evaluate 한 스크립트는 global 함수나 변수를 포함한 베이스 클래스를 가짐

Page 50: Domain Specific Languages With Groovy

GroovyShell 예• def binding = new Binding()binding.mass = 22.3binding.velocity = 10.6

def shell = new GroovyShell(binding)def expr = “mass * velocity ** 2 / 2”

assert shell.evaluate(expr) == 1252.814

Page 51: Domain Specific Languages With Groovy

GroovyClassLoader 예• GroovyClassLoader gcl = new GroovyClass-Loader();

Class greetingClass = gcl.parseClass( new File( “DSL.groovy”));

GroovyObject dsl = (GroovyObject)greetingClass.newInstance();

dsl.setMetaClass(myCustomDSLMetaClass);

Page 52: Domain Specific Languages With Groovy

DSL 설계시 고려사항

Page 53: Domain Specific Languages With Groovy

DSL 적용• 강제로 적용하지 말 것 !

• 대신 ...–사용자들이 자신들만의 DSL 을 만들도록 할 것–정기적으로 최종 사용자를 포함시킬 것–어떻게 DSL 을 사용하고 있는지 검토할 것

–사용자들에게 어떤 것이 되고 안 되는지 알려줄 것

Page 54: Domain Specific Languages With Groovy

씻고 , 닦고 , 반복• 반복 프로세스–간단하게 시작

–처음에 원하는 것을 얻을 수 없음을 상기

–관련 전문가와 브레인스토밍하며 지속적으로 개선 시켜야 함 !

Page 55: Domain Specific Languages With Groovy

방어 프로그래밍• DSL 은 샌드박스에서 실행해야 한다 .–사용자들이 애플리케이션을 다운시켜서는 안됨

• 테스트 , 테스트 , 테스트 !–우아하게 실패할 것–유효하지 않은 경우 : 에러 테스트 !–의미 있는 에러 메시지를 출력할 것

Page 56: Domain Specific Languages With Groovy

요약• DLS 은 해당 분야 전문가 domain xpert 와 개발자 사이에

공통의 상징 metaphor 으로서 공유할 수 있는 훌륭한 툴

• DSL 은 기존의 틀에 박힌 코드 없이 범주 domain 개념을 표현

• Groovy 문법과 동적 특성으로 DSL 를 쉽게 만들고 Java 애플리케이션 통합

• 고품질 적용을 고려하여 반복적 iterative 이고 방어적인 프로그래밍 .

Page 57: Domain Specific Languages With Groovy

참고자료• JavaZone 2008 Groovy DSL

– Guillaum Laforge, G2One

• Design you own Domain-Specific Language• Guillaum Laforge, SpringSource, SpringOne 2GX

• Groovy in Action– Dierk König, Guillaum Laforge, Manning Publications

• Programming Groovy– Vankat Subramaniam, PragramaticBookshelf

• Groovy 오픈캐스트– http://opencast.naver.com/gr386