//321p
이해하기 쉬운 코드는 특히 중요하다.
개발팀과 도메인 전문가가 공유하고 이해할 수 있는 코드는 생산성과 직결되기 때문이다.
도메인 전문가는 소프트웨어 개발 프로세스에 침여할 수 있고
비즈니스 관점에서 소프트웨어가 제대로 되었는지 확인할 수 있다.
for (Dish d : menu) {
if (d.getCalorie() < 400) {
System.out.println(d.getName());
}
}
위 코드는 개발자가 아닌 도메인 전문가가 보았을 때 이해하기 껄끄러운 부분이 있을 수 있습니다.
for, if 같은 제어문들이 껄끄러운 부분(잡음)에 해당할 수 있습니다.
menu.stream()
.filter(d -> d.getCalories < 400)
.map(Dish::getName)
.forEach(System.out::println);
위와 같이 람다/스트림을 이용하면 보다 이해하기 쉬운 코드로 바뀔 수 있습니다.
하지만, 도메인과 비즈니스 환경에 따라 위 코드에서도 여전히 잡음이 있다고 판단될 수 있습니다.
- stream(), sysout람다식 등의 여전한 잡음
- filter, forEach, map이 도메인 영역의 키워드가 아닌 경우
- 기타 등등..
이를 해결하기 위해 DSL(도메인 전용 언어)를 활용합니다.
높은 수준의 추상화와, 도메인 영역 키워드를 사용함으로써
저수준의 세부내용을 숨길 수 있고, 특정 도메인의 동작을 표현할 수 있게 하는
사용자 친화적인 DSL을 만들 수 있습니다.
DSL 은 크게
- 내부 DSL : 호스팅 언어(애플리케이션을 개발할 언어)로 DSL개발
- 개발 노력이 적게 듦 / 호스팅 언어의 문법적 제약 받음
- 외부 DSL : 직접 언어를 설계하여 DSL개발
- 높은 유연성 제공 / 구현하기가 어려움
- 다중 DSL : 호스팅 언어의 컴파일 환경에서 이용할 수 있는 다른 언어로 DSL개발
- 호스팅 언어보다 유연한 경우 간결함 / 통합 시 복잡함과 호환성 문제
로 나눌 수 있습니다.
내부 DSL 개발에 대하여 조금 더 알아보자면
// before
menu.stream()
.filter(d -> d.getCalories < 400)
.map(Dish::getName)
.forEach(System.out::println);
// after
menu.show(
caloriesSmallerThan(400),
only(NAME)
);
// after - 2
menu.caloriesSmallerThan(400)
.only(NAME)
.show();
결과적으로, 기존(before)의 코드를 도메인 영역에 가깝게(after) 구현하는 것입니다.
이를 위해서는
- 메서드 체이닝
- 더미 메서드
- 빌더 패턴
- 람다식
등을 활용하여
위(after)와 같은 유창한 코드를 위해서 추가적인 클래스 및 메서드를 노출(별도제작)하여야 합니다.