ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 도메인 특화 언어와 단위 테스트 - 5부
    [옛날 글들] 설계 이야기 2024. 5. 31. 10:29
    728x90

    이전 글 : 도메인 특화 언어와 단위 테스트 - 4부

    소프트웨어의 본질적인 복잡성

    프레더릭 브룩스는 그의 기념비적인 논문 “은총알은 없다(No Silver Bullet)”에서 소프트웨어 개발과 관련된 작업을 본질적인 작업(essential task)과 부차적인 작업(accidental task)으로 구분하고 있다. 브룩스에 따르면 본질적인 작업이란 도메인 내의 추상적인 개념들을 명세하고 설계하고 구현 가능한 상태로 정교하게 다듬는 정신적인 작업을 의미한다. 이에 반해 부차적인 작업이란 고안된 추상화를 공간과 시간 제약 속에서 프로그래밍 언어로 변환하는 작업을 말한다.

    프레더릭 브룩스는 불행히도 소프트웨어 개발과 관련된 전체 작업 가운데 부차적인 작업이 차지하는 비율이 90%를 넘지 않는 한 부차적인 작업에 쏟는 노력을 완전히 제거한다고 해서 소프트웨어 공학의 현실이 크게 개선될 것 같지 않다는 비관적인 전망을 내놓았다. 소프트웨어와 관련된 본질적인 어려움은 도메인에 내재된 개념과 추상화를 다루는 정신적인 작업과 관련된 것이지 프로그래밍 언어나 기술적인 문제가 아니다. 따라서 10년 내에 생산성을 10배 이상 혁신시킬 수 있는 은총알이란 존재하지 않으며 도전 대상은 부차적인 작업이 아니라 본질적인 작업과 관련된 것이어야 한다고 주장한다.

    소프트웨어 개발의 본질적인 문제 중 하나는 복잡성(complexity)이다. 소프트웨어는 인간이 창조한 다른 물리적인 기계와 다르게 자연과 유사한 프랙탈적인 복잡성을 가진다. 이미 존재하는 공통 부품들을 조합해서 다양한 요소를 만들 수 있는 물리적인 기계와 달리 소프트웨어는 부품 간의 공통점보다는 차이점이 더 크기 때문에 소프트웨어의 확장은 곧 소프트웨어를 구성하는 부품 수의 급격한 증가를 초래한다. 또한 부품의 수가 증가하면 증가할 수록 부품 간의 상호작용 그래프 역시 급격하게 복잡해지기 시작한다. 따라서 소프트웨어 전체의 복잡성은 요소의 수에 선형적으로 비례하기보다는 훨씬 가파르게 증가한다.

    소프트웨어의 복잡성은 소프트웨어가 가진 본질적인 어려움이므로 제거가 불가능하다. 그러나 우리가 가진 인지능력의 한계 내에서 복잡성을 좀 더 다루기 쉬운 형태로 재단하는 것은 가능하다. 소프트웨어를 구성하는 요소들을 계층적인 형태(hierarchy)로 배열하고 각 계층에서 다루어야 하는 복잡성을 상대적으로 좁은 범위로 제한함으로써 한 순간에 다루어야 하는 복잡성의 수준을 낮출 수 있다. 그리고 이것이 우리가 고수준 프로그래밍 언어를 사용하거나 다양한 라이브러리와 프레임워크를 사용하는 이유다(복잡도를 해결하기 위한 또 다른 방법은 점증적으로 소프트웨어를 개발함으로써 한 번에 다루어야 하는 기능의 수를 제한하는 것이다).

    프로그래밍 언어의 역사는 프로시저 추상화와 데이터 추상화와 같은 소프트웨어의 비본질적인 복잡도를 낮추기 위한 다양한 시도의 연속이다. 라이브러리와 프레임워크의 역사는 재사용 가능한 부품과 설계를 제공함으로써 개발자들이 본질적인 복잡도에 집중할 수 있도록 하기 위한 시도의 연속이다. 그러나 언어, 라이브러리, 프레임워크와 같은 기술적인 발전에도 불구하고(한 편으로는 기술적인 발전 때문에) 소프트웨어 개발자들이 감내해야 하는 소프트웨어의 본질적인 복잡도는 점점 더 증가하고 있다.

    도메인 특화 언어(Domain-Specific Language)최근 들어 소프트웨어의 본질적인 복잡도를 해결할 수 있을 것으로 기대되는 한 가지 설계 방식이 개발자들의 주목을 끌고 있다. 사실 이 방식은 UNIX의 전통과 함께 오랜 시간 동안 소프트웨어 개발자들의 도구 상자 안에 존재해 왔던 것이다. UNIX 커뮤니티에는 특정한 응용 영역의 문제를 해결하기 위해 그 영역에만 적용할 수 있는 특수한 언어를 만들어 문제를 해결하는 오랜 전통이 존재한다. 이런 언어를 UNIX 커뮤니티에서는 “작은 언어(little language)”, 또는 “미니 언어(mini language)”라고 부른다.

    UNIX에는 미니언어(mini language)를 특수한 응용 영역에서 사용하는 전통이 있다. 미니언어의 도움을 받으면 프로그램의 라인 수를 현저하게 줄일 수 있다. UNIX 역사에서는 이와 같이 특수한 영역에 사용하는 언어들을 작은 언어(little language), 또는 미니언어(mini language)라 불렀다. 이렇게 이름 붙인 까닭은 범용 언어에 비해 크기가 작고 복잡도 또한 낮았기 때문이다. 

    Eric Raymond, Art of UNIX Programming

     

    UNIX의 미니 언어 전통 안에서 개발자는 도메인에서 사용되는 어휘, 문법, 의미론을 사용함으로써 도메인에 특화된 새로운 언어를 창조하고 이 언어를 이용해 프로그램을 작성한다. 이런 방식으로 작성된 애플리케이션은 프로그래밍 언어의 계층 위에 특정 도메인을 위한 특수 목적 언어 계층이 위치하는 계층형 아키텍처(Layered Architecture)의 특수한 형태를 띠게 된다. 즉, 하나의 프로그램 안에 다수의 언어 계층이 존재하게 된다.

    프로그래밍 언어로 작성된 추상화 계층 위에 도메인 언어로 작성된 추상화를 쌓아 올리는 것은 복잡성을 극복하기 위해 소프트웨어를 계층적인 형태(hierarchy)로 분할하는 전통적인 설계 방식을 확장한 것이다. UNIX의 미니 언어를 이용하면 도메인을 구성하는 추상 개념을 통해 사고하고 프로그래밍할 수 있다. 따라서 개발자는 부차적인 복잡성의 무게에 짓눌리지 않고도 본질적인 복잡성의 해결에 집중할 수 있다. 개발자가 도메인의 용어로 프로그램을 개발하면 컴파일러나 도구가 도메인의 용어를 컴퓨터가 이해할 수 있는 명령어로 변환한다. 즉, 명세가 실행 가능한 코드가 되는 것이다.

    언어의 적용 범위를 특정한 도메인으로 한정시킴으로써 작고 간결한 언어를 얻을 수 있다. 더 단순하고 추상적인 언어를 사용함으로써 구현 세부사항들에 짓눌리지 않고 도메인의 문제를 해결하는 작업에 집중할 수 있다.

    여기에서는 전통적인 ‘미니언어’라는 용어로써 간결함과 작음을 지향하는 설계의 지혜를 강조하도록 하겠다. 특수한 영역을 위한 미니언어는 대체로 매우 강력한 설계 아이디어다. 보다 높은 수준의 언어로 문제를 해결하는 적절한 방법, 규칙, 그리고 알고리즘을 정의할 수 있기 때문에 전체적인 복잡도를 낮게 유지하면서도 낮은 수준에서 손으로 코딩한 것과 대등한 결과를 얻을 수 있다. 

    Eric Raymond, Art of UNIX Programming

     

    지금까지 살펴본 UNIX의 미니 언어와 같이 “특정한 도메인에 초점을 맞춘 제한적인 표현력을 가진 컴퓨터 프로그래밍 언어”를 도메인 특화 언어(Domain-Specific Language), 또는 간단히 DSL이라고 부른다. “도메인 특화 언어”라는 용어를 구성하고 있는 각 단어를 분석함으로써 DSL의 특성을 이해할 수 있다.

    • 도메인(Domain) - 도메인이란 “지식이나 영향력, 또는 활동의 영역”을 의미한다. DSL은 특정한 도메인 내에서 사용될 것을 가정하는 언어다. 특정 도메인에 초점을 맞춤으로써 애플리케이션을 자연스럽게 성장시킬 수 있는 “문맥(context)”을 제공할 수 있다.
    • 특화(Specific) - DSL에서 "특화"라는 단어는 “제한된 문맥(bounded context)”과 “표현력의 제약(limited expressiveness)”을 강조한다. “제한된 문맥”이란 언어가 적용될 수 있는 영역의 범위가 제한적이라는 것이다. DSL은 제한된 영역에 대해 사고하고 이해하고 표현하기 위한 언어다. 제한된 언어는 오직 언어가 작은 도메인에 대해 명확한 초점을 가질 때만 유용하다. “표현력의 제약”은 도메인을 서술하는데 사용할 수 있는 구성 요소를 제한한다는 것을 의미한다. DSL은 모든 분야에 적용 가능한 범용 프로그래밍 언어를 목표로 하지 않는다. 범용 프로그래밍 언어는 다양한 데이터 타입, 제어 로직, 추상적인 구조를 제공한다. 다양한 언어 요소는 언어를 다양한 환경에서 사용할 수 있도록 한다는 점에서는 유용하지만 반대로 언어를 배우고 사용하기 어렵게 만든다. DSL은 배우기 쉽고 사용하기 편해야 한다. 따라서 제어나 분기와 같은 요소는 가급적 배제하고 도메인에 적합한 최소한의 기본 요소만을 포함한다.
    • 언어(Language) - DSL의 언어적인 특성은 “프로그래밍 언어”와 “유창함(fluency)”이라는 두 가지 측면을 포괄한다. 먼저 DSL은 프로그래밍 언어다. 따라서 컴퓨터가 수행할 수 있는 명령을 지시하기 위해 사람들이 사용할 수 있어야 한다. 그러나 DSL은 일반적인 프로그램 언어보다 특정 문맥(context)에서의 유창함(fluency)을 더욱 더 강조한다. 즉, 개별적인 표현이 아닌 표현들이 함께 조합되는 방식으로부터 나타나는 유창함이 DSL의 설계를 이끄는 원동력이 된다. 그러나 유창함이 자연어와의 유사함을 의미하는 것이 아니라는 점에 주의해야 한다. DSL은 단지 프로그래밍 언어일 뿐이다. 프로그래밍 언어가 태생적으로 안고 있는 표현력의 제약 속에 유창한 흐름이 존재할 때 DSL의 강력함이 드러난다.

    DSL이 가져야 하는 기본적인 3가지 특징은 단순함(simplicity), 간결함(conciseness), 유창함(fluency)이다.

    • 단순함(Simplicity) – DSL을 사용하는 이유가 도메인과 관련된 복잡성을 낮추는 것이므로 DSL은 반드시 단순해야 한다. 도메인에 익숙한 개발자나 클라이언트는 DSL로 작성된 스크립트를 보고 그 의미를 쉽게 파악할 수 있어야 한다. 도메인에서 사용되는 어휘를 사용하고 언어를 익히기 위해 필요한 문법을 제한함으로써 이해하기 쉬운 단순한 언어를 창조할 수 있다. DSL은 튜링 완전(turing completeness)해서는 안 된다.
    • 간결함(Conciseness) – DSL은 간단하면서도 표현력이 있는 문법을 선택해야 한다. 문제와 관련되지 않은 군더더기 없는 표현을 최대한 제거함으로써 코드를 간결하게 만들 수 있다. 두 개의 행렬을 곱하는 문제가 있을 때 matrixA * matrixB와 matrixA.multiply(matrixB) 둘 중 어떤 것이 더 간결해 보이는가?
    • 유창함(Fluency) - 언어의 유창함이란 “얼마나 빠르고 쉽게 사용자들이 정보를 처리할 수 있는가”로 정의할 수 있다. DSL의 유창함을 지원하는 두 가지 요소는 “전문 용어(jargon)”와 “문맥(context)”이다. 경험이 많은 프로그래머들은 특별한 설명이 없이도 “STRATEGY 패턴”이라는 전문 용어에 함축되어 있는 수많은 의미를 빠르게 이해한다. 대화 중간에 “배”라는 단어가 나올 때 사람들은 배가 무엇을 의미하는 지를 어떻게 알 수 있을까? 사람들은 어떤 항구에 정박해 있는 배에 관해 이야기하고 있었을지도 모른다. 아니면 출근 길에 사온 과일에 관해 이야기하고 있었을 것이다. 그것도 아니면 배탈이 났던 경험에 관해 이야기하고 있었을 수도 있다. 대화의 문맥이 존재한다면 별다른 설명이 없이도 “배”라는 단어가 무엇을 의미하는 지를 빠르고 쉽게 이해할 수 있다.

    도메인 특화 언어의 구조

    프로그램의 구성 요소를 설계할 때 고려해야 하는 기본적인 인터페이스 설계 원칙 중 하나는 커맨드(Command)와 쿼리(Query)를 분리하는 것이다. “커맨드-쿼리 분리(Command-Query Separation, CQS)” 원칙의 기본 개념은 메서드는 반드시 부수 효과를 발생시키는 커맨드이거나 부수 효과를 발생시키지 않는 쿼리 둘 중 하나여야하고 두 가지 특성 모두를 가져서는 안 된다는 것이다. 즉, 커맨드 메서드는 상태를 변경하는 대신 값을 반환해서는 안되며 쿼리 메서드는 값을 반환화는 대신 상태를 변경해서는 안 된다.

    부수 효과를 발생시키지 않는 것만을 함수로 제한함으로써 소프트웨어에서 말하는 “함수”의 개념이 일반 수학에서의 개념과 상충되지 않도록 한다. 우리는 오브젝트를 변경하지만 직접적으로 값을 반환하지 않는 커맨드(Command)와 오브젝트에 대한 정보를 반환하지만 변경하지는 않는 쿼리(Query) 간의 명확한 구분을 유지할 것이다.

    Betrand Meyer, Object-Oriented Software Construction 2nd Edition

     

    커맨드-쿼리 분리 원칙은 객체들을 독립적인 기계로 보는 객체지향의 오랜 전통에 기인한다. 이 관점에서 객체는 블랙박스이며 객체의 인터페이스는 객체의 관찰 가능한 상태를 보기 위한 일련의 디스플레이와 객체의 상태를 변경하기 위해 누를 수 있는 버튼의 집합이다. 이런 스타일의 인터페이스를 사용함으로써 객체의 캡슐화와 다양한 문맥에서의 재사용을 보장할 수 있다. Martin Fowler는 커맨드-쿼리 분리 원칙에 따라 작성된 객체의 인터페이스를 “커맨드-쿼리 인터페이스(Command-Query Interface)”라고 부른다.

    <그림 1>은 기계 메타포 관점에서 바라보는 객체의 인터페이스를 개념적으로 표현한 것이다. 디스플레이를 위한 타원을 누르면 기계의 현재 상태를 출력하지만 상태는 변경하지 않는다. 반면에 박스 버튼을 누르면 기계의 상태를 변경하지만 변경된 상태에 관한 어떤 정보도 외부로 노출하지 않는다. 즉, 타원은 쿼리 메서드이고 박스는 커맨드 메서드다.

    <그림 1> 기계로서의 객체 메타포


    커맨드-쿼리 인터페이스를 구성하는 각 오퍼레이션들은 독립적인 상황에서 사용될 수 있도록 이름 지어진다. <그림 1>에서 insert() 오퍼레이션은 empty() 오퍼레이션이나 delete() 오퍼레이션에 독립적으로 호출 가능하다. 이와 같이 인터페이스를 구성하는 오퍼레이션 간에 의존성이 적으면 적을수록 다양한 문맥에서 사용 가능하고 자유롭게 조합될 수 있는 객체를 만들 수 있다. 따라서 커맨드-쿼리 인터페이스는 사용 문맥과의 결합도를 최소화하도록 설계된다.

    이와 대조적으로 DSL의 인터페이스는 사용되는 문맥에 기반한 유창함을 강조한다. 인터페이스를 구성하는 각 오퍼레이션은 사용되는 문맥에 강하게 결합되며 함께 사용되는 오퍼레이션들과 밀접하게 연관된다. 즉, 인터페이스를 구성하는 오퍼레이션들은 문법이나 의미론적으로 서로 강한 언어적인 연관성을 가지도록 설계된다. Martin Fowler와 Eric Evans는 DSL에 사용되는 인터페이스 형식을 전통적인 커맨드-쿼리 인터페이스 형식과 구분하기 위해 “유창한 인터페이스(Fluent Interface)”라고 부른다.

    커맨드-쿼리 인터페이스와 유창한 인터페이스를 함께 놓고 보았을 때 가장 두드러지는 차이점은 오퍼레이션의 이름을 짓는 방식에 있다. 커맨드-쿼리 인터페이스는 문맥과 무관하게 독립적으로 사용될 것을 가정하기 때문에 설계자는 오퍼레이션의 이름 안에 최대한 많은 정보를 담으려고 노력한다. 이에 반해 유창한 인터페이스는 특정한 사용 문맥을 가정하기 때문에 독립적으로는 의미가 없고 연결되는 문맥 상에서 충분한 의미를 가질 수 있는 간결한 이름을 사용하려고 노력한다.

    커맨드-쿼리 인터페이스는 훌륭한 객체 인터페이스를 낳는다. 유창한 인터페이스는 훌륭한 DSL 인터페이스를 낳는다. 문제는 하나의 객체에 두 가지 방식의 인터페이스를 조합할 경우 이해하기 어려워 진다는 것이다. 따라서 DSL 설계와 관련해서 주의해야 할 기본 원칙은 커맨드-쿼리 인터페이스와 유창한 인터페이스를 서로 섞지 않는 것이다.

    DSL을 구조화하는 일반적인 방식은 커맨드-쿼리 인터페이스를 제공하는 객체 모델 위에 유창한 인터페이스 방식의 독립적인 DSL 레이어를 구축하는 것이다. 이처럼 커맨드-쿼리 인터페이스를 제공하는 하부 모델 위에서 유창한 인터페이스를 제공하는 독립적인 언어 계층을 표현식 빌더(EXPRESSION BUILDER)라고 부른다.

    이런 관점에서 DSL은 커맨드-쿼리 인터페이스 기반의 객체 모델을 제어할 수 있는 유창한 인터페이스를 제공하는 일종의 FAÇADE로 볼 수 있다. 하부의 객체 모델은 DSL에 대한 의미를 제공하고 DSL은 하부 모델을 표현하기 위한 또 다른 언어를 제공한다. Martin Fowler는 DSL에 의미론을 제공하는 커맨드-쿼리 인터페이스 기반의 객체 모델을 의미 모델(SEMANTIC MODEL)이라고 부른다. 패러다임이 객체지향일 경우 일반적으로 의미 모델은 DOMAIN MODEL 패턴의 형태를 따른다.

     

     

     

    <그림 2> 의미 모델을 생성하는 표현식 빌더로서의 DSL

     

    DSL의 일반적인 구조는 커맨드-쿼리 인터페이스를 제공하는 의미 모델(SEMANTIC MODEL) 위에 유창한 인터페이스를 제공하는 표현식 빌더(EXPRESSION BUILDER)를 구축하는 것이다. 표현식 빌더(EXPRESSION BUILDER)는 말 그대로 하부의 의미 모델(SEMANTIC MODEL)을 구축하기 위해 유창한 표현력을 제공하는 빌더다.

    도메인 특화 언어의 구분

    DSL을 구축하는 방법은 다음과 같은 3가지 범주로 구분할 수 있다.

    • 외부 DSL(external DSL) – 애플리케이션 작성에 사용되는 주 언어(호스트 언어라고 부른다)가 아닌 별도의 독립적인 언어를 이용해서 DSL을 작성한다. 일반적으로 외부 DSL은 자체적인 문법을 가지지만 XML과 같은 기존 언어의 문법을 차용하기도 한다. 외부 DSL로 작성된 스크립트는 텍스트 파싱이나 코드 생성 기법을 사용해서 호스트 언어로 작성된 의미 모델로 파싱된다. 외부 DLS의 예로는 정규 표현식, SQL, Awk, Spring이나 Hibernate에서 사용되는 XML 설정 파일을 들 수 있다. 앞에서 살펴본 UNIX의 미니 언어 전통의 대부분은 외부 DSL의 범주에 속한다.
    • 내부 DSL(internal DSL) – 외부 DSL과 달리 독립적인 언어가 아닌 범용 프로그래밍 언어를 사용하되 특수한 목적을 위해 제한된 방법으로 사용하는 방식을 의미한다. 내부 DSL로 작성된 스크립트는 범용 언어의 맥락에서 유효한 코드지만 범용 언어의 일부 기능만을 사용하도록 그 범위가 제한된다. 따라서 내부 DSL로 작성된 스크립트는 호스트 언어의 문법적인 특성을 지니면서도 제한된 표현력과 특유의 유창함으로 인해 독자적으로 생성된 언어라는 느낌을 준다. 내부 DSL의 전통은 Lisp 언어에 그 뿌리를 두고 있으며 최근 들어서는 Ruby 커뮤니티에서 전통을 이어가고 있다. Ruby 언어는 내부 DSL로 사용하기에 용이한 유연한 메타 프로그래밍 메커니즘을 제공한다.
    • 언어 워크벤치(language workbench) – 언어 워크벤치는 DSL을 정의하고 개발하기 위한 용도로 개발된 IDE다. 언어 워크벤치는 외부 DSL이나 내부 DSL에 비해 상대적으로 역사가 짧고 최근에 들어서 주목을 받기 시작한 새로운 영역이다.

    본 글에서는 테스트 케이스 작성이라는 도메인과 관련된 다양한 문제를 해결하기 위해 내부 DSL 의 기법을 적용하는 방법에 초점을 맞춘다.

    문맥(Context)의 중요성

    인간의 의사소통은 참여자들이 공유하는 “문맥(context)”을 기반으로 이루어진다. 회의에 늦게 참석한 사람이 아젠다를 알고 있음에도 도착 즉시 대화에 참여할 수 없는 이유는 참석자들 간에 오간 대화의 맥락을 알 지 못하기 때문이다. 10년 만에 만난 친구와 큰 어려움 없이 대화가 가능한 이유는 과거의 추억을 공유하고 있기 때문이다. 문맥을 공유할 경우 적은 수의 단어만으로도 풍부한 의미를 전달할 수 있다. 직장 상사를 가리키며 얼굴을 찌푸리는 동료를 보았을 때 그 동료가 하고 싶은 말이 무엇인지 알 수 있는 이유는 직장 상사에 대해 유사한 기억과 감정을 공유하고 있기 때문이다. 마음에 드는 이성을 만났을 때 사람들은 본능적으로 함께 공유할 수 있는 주제를 찾으려고 노력한다. 일단 문맥을 공유하고 나면 문맥을 바탕으로 대화의 속도를 높일 수 있다. 문맥은 대화를 자연스럽게 연결시켜주는 접착제와 같은 역할을 한다.

    문맥은 사람들이 사고하는 방식에도 영향을 미친다. 사람들은 동일한 단어를 듣더라도 대화의 문맥에 따라 마음 속에 서로 다른 이미지를 떠올릴 수 있다. 문맥은 사고의 폭을 제한함으로써 대화의 의미를 선명하게 채색한다.

    DSL의 유창함은 신호 대비 잡음 비율을 감소시키는 것으로부터 나온다. 제한된 표현력의 한계 안에서 최대한 풍부한 의미를 전달하기 위해서는 구성 요소들을 문맥에 의존하도록 만드는 것이 중요하다. 이것이 앞에서 설명한 커맨드-쿼리 인터페이스(Command-Query Interface)와 유창한 인터페이스(Fluent Interface) 사이의 중요한 차이점이다. 커맨드-쿼리 인터페이스는 각 오퍼레이션 호출을 최대한 독립적으로 만들기 위해 노력한다. 이에 비해 유창한 인터페이스는 암묵적인 문맥을 기반으로 오퍼레이션들이 조합될 수 있도록 설계한다.

    DSL의 일반적인 용도는 의미 모델(SEMANTIC MODEL)로 표현된 복잡한 객체들의 집합을 생성하는 것이다. 복잡한 객체들을 하나의 오퍼레이션으로 생성할 수는 없기 때문에 DSL에서는 다양한 오퍼레이션 호출의 흐름을 따라 점진적으로 생성에 필요한 객체의 상태를 수집한 후 최종적으로 수집된 상태 정보를 이용해 객체 집합을 생성한다. 따라서 DSL에서는 생성 중인 의미 모델의 중간 상태를 저장하기 위한 변수를 필요로 한다. 이처럼 내부 DSL에서 의미 모델의 중간 상태를 저장하기 위해 내부적으로 관리하는 변수를 컨텍스트 변수(CONTEXT VARIABLE)라고 부른다.

    컨텍스트 변수(CONTEXT VARIABLE)의 역할은 대화에서 문맥이 제공하는 역할과 동일하다. 즉, 내부 DSL의 오퍼레이션 호출 간에 공유될 수 있는 문맥을 제공함으로써 호출들을 연결하는 접착제 역할을 한다.

    DSL은 오퍼레이션의 실행 결과를  컨텍스트 변수(CONTEXT VARIABLE)에 누적시킨다. 이후에 실행되는 다양한 오퍼레이션들은  컨텍스트 변수(CONTEXT VARIABLE)에 누적된 정보를 입력으로 사용한다.  컨텍스트 변수(CONTEXT VARIABLE)를 이용함으로써 오퍼레이션 실행 간에 명시적으로 전달해야 하는 정보를 암시적으로 만듦으로써 신호 대비 잡음 비율을 줄인다. 따라서 언어를 유창하게 만든다. 그러나 여러 오퍼레이션 호출 사이에서  컨텍스트 변수(CONTEXT VARIABLE)를 일관된 상태로 유지해야 하기 때문에  컨텍스트 변수(CONTEXT VARIABLE)가 복잡해 질수록 DSL을 구현하기가 어려워진다.

    컨텍스트 변수(CONTEXT VARIABLE)를 다루는 방식은 내부 DSL의 구현 패턴에 커다란 영향을 미친다.  컨텍스트 변수(CONTEXT VARIABLE)의 수를 최소화하면서 현재의 요구사항을 명확하게 표현할 수 있는 구현 패턴을 선택하는 것이 핵심이다.

    728x90
Designed by Tistory.