#2 Pragmatic Approach
2장 실용주의 접근법
💻 실용주의 프로그래머: Topic 8 좋은 설계의 핵심
1. 좋은 설계의 기준
“좋은 설계는 나쁜 설계보다 바꾸기 쉽다.”
이 문장은 실용주의 프로그래머의 설계 철학을 단 한 줄로 요약한다. 완벽한 설계란 존재하지 않는다. 시간이 지나면 환경이 바뀌고, 요구사항이 변하며, 기술도 낡아간다. 결국 진짜 좋은 설계란 변화에 쉽게 적응할 수 있는 구조, 즉 ETC (Easier to Change) 원칙을 따르는 것이다.
ETC의 핵심은 단순하다. 코드가 수정되거나 기능이 추가될 때, 전체 시스템이 쉽게 바뀌어야 한다는 것이다. 이를 위해 불필요한 결합을 줄이고, 역할을 분리하며, 이름을 명확히 붙여야 한다. 단일 책임 원칙(Single Responsibility Principle) 역시 이 흐름 안에 있다. 좋은 설계는 처음부터 완벽하게 짜인 구조가 아니라, 나중에 바꾸기 쉬운 코드로 완성된다.
2. ETC는 규칙이 아니라 ‘가치’
ETC는 “이렇게 해야 한다”는 강제 규칙이 아니다. 그것은 개발자가 스스로의 결정을 내릴 때마다 떠올려야 할 가치다. “이 설계가 나중에 바꾸기 쉬울까?” 이 질문이 바로 실용주의적 사고의 출발점이다.
ETC는 코드의 가독성, 이름의 명확함, 모듈의 독립성, 테스트 용이성 등 다양한 차원에서 작동한다. 이는 ‘지금 잘 동작하는 코드’를 만드는 것이 아니라, **“미래에 더 잘 바꿀 수 있는 코드”**를 만드는 것이다.
3. 교체 가능한 설계를 고민하라
설계의 진정한 목적은 코드의 교체 가능성이다. 특정 기능을 바꾸거나 확장할 때, 시스템 전체를 뜯어고치지 않고 일부만 수정할 수 있다면 그게 바로 좋은 설계다. 코드가 모듈화되어 있으면 새로운 요구사항이 와도 기존 구조를 유지한 채 확장할 수 있다.
즉, 교체 가능성은 단순히 기술적 완성도가 아니라 유지보수의 생산성을 결정한다. “교체가 쉽다”는 말은 결합도를 낮추고 응집도를 높이는 설계적 균형의 결과물이다.
4. ETC를 위한 실천법
항상 스스로에게 물어라: “내가 지금 수정하는 부분이 전체를 바꾸기 어렵게 만들지는 않았는가?”
테스트를 작성할 때도 생각하라: “이 테스트는 기능이 바뀌어도 쉽게 수정 가능한가?”
이름을 짓는 데 신중하라: 명확한 이름은 나중의 혼란을 줄이고, 코드의 의도를 설명한다.
교체가 가능한 구조를 설계하라: 한 기능의 변경이 다른 모듈에 최소한의 영향을 주도록 하라.
이 모든 질문은 ETC라는 가치로 수렴된다. 실용주의 프로그래머는 규칙을 따르기보다 원칙을 체화한다. 즉, “지금의 결정이 미래의 변화를 어렵게 만들지 않을까?”를 스스로 묻는 개발자다.
5. 실용적 결론
좋은 설계는 완벽한 설계가 아니다. 오히려 변화를 수용할 준비가 된 설계다. 바꾸기 쉬운 구조를 만든다는 것은 결국 인간적인 여유를 남기는 일이다. 불확실한 미래에 대비해, 코드를 유연하게 만들어 두는 것. 그것이 바로 실용주의 프로그래머가 말하는 ‘좋은 설계의 핵심’이다.
💻 실용주의 프로그래머: Topic 9 DRY — 중복의 해악
1. 중복은 단순한 반복이 아니다
‘DRY(Don’t Repeat Yourself)’ 원칙은 단순히 “복붙하지 말라”는 뜻이 아니다. 이 원칙의 본질은 ‘지식(knowledge)’의 중복을 피하라는 데 있다. 프로그램 내에서 동일한 개념이나 규칙이 여러 곳에서 표현되면, 나중에 수정할 때 그 모든 곳을 함께 바꿔야 한다. 이런 중복은 유지보수를 어렵게 만들고, 코드의 신뢰성을 떨어뜨린다. 결국 DRY는 “모든 지식을 시스템 내 단 한 번만, 명확하게 표현하라”는 선언이다.
2. 코드 안팎의 중복
DRY는 코드뿐 아니라 **의도(intent)**의 중복까지 포함한다. 같은 계산 로직이 반복되거나, 동일한 데이터 구조가 코드 여러 곳에 흩어져 있으면 이미 DRY 위반이다. 심지어 테스트 데이터, 문서 주석, DB 스키마 등에서도 같은 정보가 반복된다면 모두 같은 위험을 낳는다. 따라서 실용주의 프로그래머는 “어떤 정보를 바꿀 때, 내가 수정해야 할 곳이 하나뿐인가?”를 늘 자문해야 한다.
3. 다양한 형태의 중복
중복은 여러 형태로 나타난다.
표현상의 중복: 외부 시스템(API, 스키마, 저장소 등)과 연결되며 동일한 지식을 여러 번 표현하는 경우.
데이터 저장소의 중복: 데이터베이스, 캐시, 로그 등에서 같은 정보를 여러 소스에 나누어 저장하는 경우.
개발자 간 중복: 협업 중 서로 동일한 기능을 구현하거나 같은 문제를 해결하는 코드가 여러 버전으로 생기는 경우.
이런 중복은 피하기 어렵지만, 최소화할 수 있다. 내부 API를 명확히 문서화하고, 공용 명세를 정의하며, 공유된 툴로 테스트를 자동화하면 중복을 크게 줄일 수 있다. 핵심은 “모두가 같은 언어로 말하도록 만드는 것” 이다.
4. 재사용성과 DRY의 관계
DRY의 반대는 ‘재사용 불가능한 코드’다. 사람들은 대체로 재사용이 어렵다면 쉽게 포기한다. 따라서 실용주의 프로그래머는 “재사용하기 쉽게 만들라(Tip 16)”는 환경 자체를 설계한다. 명확한 API, 일관된 데이터 구조, 반복 없는 설계가 곧 재사용성을 높인다. 이는 단순히 코드를 절약하는 게 아니라, 시스템 전체의 **지식 일관성(knowledge integrity)**을 지키는 행위다.
요약하자면 DRY 원칙은 “코드를 줄이는 기술”이 아니라 ‘한 번의 변경으로 모든 곳이 바뀌는 시스템’을 만드는 사고방식이다. 실용주의 프로그래머는 중복을 없애며 코드를 정제하고, 유지보수 가능한 시스템이라는 장기적 이익을 추구한다.
💻 실용주의 프로그래머: Topic 10 직교성 (Orthogonality)
1. 직교성이란 무엇인가
‘직교성(orthogonality)’은 서로 영향을 주지 않는 독립성을 의미한다. 그래프의 두 축이 직각으로 만나듯, 하나의 축이 움직여도 다른 축은 변하지 않는다. 소프트웨어에서도 마찬가지다. 한 모듈을 수정할 때, 다른 모듈이 영향을 받지 않는다면 그 시스템은 직교적이라고 할 수 있다.
직교성은 곧 결합도(coupling)를 줄이고, 독립성(independence)을 높이는 설계 철학이다. 한 부분이 바뀌어도 다른 부분이 무사하다면, 테스트·확장·배포가 모두 쉬워진다. 이 원칙을 잘 지키면 시스템의 품질은 즉시 개선된다.
2. 비직교적 시스템의 문제
헬리콥터 조종의 비유가 인상적이다. 헬리콥터는 조종간 하나를 움직여도 나머지 세 축(피치, 요, 롤)에 동시에 영향을 미친다. 즉, 하나를 조정하면 나머지가 엉켜버리는 비직교적 시스템이다. 소프트웨어에서도 이와 같은 현상이 자주 발생한다 — 하나의 기능 변경이 예기치 않게 여러 컴포넌트에 파급효과를 일으키는 것이다.
이런 시스템은 복잡하고, 유지보수가 어렵다. 결합도가 높을수록, 작은 수정이 전체 시스템의 불안정성을 키운다. 결국 “조종하기 어려운 헬리콥터” 같은 프로그램이 된다.
3. 직교적 설계의 장점
직교성을 갖춘 시스템은 생산성과 안정성 모두에서 압도적인 이점을 가진다.
생산성 향상: 모듈이 서로 독립적이기 때문에 테스트와 수정이 빠르고, 코드 추가 시 영향 범위가 작다.
리스크 감소: 결합된 코드가 적을수록, 수정 시 문제 발생 확률이 줄어든다. 시스템의 일부가 고장나도 나머지는 정상 동작한다.
테스트 용이성: 단위 테스트가 단독으로 수행될 수 있으며, 통합 테스트의 복잡성을 크게 줄인다.
코드 명료화: 모듈 간 인터페이스가 명확해지고, 설계 변경 시 예측 가능한 경로를 따라 수정된다.
요약하자면, 직교성은 “작은 변화로 전체를 조종할 수 있는 설계의 단순함”이다.
4. 실무에서의 적용
직교적 설계를 실천하는 방법은 구체적이다.
모듈 간 독립 유지: 서로 다른 책임을 가진 모듈들이 기능을 중복하지 않게 설계한다.
명확한 인터페이스 정의: 각 컴포넌트는 외부와의 계약(API)을 통해서만 소통해야 한다.
중복된 데이터 제거: 같은 정보를 여러 계층이 공유하면 의존성이 생긴다.
유사한 함수 분리: 비슷한 코드를 반복 작성하지 말고, 전략 패턴이나 추상화를 사용한다.
툴과 라이브러리 선택 시 신중: 외부 의존성은 직교성을 깨뜨릴 수 있으므로 기술을 명확히 이해하고 선택한다.
즉, “모듈을 연결하되, 서로 간섭하지 않게 설계하라”는 것이 핵심이다.
5. 직교적으로 살아가기
저자는 직교성을 단순히 설계 원칙이 아니라 개발자의 태도로 본다. 시스템뿐 아니라 팀, 업무, 사고방식에도 적용해야 한다.
회의, 일정, 기능이 서로 얽히지 않게 관리하라.
한 번에 한 문제만 해결하고, 서로 다른 작업이 의존하지 않게 하라.
DRY 원칙과 결합하면, 중복을 줄이고 유연한 시스템을 만들 수 있다.
결국 직교성은 **“변화를 두려워하지 않는 구조”**를 만드는 기술이다. 모듈이 독립적이라면, 언제든 안전하게 리팩터링할 수 있다. 실용주의 프로그래머는 “헬리콥터의 조종간을 부드럽게 움직이는 조종사”처럼, 복잡한 시스템 속에서도 균형을 유지한다.
직교성은 변화의 파급을 최소화하고, 코드의 자유도를 극대화하는 설계 철학이다. “관련 없는 것들 간에 서로 영향을 미치지 않도록 하라.”
💻 실용주의 프로그래머: Topic 11 가역성 (Reversibility)
1. 가역성이란?
“당신이 가진 생각이 딱 하나뿐이라면, 그건 위험하다.” — 에밀 오귀스트 샤르티에
가역성은 **“한 번 내린 결정이 나중에 바꿀 수 있는가?”**에 관한 원칙이다. 즉, 시스템 설계나 기술 선택을 되돌릴 수 있도록 만들어라는 뜻이다.
엔지니어는 흔히 “딱 하나의 정답”을 찾고 싶어 한다. 하지만 현실의 소프트웨어는 언제나 변화한다. 특정 기술·아키텍처·벤더에 종속된 선택을 했다면, 그 선택이 틀렸음을 깨달았을 때 되돌리기가 매우 어렵다.
가역성은 이런 위험을 줄이기 위한 **“미래에 대비하는 유연성의 기술”**이다.
2. 엔지니어의 함정 — 단 하나의 답만 고집하기
엔지니어는 수학 문제처럼 “x=2” 식의 명확한 답을 좋아한다. 그러나 현실은 스프린트, 데드라인, 기술 트렌드 등 수많은 변수에 좌우된다. 한 번 내린 기술 결정(예: 특정 DB, 프레임워크, 아키텍처)은 시간이 흐르며 필연적으로 낡고, 더 나은 대안이 등장한다.
그럼에도 “이미 선택했으니 바꿀 수 없다”는 태도는 가역성 부재의 전형적인 징후다. 결정의 유연성을 잃으면, 프로젝트 전체가 함께 고착된다.
3. 가역적 설계의 핵심 원칙
✅ 1) 결정을 되돌릴 수 있게 설계하라
특정 벤더나 기술에 종속되지 말고, 변경이 가능한 구조를 만들어라. 예: 데이터베이스를 추상화 계층(Repository, ORM 등)으로 감싸면, RDB → NoSQL 교체도 큰 파급 없이 수행할 수 있다.
✅ 2) 되돌릴 수 없는 결정은 신중히 내려라
DB 스키마, API 프로토콜, 외부 계약처럼 바꾸기 어려운 것은 충분한 시뮬레이션과 대안 검토를 거친 후 선택해야 한다.
✅ 3) “최종 결정”이란 없다
책의 Tip 18에서도 말하듯 —
“최종 결정이란 없다.” 결정은 언제나 가설이며, 바뀔 수 있다. 이를 인정해야 시스템도 살아남는다.
4. 유연한 아키텍처 설계
많은 개발자는 코드는 유연하게 유지하면서도 인프라나 배포, 데이터베이스는 고정된 것으로 착각한다. 하지만 가역성은 시스템의 모든 계층에 걸쳐야 한다.
예시 – 현대적 클라우드 기반 구조
거대한 싱잉(monolith) 대신 작은 마이크로서비스 분산 구조
컨테이너 기반 배포로 환경 전환 용이
클라우드 네이티브 서비스(Serverless, managed DB 등) 활용
외부 API, SDK에 직접 의존하지 않고 추상화 계층을 둔다
즉, 환경이 바뀌어도 재배포나 코드 수정 없이 시스템이 작동할 수 있어야 한다.
5. “유행을 좇지 말라”
Tip 19: 유행을 좇지 말라
가역성은 단순히 기술을 쉽게 바꾸는 능력이 아니다. 한 기술에 맹목적으로 의존하지 않는 태도를 말한다.
새로운 프레임워크나 데이터베이스가 유행한다고 해서 당신의 시스템이 반드시 그것을 필요로 하진 않는다. 기술은 항상 변하지만, 가역적인 시스템은 변화에 휘둘리지 않는다.
6. 실용적 적용 전략
인터페이스 기반 추상화: 외부 라이브러리나 DB 접근 코드를 인터페이스로 감싸라.
데이터 포맷 표준화: JSON, YAML, Protocol Buffers 등 교체 가능한 구조로 설계.
실험과 회귀가 가능한 배포 프로세스: rollback 가능한 CI/CD 구성.
“상자 닫기 전에 생각하기” — 미래의 변경 가능성을 고려하라.
결정이 틀렸을 때, “이걸 되돌릴 수 있을까?” 라는 질문에 Yes라고 답할 수 있어야 진짜 실용주의 설계다.
**가역성(Reversibility)**은 “한 번의 선택이 모든 미래를 묶지 않게 하는 힘”이다. “최종 결정이란 없다. 되돌릴 수 없는 선택은 하지 마라.”
💻 실용주의 프로그래머: Topic 12 예광탄 (Tracer Bullets)
1. 예광탄이란 — “어둠 속에서 목표를 찾는 코드”
“준비, 발사, 조준…” 소프트웨어 개발을 ‘사격’에 비유한다면, 예광탄은 **‘조준을 위한 발사체’**다.
실제 전장에서 병사들은 어둠 속에서도 목표를 확인하기 위해 예광탄을 쏜다. 총알에 미량의 발광 물질을 섞어, 탄환 궤적이 눈에 보이게 만드는 것이다. 이 빛의 궤적을 보고 병사는 조준을 다시 잡는다.
개발도 마찬가지다. 프로젝트 초기에 완벽한 설계를 한 번에 만드는 것은 거의 불가능하다. 대신 빠르게 **작동하는 최소한의 코드(예광탄)**를 만들어 실제 환경에서 어떻게 움직이는지를 확인한다. 그 결과를 바탕으로 점차 정교하게 조정해 나가는 것이 실용주의 프로그래머가 말하는 “예광탄 개발(Tracer Development)”이다.
2. 예광탄 개발의 목적 — 빠른 피드백, 명확한 방향
예광탄은 “목표를 맞히는 코드”가 아니라, 목표를 찾기 위한 코드다.
핵심 목적
빠른 피드백 : 실제 실행 가능한 최소 코드를 통해 즉시 결과를 확인한다.
현실 검증 : 이론적 설계가 실제로 유효한지 실험한다.
조정과 학습 : 잘못된 방향을 초기에 교정하고, 팀 전체가 방향을 공유한다.
프로젝트 초기에 UI, API, 데이터 흐름이 어떻게 연결될지 미리 가늠하고, “작동하는 코드”를 통해 팀과 사용자에게 빛을 비춰주는 역할을 한다.
Tip 20. 목표물을 찾기 위해 예광탄을 써라. “Hello World” 수준의 코드라도, 실제 환경에서 돌아가는 첫 탄환이 중요하다.
3. 예광탄 코드와 프로토타이핑의 차이
많은 개발자가 예광탄을 프로토타입(prototype)으로 혼동한다. 하지만 두 개념은 목적부터 다르다.
목적
방향 확인 및 피드백
아이디어 실험 및 폐기
결과
실제 시스템의 일부로 발전
최종 코드에 포함되지 않음
접근
작동 가능한 최소 단위부터 점진 확장
버릴 것을 전제로 빠른 구현
예시
“이 기능이 실제로 작동할까?”
“이 UX를 채택할까?”
즉, 예광탄은 단순한 “연습용”이 아니라, 최종 시스템을 향해 빛을 쏘는 실전용 코드다. 그 자체가 향후 코드베이스의 뼈대가 된다.
4. 예광탄 개발의 장점
✅ (1) 조기 검증 & 피드백
실제 실행 결과를 보면서 즉각 수정할 수 있어, 추측이나 문서 중심 설계보다 훨씬 현실적이다.
✅ (2) 팀 정렬 & 통합
모듈 간의 실제 연동을 통해 팀 전체가 같은 그림을 본다. API, UI, DB 흐름이 일관된지 확인할 수 있다.
✅ (3) 반복적인 개선
매주 빌드마다 작은 예광탄을 쏘며 목표를 점점 정밀하게 조정한다. 이 과정에서 사용자 반응을 즉시 반영하고, “완성도보다 일관성”에 집중한다.
✅ (4) 신뢰 구축
예광탄은 경영진, 이해관계자에게 “진짜 돌아가는 코드”를 보여준다. 즉, 말보다 작동하는 결과물로 설득한다.
5. 실무 적용 — 어떻게 예광탄을 쏠 것인가
최소 기능부터 작동시키기 → DB 연결, API 통신, UI 렌더링 중 가장 핵심적인 흐름 하나를 먼저 완성하라.
통합 테스트를 일찍 도입하기 → 단위 테스트보다 먼저, 시스템 간 연결을 실제로 검증하라.
예광탄 빌드를 지속적으로 반복 → 매주, 혹은 주요 기능마다 빌드 가능한 형태로 코드를 정리하라.
사용자 반응을 빠르게 수집 → 클릭, 반응 속도, 오류 로그 등 실사용 데이터를 수집해 방향을 조정하라.
6. 주의점 — 예광탄은 목표를 “정확히” 맞히는 것이 아니다
예광탄은 완벽한 해법이 아니라 **“탐색의 도구”**다. 때로는 엉뚱한 방향으로 날아갈 수 있다. 하지만 그 덕분에 우리는 빠르게 배우고 수정할 수 있다.
프로젝트가 지나치게 예광탄 중심이 되면 “빠른 구현”에만 몰입해 설계 품질이 떨어질 위험도 있다. 따라서 예광탄 → 리팩터링 → 확장의 순서를 반드시 유지해야 한다.
**예광탄(Tracer Bullet)**은 “작동하는 코드로 방향을 확인하는 개발 방법”이다. “계획보다 실행, 완벽보다 피드백.”
💻 실용주의 프로그래머: Topic 13 프로토타입과 포스트잇
1. 프로토타입이란 무엇인가
프로토타입(prototype)은 아이디어를 구체적으로 실험하기 위한 값싼 모형이다. 실제 제품보다 훨씬 저렴하고 빠르게 만들어, 개념이나 구조, 위험 요소를 검증하기 위해 사용된다.
자동차 제조업체가 신차를 설계할 때 공기역학, 스타일, 구조적 강도 등을 실험하기 위해 다양한 프로토타입을 만드는 것처럼, 소프트웨어에서도 시스템의 핵심 개념이나 위험 구간을 미리 확인하기 위한 모델이 필요하다.
2. 프로토타입의 목적 — “위험을 줄이는 실험”
프로토타입은 완성된 제품이 아니다. 그 목적은 리스크를 조기에 발견하고 제거하는 것이다.
예를 들어,
아직 확신이 없는 기술 스택,
새로 도입할 외부 API,
복잡한 데이터 흐름,
사용자 인터페이스(UI),
성능 병목지점
이런 불확실한 영역들을 짧은 시간 안에 시험해보는 것이 프로토타이핑의 핵심이다.
Tip 21. 프로토타이핑으로 학습하라.
즉, 프로토타입의 가치는 “생산성”이 아니라 “학습과 통찰”에 있다. 문제의 본질을 이해하고 위험을 드러내는 것, 그것이 진정한 목적이다.
3. 프로토타입 vs 예광탄의 차이
이전 Topic 12의 예광탄은 작동 가능한 코드로 방향을 탐색하는 방법이었다. 반면 프로토타입은 실험용 모델로 가설을 검증한다.
목적
작동 방향을 탐색
위험 요소를 검증
결과물
실제 시스템에 포함
폐기되는 실험용 코드
접근 방식
점진적 완성
단기간 집중 실험
예시
“실제 사용자 흐름을 빠르게 확인”
“성능 병목 구간을 테스트”
👉 예광탄은 실용적인 첫 단계, 👉 프로토타입은 위험을 탐색하는 연구 단계로 이해하면 된다.
4. 프로토타입의 대상 — 무엇을 실험할 것인가?
책에서는 “위험을 수반하는 모든 것”을 프로토타이핑 대상으로 제시한다. 예를 들어:
아키텍처 구조
기존 시스템에 추가할 새로운 기능
외부 데이터 연동
써드파티 도구, SDK, 라이브러리
성능 및 부하 테스트
사용자 인터페이스(UI) 설계
즉, 아직 검증되지 않은 모든 부분이 실험 대상이다. 프로토타입은 단순히 코드를 작성하는 행위가 아니라, “무엇이 위험한가?”를 명확히 드러내는 탐사 행위다.
5. 프로토타입의 구성 요소
프로토타입을 만들 때는 완성도를 기대하지 말아야 한다. 오히려 단순하고 빠르게 만드는 것이 핵심이다.
⚙️ 좋은 프로토타입의 특징
정확성보다 속도 : 더미(dummy) 데이터로 충분하다.
완전성보다 핵심 : 필요한 기능 하나만 작동해도 된다.
안정성보다 실험성 : 오류 검사는 생략해도 된다.
스타일보다 본질 : 주석, 문서화는 최소화해도 된다.
프로그래밍 언어 선택도 유연해야 한다. 고수준 스크립트 언어나 로우레벨 도구 등 상황에 맞는 언어로 빠르게 검증하는 것이 좋다.
프로토타입은 “버릴 수 있는 코드”여야 한다. 완성도가 아니라, 깨달음을 남기는 코드가 되어야 한다.
6. 아키텍처 프로토타이핑
아키텍처 수준의 프로토타입은 시스템 전체 구조를 검증한다. 이때의 목적은 “모듈들이 실제로 제대로 연결되고 작동하는가?”를 확인하는 것이다.
아키텍처 프로토타입에서는 다음을 점검한다:
주요 책임이 올바르게 분리되었는가
컴포넌트 간 협력 관계가 안정적인가
중복이 최소화되어 있는가
인터페이스가 명확히 정의되었는가
모듈들이 필요한 데이터에 접근 가능한가
이 중 “모듈 간 데이터 접근성” 문제는 실제 프로젝트에서 가장 자주 실패하는 부분이다. 즉, 초기에 잘못 설계하면 이후엔 고치기 매우 어렵다.
7. 프로토타입 코드를 사용할 때와 아닐 때
프로토타입은 기본적으로 “폐기할 전제”로 만들어야 한다. 그럼에도 어떤 경우엔 프로토타입이 최종 코드의 뼈대로 발전하는 일도 있다.
⚠️ 주의할 점
프로토타입 코드를 “완성된 결과물”로 오해하지 말라.
이해관계자에게 너무 빨리 보여주면, 그걸 그대로 제품으로 착각할 수 있다.
팀 내부에서는 “이건 실험용 코드”라는 점을 명확히 공유하라.
필요하다면 프로토타입 이후에 예광탄 접근법으로 이어지는 것이 좋다. 실험에서 얻은 통찰을 바탕으로, 진짜 작동하는 코드로 옮겨가는 것이다.
8. 프로토타이핑의 실무적 이점
초기 위험 제거 : 실패 비용이 작을 때 문제를 발견한다.
팀 학습 : 빠르게 피드백을 공유하고 기술 역량을 높인다.
디자인 정제 : 실제 사용성을 시험해 UI/UX를 개선한다.
프레임워크 구축 : 반복 가능한 개발 패턴을 확보한다.
즉, 프로토타입은 “소프트웨어 버전의 실험실”이다. 짧은 시간, 낮은 비용, 높은 학습 효율을 제공한다.
**프로토타입(Prototype)**은 “위험을 값싸게 시험하고 학습하기 위한 실험용 코드”다. “완벽을 목표로 하지 말고, 문제를 드러내는 데 집중하라.”
💻 실용주의 프로그래머: Topic 14 도메인 언어 (Domain Languages)
1. 핵심 개념 — “언어가 사고를 만든다”
“언어의 한계가 곧 자기 세계의 한계다.” — 루트비히 비트겐슈타인 (Ludwig Wittgenstein)
프로그래밍 언어는 단순한 문법 도구가 아니라, 사고의 틀이다. 우리가 사용하는 언어는 문제를 정의하고 해결하는 방식을 제한하거나 확장한다.
예를 들어:
C++은 절차적 사고와 객체지향 모델링에 적합하고,
Haskell은 함수형 사고를 촉진한다.
각 언어가 내재한 철학은 문제를 바라보는 방식 자체를 형성한다.
그렇다면 “도메인 언어”란 무엇일까? → 특정 문제 영역(domain)을 가장 자연스럽게 표현할 수 있는 언어적 표현 방식이다. 즉, 프로그램이 현실의 개념과 같은 수준에서 이야기하도록 만드는 것.
2. 핵심 원칙 — 문제 도메인에 가까운 언어로 프로그래밍하라
Tip 22. 문제 도메인에 가깝게 프로그래밍하라.
좋은 개발자는 단순히 코드를 작성하는 것이 아니라, 도메인의 언어를 빌려서 사고하고 표현한다.
예를 들어,
금융 도메인이라면 “이자율”, “원금”, “만기” 등의 용어가 코드에 녹아야 하고,
물류 도메인이라면 “배송지”, “픽업”, “운송 단가” 같은 개념이 그대로 등장해야 한다.
즉, 프로그램의 코드가 곧 도메인의 대화 언어가 되어야 한다.
3. 실제 사례 — 도메인 언어의 구현
(1) RSpec (루비 테스트 DSL)
루비의 테스트 프레임워크 RSpec은 “테스트를 코드가 아닌 문장처럼 읽히게” 만든 대표적 예다.
자연어 문장처럼 읽히기 때문에, **도메인(테스트 시나리오)**과 코드가 분리되지 않는다. 개발자뿐 아니라 기획자나 QA도 이해할 수 있다.
(2) Cucumber (큐컴버)
큐컴버는 비개발자도 읽을 수 있는 테스트 언어를 제공한다.
이 테스트는 자연어로 작성되지만,
내부적으로는 매칭되는 코드(step definitions)가 실행된다.
즉, 언어와 코드의 경계가 사라지는 구조다.
(3) Phoenix Router (피닉스 라우터)
Elixir 기반의 Phoenix 웹 프레임워크는 라우팅을 선언적으로 표현하는 도메인 언어를 제공한다.
한 줄의 선언으로 HTTP 요청을 컨트롤러 동작에 매핑한다. 즉, “웹 애플리케이션의 도메인”을 가장 자연스럽게 표현한 DSL이다.
(4) Ansible (앤서블)
서버 설정 자동화 도구인 Ansible은 YAML로 “시스템 구성”을 코드처럼 표현한다.
사람이 읽기 쉬운 도메인 언어로, “서버가 어떤 상태여야 하는지”를 명확히 기술한다. 이는 곧 인프라의 의도를 코드화한 도메인 언어다.
4. 도메인 언어의 분류
도메인 언어는 크게 두 가지로 나뉜다.
정의
기존 언어 내부에서 DSL을 구현
완전히 별도의 문법으로 DSL 설계
예시
RSpec, Phoenix Router
Cucumber, YAML, SQL
장점
간결하고 실행 속도가 빠름
문법 표현의 자유도가 높음
단점
문법 제약이 있음
파서(parser)가 필요함
5. 왜 도메인 언어가 중요한가
의사소통의 통합: 도메인 전문가와 개발자가 같은 언어로 이야기할 수 있다.
가독성 향상: 코드가 곧 문서가 된다.
확장성 확보: 새로운 개념을 쉽게 추가할 수 있다.
테스트와 문서의 일체화: 실행 가능한 사양(Specification by Example)이 가능해진다.
결국, 도메인 언어는 “코드로 사고하는 방법”을 제공한다. 즉, **도메인 주도 설계(DDD)**의 기초이자, 소프트웨어 언어적 표현의 완성이다.
6. 실무 적용 팁
용어 통일: 도메인 전문가가 사용하는 단어를 코드에서도 동일하게 사용하라.
테스트 문장을 자연어처럼 표현하라: RSpec 스타일로 “~해야 한다(should)” 문장 사용.
DSL을 과도하게 설계하지 말라: 필요한 최소한의 개념만 코드화하라.
내부 언어 → 외부 언어 확장은 신중하게: 파서 생성 비용이 크다.
문제 도메인에 밀착된 이름 짓기: 함수명 하나라도 실제 업무 언어를 반영하라.
**도메인 언어(Domain Language)**는 “현실 세계의 개념을 코드 언어로 그대로 옮기는 기술”이다. “코드를 도메인 전문가의 언어로 말하게 하라.”
💻 실용주의 프로그래머: Topic 15 추정 (Estimation)
1. 핵심 개념 — “추정은 무의미하지 않다”
Tip 23. 추정으로 놀람을 피하라.
추정은 단순히 숫자를 맞추는 행위가 아니다. 시스템의 작동 원리를 이해하고, 불확실성을 통제하는 사고 방식이다.
예를 들어,
“100MB 텍스트를 압축하는 데 걸리는 시간은?”
“프로젝트가 끝나려면 몇 개월이 필요할까?”
“1Gbps 네트워크로 데이터를 전송하면 얼마나 걸릴까?”
이 질문들은 모두 막연한 수치 감각과 시스템 이해력을 요구한다. 즉, 추정 능력은 프로그래머가 “자신의 코드와 시스템의 물리적 한계”를 몸으로 이해하는 방법이다.
2. 추정의 목적 — "놀라지 않게 만들기"
추정은 완벽히 맞추기 위한 것이 아니라, 예상 밖의 일(놀람)을 최소화하는 도구다.
“추정은 틀리더라도 ‘얼마나 틀릴 수 있는지’를 아는 과정이다.”
예를 들어, 프로젝트가 3개월이 걸릴 거라 했는데 실제로 4개월이 걸린다면, 그건 실패가 아니라 추정 편차를 이해한 성공적인 피드백이다.
3. 정확도의 기준 — “얼마나 정밀해야 충분한가?”
모든 추정은 오차가 있다. 중요한 건 “얼마나 정밀해야 하는가”를 결정하는 것이다.
1~15일
일
3~6주
주
8~20주
월
즉, 맥락에 맞는 단위로 추정하라. 초 단위까지 맞출 필요는 없다. 단지 의사결정이 가능한 수준이면 충분하다.
4. 추정의 근원 — “모델에서 나온다”
모든 추정은 문제의 모델에서 시작된다. 즉, “어떤 일이 일어나고, 어떤 변수가 작용하는가”를 이해하지 못하면 정확한 추정은 불가능하다.
예시:
서버 처리량을 추정하려면 네트워크 속도, 디스크 I/O, 쓰레드 개수 등의 모델이 필요하다.
프로젝트 기간을 추정하려면 팀 규모, 병렬 작업량, 피드백 주기 등의 모델이 필요하다.
이 모델을 세우지 않은 상태에서 단순히 “감”으로 추정하면 항상 낙관적인 수치가 나온다.
5. 실무 추정 절차
(1) 모델 만들기
“이 시스템은 어떻게 작동하는가?”를 이해하고, 이를 기반으로 계산 가능한 모델을 만든다.
(2) 컴포넌트로 분해하기
전체 모델을 작은 컴포넌트 단위로 나누고, 각 부분이 결과에 미치는 영향을 평가한다.
(3) 매개변수 값 추정
주요 변수(속도, 크기, 반복 수 등)에 합리적인 값을 넣는다.
유사한 시스템의 경험치를 참고하면 좋다.
(4) 계산하기
각 변수를 대입하여 전체적인 추정치를 계산한다.
필요하면 근사값이나 단순화된 공식으로 접근한다.
(5) 결과 검증하기
실제 수행 결과와 비교하여 추정 정확도를 기록한다.
피드백을 통해 추정 모델을 개선한다.
6. 실무 적용 예시
💡 예시 1. 네트워크 전송 시간 추정
“1Gbps 네트워크로 1TB 데이터를 전송하려면?”
즉, 순수 전송 시간만 2시간 20분, 오버헤드(손실, 재시도, I/O 등)를 고려하면 약 3시간 내외로 추정 가능하다. 이 정도 정확도면 의사결정에 충분하다.
💡 예시 2. 프로젝트 일정 추정
“이 프로젝트는 얼마나 걸릴까?”
전체 기능을 반복(iteration) 단위로 나눈다.
각 반복 주기에 기능 구현 + 테스트를 포함시킨다.
실제 수행 후 추정 오차를 기록하고, 다음 주기 계획에 반영한다.
Tip 24. 코드와 함께 일정도 반복하며 조정하라.
즉, 일정 추정도 코드처럼 애자일하게 다뤄야 한다.
7. 추정 능력을 키우는 법
✅ ① 추정 결과를 항상 기록하라
실제 결과와 비교해 오차를 파악하라.
추정이 잘못된 이유를 찾아 모델을 개선하라.
✅ ② 실험을 통해 체득하라
CPU, 디스크, 네트워크 성능 등 시스템 실험을 통해 감각을 익혀라.
단순히 “느낌상 빠르다”가 아니라, “이 작업은 초당 2000 I/O 처리 가능”처럼 구체적 수치로 말할 수 있어야 한다.
✅ ③ 질문의 의도를 파악하라
“이 일은 얼마나 걸릴까요?” → “어떤 정확도로, 어떤 단위로 필요하신가요?”라고 되묻는다. 상대의 기대 수준을 명확히 파악해야 한다.
8. 프로젝트에서의 추정 원칙
추정은 모델링이다 → 감이 아니라 시스템을 수학적으로 이해하라.
정확성보다 일관성이 중요하다 → 오차 범위를 줄이는 게 핵심이다.
추정은 기록이며 피드백이다 → 매번 비교해 학습하라.
반복(iteration)은 추정을 개선하는 실험이다.
추정은 책임 회피가 아니라 위험 관리 도구다.
9. 도전해 볼 것
자신이 작성한 코드나 시스템의 성능을 직접 측정하고, “내 예상과 얼마나 차이 나는가?” 기록하기.
과거 프로젝트의 추정치와 실제 일정 비교해서, 오차의 주된 원인(요구 변경, 인력 부족, 통신 지연 등) 찾아보기.
**추정(Estimation)**은 ‘정답을 맞히는 기술’이 아니라 **‘불확실성을 이해하고 통제하는 기술’**이다. “모델을 만들고, 실험으로 검증하라. 놀라지 않게 만드는 것이 진짜 추정이다.”
Last updated