도메인 전용 언어
- DLS은 특정 비즈니스 도메인의 문제를 해결하려고 만든 언어다. 예를 들어 회계전용 소프트웨어 애플리케이션을 개발한다고 가정, 이 상황에서 비즈니스 도메인에는 통장 입출금 내역, 계좌와 같은 개념이 포함된다.
- DSL은 평문 언어가 아니며, 도메인 전문가가 저수준 비즈니스 로직을 구현하기 위해 사용하는것이 아니다. 다음 뚜 가지 필요성을 생각하며 DSL을 개발해야 한다.
- 작성자 코드의 의도가 명확히 전달되어야 한다.
- 가독성이 좋게 코드를 작성해야 한다.
DSL의 장점과 단점
- DSL의 장점
- 간결함: API는 비즈니스 로직을 간편하게 캡슐화 하여 코드가 간결해지며 중복을 줄일 수 있다.
- 가독성: 도메인 영역의 용어를 사용하므로 비 도메인 전문가도 코드를 쉽게 이해할 수 있다.
- 유지보수: 잘 설계된 DSL은 도메인과 같은 추상화 수준에서 동작하므로 도메인의 문제와 직접적으로 관련되지 않은 세부 사항을 숨긴다.
- 높은 수준의 추상화: DSL은 도메인과 같은 추상화 수준에서 동작하므로 도메인의 문제와 직접적으로 관련되지 않은 세부 사항을 숨긴다.
- 관심사 분리: 지정된 언어로 비즈니스 로직을 표한함으로 애플리케이션의 인프라 구조와 관련된 문제, 독립적으로 비즈니스 관련된 코드에 집중하기가 용이하다.
- DSL의 단점
- 설계의 어려움: 간결하게 제한적인 언어에 도메인 지식을 담는 것이 쉬운 작업이 아니다.
- 개발 비용: 코드에 DSL을 추가하는 작업은 초기 프로젝트에 많은 비용과 시간이 소모되는 작업이다. 또한 DSL 유지보수와 변경은 프로젝트에 부담을 주는 요소이다.
- 새로 배워야 하는 언어: 요즘 추세는 하나의 프로젝트에도 여러가지 언어를 사용한다. DSL을 프로젝트에 추가하며 배워야 하는 언어가 늘어난다는 부담이 생긴다. (실무에서도 이런 비슷한 이유로 신기술을 도입하지 않았다.)
- 호스팅 언어 한계: 자바 같은 언어는 장황하고 엄격한 문법을 가졌다. 이런 언어의 특성상 사용자 친화적 DSL을 만들기가 힘들다. Java8의 람다 표현식은 이 문제를 해결할 강력한 도구이다.
JVM에서 이용할 수 있는 다른 DSL 해결책
DSL의 카테고리를 구분하는 가장 흔한 방법은 내부 DSL과 외부 DSL을 나누는 것이다.
내부 DSL
- 기존 자바 언어를 이용해 외부 DSL에 비해 새로운 패턴과 기술을 배워 DSL을 구현하는 노력이 현저히 줄어든다.
- 순수 자바로 DSL을 구현하면 나머지 코드와 함께 DSL을 컴파일할 수 있다. 따라서 다른 언어의 컴파일러를 이용하거나 외부 DSL을 만드는 도구를 사용할 필요가 없으므로 추가 비용이 발생하지 않는다.
- 개발 팀이 새로운 언어를 배우거나 또는 익숙하지 않고 복잡한 외부 도구를 배울 필요가 없다.
- DSL 사용자는 기존의 자바 IDE를 이용해 자동 완성, 리팩터링과 같은 기능을 사용할 수 있다.
- 한 개의 언어로 하나 또는 여러 도메인을 대응하지 못해 추가 DSL을 개발해야 하는 상황에서 자바를 이용하여 추가 DSL을 쉽게 합칠 수 있다.
외부 DSL
- 외부 DSL은 쉽게 제어 범위를 벗어날 수 있으며 처음 설계한 목적을 벗어날 수 있다는 문제점이 있다.
- 자신만의 문법과 구문으로 새 언어를 설계하고 DSL을 실행할 코드를 만들어야 한다.
- 이런 문제점들이 있지만 사용하는 큰 이유는 외부 DSL이 제공하는 무한한 유연성 때문이다.
최신 자바 API의 작은 DSL
Collections.sort(persons, new Comparator<Person>() {
public int compare() ...
})
- Java8 이전에는 위와 같이 익명 클래스를 활용하여 구현해야 했다.
- 내부 클래스를 간단한 람다 표현식으로 바꿀수 있다.
Collections.sort(persons, (p1, p2) -> p1.getAge() - p2.getAge())
- 위와 같은 구현은 코드를 간결하게 만들었지만 정적 유틸리티 메서드를 활용하여 좀 더 가독성 있게 개선할 수 있다.
Collections.sort(persons, comparing(p -> p.getAge()))
- 람다를 메서드 참조로 변경하여 코드를 개선할 수 있다.
// 나이 정렬 후 이름 정렬
Collections.sort(persons, comparing(Person::getAge)
.thenComparing(Person::getName))
이 예시에서도 DSL이 코드의 가독성, 재사용성, 결합성을 높일수 있는지 보여준다.
스트림 API는 컬렉션을 조작하는 DSL
Stream 인터페이스를 이용하여 코드를 쉽게 구현할 수 있다.
List<String> errors = Files.lines(Paths.get(fileName))
.filter(line -> line.startWith("ERROR"))
.limit(40)
.collect(toList());
'자바 > 모던 자바 인 액션' 카테고리의 다른 글
[모던 자바 인 액션] 12장 새로운 날짜와 시간 API (0) | 2023.02.07 |
---|---|
[모던 자바 인 액션] 11장. null 대신 Optional 클래스 (0) | 2023.01.07 |
[모던 자바 인 액션] 9장. 리팩터링, 테스팅, 디버깅 (0) | 2022.11.18 |
[모던 자바 인 액션] 8장. 컬렉션 API 개선 (0) | 2022.11.10 |
[모던 자바 인 액션] 7장. 병렬 데이터 처리와 성능 (0) | 2022.10.24 |