1. 개요
Domain-specific language주어진 영역(domain) 안에서만 성립하는 형식 언어의 일종.
주로 컴퓨터 공학 분야에서 주어진 문제를 쉽게 해결하기 위해 필요한 요소만 정의한 아주 작은 언어를 말한다. 반대 용어는 범용 언어(General-purpose language, GPL).
2. 상세
정의만 보면 모호하지만, 도메인 엔지니어링(domain engineering)의 관점에서 보면 조금 더 명확해진다. 다시 말해, '이걸로 뭘 할 수 있지'가 아니라 먼저 특수한 문제를 정의하고 그 문제를 해결하는 도구로써 언어를 설계하는 방식이다.국가, 지역별로 수집된 주택과 관련한 다양한 통계 데이터에서 연령대별로 소유한 주택 가격을 조사해보자. 일반적인 GPL로는 다음과 같이 할 수 있을 것이다.
#!syntax cpp
정의 data = 불러오기(데이터);
정의 map;
data의 row마다 반복하기:
정의 mapi = map[row.연령대];
만약 mapi가 비어있다면:
mapi = 0;
종료
mapi = (mapi + row.주택가격) / 2;
map[row.연령대] = mapi;
...
GPL을 사용했기에 코드를 짜는 것에는 성공했지만, 간단한 통계 데이터를 만드는 일에도 굉장히 복잡하고 번거로운 코드가 필요하다. 만약 이러한 분석을 한 번 하는 것이 아니라 새로운 통계 데이터를 분석하고 실험할 때도 즉흥적으로 작성해야 한다면? 다음과 같이 새로운 언어를 만들어보자.[* 눈치가 좋다면 알겠지만, 실존하는 쿼리 언어인 SQL을 조금 한글화한 것일 뿐이다. SQL로 쓰면 다음과 같다.
#!syntax sql
select 연령대, avg(주택가격) from 데이터 group by 연령대;
통계 분석을 밥먹듯이 하는 실무에서는 SQL로도 부족해서 MATLAB 등의 DSL을 사용한다.]#!syntax sql
(데이터)에서 -> (연령대)별로 (주택가격)을 (AVG)수행
이 새로운 언어는 '데이터'를 바꾸거나 '연령대'가 아닌 다른 지표를 기반으로 그룹핑도 가능하고, 'AVG' 말고 다른 함수들도 이용할 수 있다. 무엇보다 훨씬 쉽고, 간단해졌다.
또 다른 예시로 주어진 문자열이 전화번호 형태인지 알아보는 코드를 작성해 보자.
#!syntax cpp
정의 s = 입력("문자열");
만약 길이(s) == 0:
반환 false;
종료
만약 s[0] = "+":
정의 i = 1:
반복(s[i]가 "공백")일 때까지:
만약 아님(s[i]가 "숫자"):
반환 false;
종료
i = i + 1;
종료
종료
만약 ...
역시 단순한 문제(문자열 패턴 검증)에 비해 해결책으로 쓰인 코드가 너무 복잡하다. 만약 전화번호 뿐만 아니라 주소, 사람 이름, 비밀번호, 단위 표시 등등 다른 문자열 검증 문제를 해결할 때도 이렇게 길고 복잡한 코드를 작성해야 한다면? 정규표현식이라는 DSL을 이용해 위 문제를 풀어 보자.
#!syntax javascript
/(?:\+?\d{1,3}[- ]?)?\d{2,3}[- ]?\d{3,4}[- ]?\d{4}/
마찬가지로 코드가 정말 쉽고 단순해졌다. 또한 다른 문자열 패턴과 관련된 처리나 간단한 스크립팅에도 적용이 가능하다.[1] 단, 앞선 쿼리 언어와 마찬가지로 게임을 만들거나 날씨를 예측하는 등 전혀 다른 문제를 푸는 것은 불가능하다. 이는 DSL의 핵심적인 특징으로, DSL은 특정 도메인 내의 문제만 풀기 위해 설계되며, 해당 도메인 밖의 문제를 푸는 것은(그것이 기술적으로 가능한가와는 별개로[2]) 고려하지 않는다.
2.1. 유사 개념과의 비교
워낙 정의가 모호하고 예시에 대부분의 언어를 집어넣을 수 있기에, DSL이 정확히 무엇인지에 대한 오해도 뒤따르게 된다. 비슷한 예시로 범용 프로그래밍 언어(GPL)와 스크립트 언어[3], 마크업 언어, 쿼리 언어의 구분이 있다.- DSL은 사람이 읽도록 만들어졌기에, 컴퓨터는 읽을 수 없다
범용 자연어 해석기(general natural language interpreter)인 사람은 무슨 언어든지 읽을 수 있다. 그냥 그게 쉽냐 어렵냐의 차이일 뿐이다. 엄밀하게 따지면 모든 형식 언어는 자연어의 부분집합이며, 컴퓨터가 주어진 언어를 이해하기 위해서는 생성 규칙을 유한 개 이내로 줄일 필요가 있다. 또다른 직관적인 반례로 사람은 프로그래밍 언어를 읽을 수 있다. DSL과 GPL의 차이는 해당 언어를 프로그래머가 아닌 사람이 얼마나 익히기 쉽냐의 차이일 뿐이다. 예를 들어 자막 편집을 하는데 GPL 언어의 함수 문법을 배울 필요는 없듯이 말이다. 기계가 읽을 수 없는 자연어로는 의사 코드가 대표적인데, 이는 기계를 염두에 두지 않고 사람끼리 의사소통을 하기 위해 만들어졌기 때문이다. - DSL은 프로그래밍 언어이다/아니다
모든 DSL이 프로그래밍 언어인 것은 아니지만, DSL 중 프로그래밍 언어인 것도 있다. 즉, DSL과 프로그래밍 언어는 딱히 부분집합 관계는 아닌 것. 일례로 포스트스크립트는 튜링 완전한 프로그래밍 언어로 쓸 수 있고, Nix는 아예 순수 함수형 프로그래밍 언어다. 반면에 TeX 등의 언어로 프로그래밍을 할 수 있을 리 만무하다. - DSL은 마크업 언어의 일종이다
정의대로 따지면 마크업 언어가 DSL의 부분집합이다. 이는 두 언어의 정의 자체가 매우 모호하기 때문에 발생하는 일로, 누구도 JSON을 마크업 언어라고 하진 않지만 JSON과 구조적으로 크게 다르지 않은 XML, XML에서 파생된 HTML 등은 흔히 마크업 언어라고 불린다. 워낙 정의가 모호하고 descriptive하기 때문에 문맥에 따라서 마크업 언어나 DSL 등으로 부르는 것이 좋다.
3. 종류
도메인 특화 언어는 언어가 '무엇을 (풀기) 위해' 설계되었나에 따라 정의될 뿐, 어떤 형태인지, 어떻게 실행되는지와는 무관하다. 따라서 구체적인 구현과 종류에 따라 다양한 하위 분류가 나뉘는데, 예를 들면 도메인 특화 마크업 언어(domain-specific markup languages), 도메인 특화 프로그래밍 언어(domain-specific programming languages) 하는 식.4. 목록
5. 기타
6. 관련 문서
[1] 실제로 위에서 사용한 Perl 표준 정규표현식(PCRE)과 Perl 언어는 awk같이 문자열 편집이나 파일 처리 등등을 하기 위해 만들어진 간단한 DSL로 시작했다![2] 후술할 예시에도 튜링 완전한 DSL들이 다양하게 존재한다. 일례로 웹 브라우저 화면에 보여질 GUI를 기술하는 게 목적인 HTML조차 튜링 완전하다. GPL에 비해 이 완전성이 별 의미를 갖지 못할 뿐.[3] The boundaries between these concepts are quite blurry, much like the boundary between scripting languages and general-purpose languages.