LanguageBuilding
주니어 개발자들을 위한 패턴 언어 - 문제 영역의 언어를 만들어 프로그래밍하는 방법
Contents
The Story 1: The Evolving Vocabulary (Programming)
두 명의 개발자, 민수와 하나가 '주문 처리 시스템'의 코드를 작성하고 있다.
민수의 코드 (The Raw Primitives): 민수의 코드는 if-else와 원시 데이터 연산으로 가득하다. "주문을 처리해요. 재고를 확인하고, 결제를 하고, 배송을 준비하고..." 하지만 민수의 코드를 읽으면 그 의도가 한눈에 들어오지 않는다. for 문과 배열 조작 로직 속에 비즈니스의 의미가 묻혀 있기 때문이다. 코드는 기계의 언어로 쓰여 있다.
하나의 코드 (The Domain Story): 하나는 다르게 시작했다. 그녀는 먼저 비즈니스의 개념을 함수와 메서드로 정의했다.
order .validate_inventory() .process_payment() .prepare_shipment() .notify_customer()
"우리가 새로운 단어를 만든 거예요. 문제 영역의 언어를 만드는 거죠." 하나는 Lisp 프로그래머들의 전통을 따랐다. "프로그램을 언어를 향해 작성하는 동시에 언어를 프로그램을 향해 만든다." 하나의 코드는 전문화된 어휘로 잘 쓰인 산문처럼 읽혔다.
The Story 2: The Barista's Tongue (Ordinary Life)
민수와 하나는 커피 전문점에서 바리스타 교육을 받고 있다.
민수의 표현 (The General Language): 민수는 커피 맛을 아주 단순하게만 표현한다. "이 커피는 쓰고 좀 시네요. 뜨거워요." 민수의 언어로는 이 원두와 저 원두의 미묘한 차이를 동료에게 설명하거나 더 나은 맛을 추출하기 위한 구체적인 전략을 세우기 어렵다. 그의 언어는 너무 일반적이다.
하나의 표현 (The Specialized Vocabulary): 하나는 바리스타들만의 전문 용어를 익혔다. "이 원두는 '브루잉' 과정에서 '바디감'이 묵직하게 살아나네요. '산미'는 오렌지 계열이고요." 하나는 '추출 수율', '로스팅 포인트' 같은 단어들을 사용하여 맛의 세계를 정교하게 정의했다. 이 단어들은 하나가 커피라는 복잡한 문제를 다루는 '이론'이 되었고, 동료들과 한 치의 오차도 없이 소통하게 해주었다. 전문적인 어휘가 전문적인 기예를 가능하게 함을 하나는 알고 있었다.
Context
복잡한 문제 영역을 다루는 프로그램을 작성하고 있다. 코드가 길어질수록 이해하기 어려워지고, 새로운 기능을 추가하기가 점점 더 힘들어진다. 함수와 변수를 만들지만, 전체적으로 무엇을 하는지 점점 불명확해진다.
당신은 DataAsFoundation을 통해 데이터 구조의 중요성을 알고 있고, NamesAsDesign을 통해 좋은 이름의 가치를 인식하고 있다. 하지만 개별 함수와 데이터 구조를 넘어서, 문제 영역 전체를 표현하는 더 높은 수준의 무언가가 필요하다는 느낌을 받는다.
Problem
범용 언어의 원시 요소만으로는 문제 영역을 자연스럽게 표현하기 어렵다.
Python, Java, JavaScript 등은 모든 문제를 해결하기 위해 설계되었기에, '특정 문제'를 표현하기에는 너무 일반적입니다.
- 비즈니스 로직이 구현 세부사항(for, if, append) 속에 묻히면 의도가 사라집니다.
- 도메인 전문가와 개발자 사이의 어휘가 다르면 의사소통 비용이 기하급수적으로 증가합니다.
Solution
프로그래밍을 "문제를 표현하는 언어를 만드는 과정"으로 접근하라.
Lisp 프로그래머들이 수십 년간 해온 방식입니다: 먼저 문제를 잘 표현할 수 있는 언어를 만들고, 그 언어로 해결책을 작성하는 것입니다.
Principle 1: Programming as Theory Building
Peter Naur는 "프로그래밍은 단순히 코드를 작성하는 것이 아니라, 문제 영역에 대한 이론(Theory)을 구축하는 것"이라고 했습니다. 코드는 그 이론의 구현일 뿐이며, 진짜 가치는 문제를 이해하고 어휘를 만드는 이론에 있습니다.
Principle 2: Bottom-Up Language Construction
아래에서 위로 언어를 만들어 올라가십시오.
- Level 0: 원시 연산 (filter, map)
Level 1: 도메인 개념 정의 (is_overdue, is_urgent)
Level 2: 도메인 언어 합성 (urgent_overdue_tasks)
- Level 3: 문제 해결
Principle 3: Domain Vocabulary as Functions
문제 영역의 단어를 함수로 만드십시오. 코드가 도메인 전문가가 이해할 수 있는 단어들로 구성될 때 가독성과 유지보수성이 극대화됩니다.
Principle 4: Two Languages - Problem and Solution
TwoWorlds를 기억하십시오. 문제 공간의 언어(도메인 개념)와 해결 공간의 언어(기술적 추상화)는 명확히 분리되되, 각각 풍부하게 구축되어야 합니다.
Real Examples
Example 1: Test DSL - RSpec
RSpec은 테스트를 "User는... correct password로 인증한다"는 명세(Specification)로 읽히게 만들었습니다. 이것은 테스트를 쓰는 새로운 언어입니다.
Example 2: Rails - Convention over Configuration
Rails는 웹 개발을 위한 고유한 언어를 만들었습니다. 선언적 언어로 의도를 표현하면, 프레임워크가 복잡한 세부 사항을 처리합니다.
Common Pitfalls
"Let's Build a Framework First!"
문제를 충분히 이해하기 전에 거대한 프레임워크부터 만들려 하지 마십시오. 언어는 필요에 의해 점진적으로 자라나야 합니다(OrganicGrowth).
"DSL for Everything!"
모든 것에 고유 언어를 만들면 학습 곡선과 유지보수 부담이 커집니다. The95PercentRule을 기억하고 적절한 지점에서 멈추십시오.
Connection to Other Patterns
DataAsFoundation - 언어의 명사(Nouns)를 결정하는 과정입니다. 단단한 데이터 구조가 좋은 언어의 시작입니다. 기반
LivingVocabulary - 구축된 언어는 고정되지 않고, 시스템이 성장함에 따라 함께 살아 움직이며 진화해야 합니다. 지속적 정제
NamesAsDesign - 언어를 만드는 구체적인 행위는 본질적으로 '이름 짓기'라는 설계 활동입니다. 핵심 도구
ComplexityTaming - 잘 설계된 도메인 언어는 복잡한 비즈니스 로직을 단순한 문장으로 변환하여 복잡성을 길들입니다. 목표
Signs of Success
- 코드를 읽으면 비즈니스 이야기가 들린다.
- 도메인 전문가와의 대화가 코드에 그대로 반영된다.
- 주석이 거의 필요 없는 자체 문서화된 코드가 된다.
- 새로운 기능을 추가할 때 언어를 확장하는 것처럼 자연스럽게 추가된다.
The Ultimate Insight
프로그래밍 = 언어 만들기 + 그 언어로 표현하기
범용 프로그래밍 언어는 재료일 뿐입니다. 진짜 예술은 이 재료로 문제 영역의 언어를 만드는 것입니다. 문제를 잘 표현하는 언어를 만들면 해결책은 자연스럽게 따라옵니다.
CategoryPatternLanguage CategoryProgramming CategoryDesign CategoryLanguage CategoryDSL
