1. 핵심 아이디어
"We can see that wishful thinking is a powerful tool for building abstractions. In fact, this is how large systems are designed. We name something and then explore its use, assuming that it exists, before we implement it."
(희망적 사고는 추상화를 구축하는 강력한 도구입니다. 실제로 대규모 시스템은 이렇게 설계됩니다. 무언가에 이름을 붙이고, 구현하기 전에 그것이 존재한다고 가정하고 사용법을 탐색하는 것입니다.)
우리는 컴퓨터 프로그래밍의 구조와 해석을 다룬 고전 교재 SICP(Structure and Interpretation of Computer Programs)의 ‘Wishful Thinking’ 방법론을 활용해, 초보자가 이미 일상에서 하고 있는 추상화 사고를 코드로 전이시키는 방법을 가르치려고 합니다.
2. 추상화란 무엇인가?
추상화는 What과 How를 분리하는 것입니다.
What: 무엇을 하는가 (본질, 의도)
How: 어떻게 하는가 (구현, 세부사항)
커피 주문을 생각해보세요. "아메리카노 주세요"(What)라고 말할 때, 당신은 원두가 3번 선반에 있는지, 머신 온도가 93도인지(How) 몰라도 됩니다.
코드도 마찬가지입니다. cafe.order('americano')라고 쓸 때, 내부 구현을 몰라도 됩니다. 사용하는 쪽(caller)은 What만 알면 되고, 구현하는 쪽(callee)이 How를 책임집니다. 이 분리가 추상화의 본질입니다.
Wishful Thinking은 이 추상화를 만드는 사고법입니다.
"이런 게 있으면 좋겠다"(What)를 먼저 상상하고, "어떻게 만들지"(How)는 나중에 생각합니다. SICP는 이것을 "희망적 사고(Wishful Thinking)"라고 불렀고, 이것이야말로 추상화의 핵심 사고방식임을 강조했습니다.
SICP는 MIT에서 수십 년간 컴퓨터 과학 입문 과정으로 사용되며 이 방법론을 검증했습니다. 전 세계 수많은 프로그래머들이 이 방식으로 추상화를 배웠고, "구현 전에 이름을 짓고 사용법부터 탐색"하는 것이 대규모 시스템 설계의 핵심임이 밝혀졌습니다.
우리는 이 검증된 방법론을 현대 프론트엔드 맥락으로 번역하고, 체계적인 학습 경로로 재구성했습니다.
3. 문제 상황: 고칠거면 근본적으로 고쳐야 하는데…
증상만 고치기 vs 원인 찾기
SICP는 왜 Wishful Thinking을 이야기했을까요? 초보자가 버그를 만났을 때를 떠올려보세요.
Uncaught TypeError: Cannot read properties of null 에러가 뜹니다. 초보자는 "null 체크 추가해야지"라고 생각하며 바로 if (data !== null) 코드를 추가합니다.
반면 전문가는 "왜 null이 들어왔지?"라고 묻습니다. 데이터 흐름을 추적하고, 근본 원인을 찾은 후, 여러 해결 방법을 떠올리고, 그중에서 가장 경제적인 선택을 합니다.
추상화도 똑같습니다. 코드가 이상하게 느껴질 때, 초보자는 "복잡해 보이네? 함수로 쪼개자!"라고 생각하며 바로 분리를 시작합니다. 전문가는 "왜 복잡하지?"라고 먼저 묻습니다. 요구사항을 다시 보고, 이상적 형태를 떠올린 후, 그 방향으로 개선합니다.
실제 대화를 들어보면 이 문제가 더욱 명확해집니다.
코치: "왜 이렇게 분리하셨나요?"
학습자 A: "...복잡해 보여서요"
학습자 B: "...함수가 너무 길어서요"
학습자 C: “…죄송합니다”
대체로 느낌만 있고 명확한 기준이 없는 상태입니다. 다수의 학습자가 코드의 물리적 '분리'나 '추출'을 '추상화'로 동일시하고 있으며, "왜 그렇게 분리했는지"에 대한 판단 근거가 없습니다.
다른 예시를 들어보겠습니다.
•
useEffect랑 useState의 흐름이 복잡해 보이면 커스텀 훅이나 컴포넌트로 분리한다
•
props가 많으면 config나 options 같은 객체로 묶고, 조건이 복잡하면 분기를 추가합니다.
그런데 위와 같은 방식으로 고치고 나면 오히려 더 복잡해질 때가 많습니다. 시연을 보거나 피드백을 받아도 행동이 크게 달라지진 않습니다. 학습자들이 보는 것은 "코드를 분리하는 행위" 그 자체에 지나지 않을때가 많습니다. 결과적으로 "왜 그렇게 분리했는지"에 대한 판단 근거를 갖추는 것까지는 이어지지 못합니다.
물론 이전 챕터에서 우리는 코드의 '얽힘'을 배웠습니다. 시간축 얽힘, 암묵적 의존 등 복잡도를 높이는 주요한 원인들이죠.
하지만 얽힘을 배웠다고 해서 문제가 끝나는 건 아닙니다.
•
실무 코드에서 실제로 배움을 적용(eg. "이게 시간축 얽힘인가? 암묵적 의존인가?")하며 효과적인 판단을 내리기 쉽지 않습니다.
•
막상 얽힘을 발견해도 어떻게 풀지 모릅니다. "얽혀있네"는 알겠는데, "그래서 어떻게?"가 막막합니다.
•
설령 풀 수 있다 해도 되는대로 마구 고칩니다. 눈에 보이는 얽힘마다 덤벼들다가 오히려 더 복잡해지기도 합니다. 손에 망치를 들면 전부 못처럼 보이는 것이지요.
왜 이런 일이 일어날까요?
Wiedenbeck(1985) 연구가 이를 명확히 보여줍니다.
초보자는 겉으로 드러난 '증상(symptom)'만 고치려 합니다. 마치 슬롯머신 당기듯이 막연히 수정하고 문제가 해결되기를 바랍니다. 반면 전문가는 근본적인 '원인(fault)'을 찾고, 전체적인 전략을 세웁니다.
초보자가 겉만 고치는 이유는 두 가지입니다:
1.
본질을 찾아야 한다는 걸 모름 (동기)
•
"복잡해 보이면 쪼개면 되지 않나?"
•
"이미 분리했는데 뭐가 더 필요해?"
•
본질을 찾는 게 왜 중요한지 경험이 없음
2.
본질을 찾는 방법을 모름 (능력)
•
"본질이 중요한 건 알겠는데, 어떻게 찾아?"
•
"요구사항을 봐도 뭐가 본질인지 모르겠어"
•
구체적인 방법론이 없음
그럼 이 예시에서 "근본 문제"는 무엇일까요? 바로 얽힘입니다.
useEffect가 복잡한 증상 뒤에는, 데이터 페칭과 상태 관리와 라우팅이 시간축으로 얽혀있다는 근본 문제가 있습니다. 초보자는 "복잡해 보이니까 쪼개자"고 하지만, 얽힘은 그대로입니다.
Props가 많은 증상 뒤에는, 컴포넌트가 너무 많은 것을 알아야 한다는 근본 문제가 있습니다. 초보자는 "config로 묶자"고 하지만, 수정 후에도 여전히 많은 것을 알아야 하는 건 마찬가지 입니다.
Chi(1981)의 연구도 같은 패턴을 보여줍니다. 초보자는 표면적 특징(복잡해 보임)으로 문제를 범주화하지만, 전문가는 깊은 구조(얽힘의 종류)로 범주화합니다.
해결의 방향: 요구사항에서 본질에 대한 힌트를 찾기
자료를 참고하세요!
그럼 전문가는 어떻게 다르게 할까요? 코드만 보면 안 됩니다. 요구사항을 다시 봐야 합니다.
핵심 차이는 "이상적 형태"를 먼저 상상하느냐입니다. 방향 없이 코드를 고치면 더 꼬이지만, 이상을 먼저 상상하면 명확한 방향성이 생깁니다.
"사용자는 제품 목록을 보고, 빈 목록이면 empty 페이지로 이동한다." 이 요구사항에서 본질은 "제품 목록 보여주기"입니다. 그럼 이상적으로는 <List items={products} />처럼 되어야 합니다.
사고 과정의 차이를 비교해보면:
초보자 (증상 처리)
얽힌 코드 발견
↓
바로 분리 시도
↓
"추상화 했다!"
↓
질문: "왜 그렇게 했어?"
답변: "...복잡해 보여서요"
↓
문제: 판단 근거 없음
Plain Text
복사
전문가 (근본적 원인 해결)
얽힌 코드 발견
↓
요구사항 다시 보기
↓
본질 파악: "제품 목록 보여주기"
↓
이상적인 형태: "List가 있으면 좋겠다"
↓
여러 선택지 고려:
• 옵션 1: 하나의 큰 컴포넌트
• 옵션 2: List + Item 분리
• 옵션 3: List + useProducts 분리
↓
트레이드오프 검토:
• 재사용성 vs 복잡도
• 유연성 vs 단순함
↓
경제적 선택: List + useProducts (데이터 소스 변경 가능성 고려)
↓
일반해로 표현: <List items={products} />
↓
질문: "왜 그렇게 생각하셨나요?"
답변: "요구사항의 본질이 '목록 보여주기'라서
여러 분리 방법 중 데이터 페칭을 분리하는 게
변경 비용 대비 효과가 가장 크다고 판단했습니다"
↓
해결: 명확한 판단 근거 + 경제적 선택
Plain Text
복사
좋아보입니다. 하지만, 문제는 초보자가 이 "이상적 형태"를 상상조차 못 한다는 것입니다.
4. 문제 진단: 왜 상상을 못 할까?
초보자가 "이런 게 있으면 좋겠다"를 떠올리지 못하는 이유는 세 가지입니다.
첫째, 추상화의 단위가 되는, ‘일반해 어휘’가 없습니다.
영어 단어를 모르면 영어 문장을 만들 수 없듯, Form, List, Dialog 같은 추상화 패턴을 모르면 "이런 게 있으면 좋겠다"고 상상할 수 없습니다.
Prat(2020) 연구는 프로그래밍 학습이 수학보다 외국어 학습에 가깝다는 것을 밝혔습니다. 추상화를 문장 쓰기에 비유할 수 있다면, 마찬가지로 문장의 구성 요소가 되는 ‘어휘’를 공부할 필요가 있다는 걸 알 수 있습니다.
둘째, 요구사항을 단계별 추상화로 분해하는 방법을 모릅니다.
"검색 기능이 붙어 있는 제품 목록 페이지 만들어주세요”라는 요청을 보면, 전문가는 자연스럽게 요구사항을 여러 추상화 레벨로 나눕니다. (레벨 0: 페이지 → 레벨 1: List + Search → 레벨 2: 각 컴포넌트 구현)
하지만 초보자는 모든 걸 한 레벨에서 생각하며 복잡도에 압도됩니다.
셋째, What과 How를 분리하지 못합니다.
전문가는 "무엇을 만들지(What)"를 먼저 정하고 "어떻게 구현할지(How)"는 나중에 생각합니다.
"검색 기능이 붙어 있는 제품 목록 페이지 만들어주세요"라는 요청을 보면, 초보자는 구현(How)부터 생각합니다. "useState로 검색어 받고, useEffect로 API 호출하고, map으로 돌려서 카드 렌더링하고..." 머릿속이 구현 세부사항으로 가득 차서 복잡도에 압도됩니다.
전문가는 의도(What)부터 생각합니다: "검색 가능한 제품 목록이 필요하네. 그럼 <SearchableList items={products} onSearch={...} />처럼 되면 좋겠다." 그 다음에야 "useQuery로 데이터 가져올까?"를 생각합니다.
5. 추상화 능력을 구성하는 3가지 역량
Wishful Thinking을 잘 하려면 세 가지 역량이 필요합니다. 이것들은 따로 떨어진 기술이 아니라, 함께 작동하는 하나의 능력을 구성합니다.
Wishful Thinking 기반 추상화를 잘 하려면?
├─ 요구사항 분해 능력 (추상화 레벨 나누기)
│ ├─ A. 고객 언어 → 개발 언어 번역 (추상 의도를 구현으로)
│ │ 예: "제품을 보고 싶어요" → "목록 조회 + 상세 보기"
│ ├─ B. 큰 것 → 작은 것 나누기 (추상화 계층 구조 나누기)
│ │ 예: "제품 목록 페이지" → "List + Search + Filter"
│ └─ C. 본질 찾기 (환원적 사고)
│ 예: 복잡한 조건 → "권한이 있으면 보여준다"
│
├─ 일반해 어휘 보유 (추상화 패턴 알기)
│ ├─ E. 패턴 라이브러리 알기 (검증된 추상화들)
│ │ 예: List, Form, Dialog의 역할과 사용 시점
│ ├─ F. 욕구 → 일반해 매핑 (상황을 추상화로 번역)
│ │ 예: "입력 받기" → Form, "확인 받기" → Dialog
│ └─ G. 조합 단위 인식 (추상화 조합하기)
│ 예: Form + Input + Button = SignupForm
│
└─ 인터페이스 설계 감각 (What 설계하기)
├─ H. 좋은 인터페이스 판단 (What이 명확한가?)
│ 예: useProducts() vs fetchAndSetProductsAndNavigate()
├─ I. 사용자 관점 유지 (What 부터 생각하기)
│ 예: "이렇게 쓸 수 있으면 좋겠다" 먼저
└─ J. 변경 대응 설계 (What은 명확하게, How는 유연하게)
예: 유연함 vs 구체성 균형
Markdown
복사
이 역량들이 어떻게 함께 작동하는지 예시를 보겠습니다:
상황: 기획자가 "사용자는 제품 목록을 볼 수 있다"고 요청합니다.
1단계: 요구사항 분해
먼저 고객의 말을 개발 언어로 번역합니다.
"제품 목록을 본다"는 결국 "데이터를 조회해서 화면에 표시하는 것"이죠. 그 다음 큰 것을 작은 것으로 나눕니다. "제품 목록 페이지"는 "목록 표시 부분"과 "데이터 가져오는 부분"으로 나눌 수 있습니다. 마지막으로 본질을 찾습니다. 여러 가지 중에서 핵심은 "목록 보여주기"입니다.
2단계: 일반해 어휘 활용
"목록 보여주기"라는 욕구를 듣자마자 머릿속에 List 패턴이 떠오릅니다.
일반해 어휘를 알고 있기 때문이죠. "데이터 가져오기"는 useProducts 같은 커스텀 훅으로 표현할 수 있겠네요. 이 둘을 조합하면? List + useProducts 조합이 나옵니다.
3단계: 인터페이스 설계
그럼 어떻게 쓰면 좋을까요? <List items={products} /> 이렇게 쓸 수 있으면 좋겠습니다. What(목록 보여주기)이 명확하죠.
사용자 관점에서 생각해봐도 "이렇게 쓰면 간단하겠네"라고 느껴집니다. 나중에 데이터 소스가 바뀌어도 List 컴포넌트는 그대로 쓸 수 있습니다. What(무엇)은 고정하고 How(어떻게)만 바꾸면 되니까요.
6. 우리의 접근: 추상화 능력을 체계적으로 기르기
이처럼 추상화 과정에서 세 가지 역량이 함께 작동합니다.
•
요구사항 분해 (본질 파악)
•
일반해 어휘 (패턴 매칭)
•
인터페이스 설계 (사용 방법 결정)
추상화 능력을 구성하는 이 세 가지 요소를 체계적으로 가르치는 5단계 학습 경로를 설계했습니다.
1.
일상 사례로 인식하기
2.
일반해 어휘 사전
3.
번역 연습하기
4.
What to How
5.
Wishful Thinking 적용하기 실습
1단계: 일상 사례로 인식하기
커피 주문할 때 원두가 어느 선반에 있는지 아시나요? 머신 온도가 몇 도인지 아시나요? 손님은 모릅니다. 그냥 '아메리카노 주세요'라고 하잖아요. 이게 바로 추상화입니다. What과 How가 분리되어 있어요.
학습자가 이미 일상에서 추상화 사고를 하고 있음을 깨닫게 합니다. 추상화가 먼 얘기가 아니라 일상적으로 하는 것임을 인식시킵니다. 훈련 또한 일상 속에서 숨쉬듯이 할 수 있습니다.
2단계: 일반해 어휘 사전
// 데이터 표시
<List items={data} />
<Table rows={rows} />
<Card content={user} />
// 사용자 입력
<Form onSubmit={handleSubmit} />
<Input value={value} onChange={onChange} />
<Select options={options} onSelect={onSelect} />
// 상호작용
<Dialog open={isOpen} />
<Modal content={content} />
<Dropdown items={items} />
// 네비게이션
<Link to={path} />
<Button onClick={handleClick} />
Markdown
복사
List, Form, Dialog, Button, Input, Select 같은 패턴 라이브러리를 익히도록 해야 합니다. 이것이 추상화의 어휘이기 때문입니다. List는 "목록 보여주기"라는 What을 표현하는 추상화이고, Form은 "입력 받기"라는 What을 표현하는 추상화입니다.
Sweller(1988)의 인지부하 이론에 따르면, 완성된 예시(Worked Examples)를 보는 게 스키마 구축에 더 효과적합니다. 각 패턴의 What(역할)과 사용 시점을 예시와 함께 제시합니다.
예를 들면, “Form은 사용자의 입력을 받아 어딘가로 보내는 역할을 하며, onSubmit을 인터페이스로 가져야 한다” 같은 정의와 형태를 공부하는 겁니다.
일반해의 보다 세부적인 내용들에 대해서는 별도의 추가적인 챕터로 분리하여 다룰 예정입니다.
3단계: 번역 연습하기
복잡한 코드를 보면 "이런 게 있으면 좋겠다"를 떠올려야 하는데 초보자는 막막할 뿐입니다.
"뭐가 있으면 좋을까?" 자체가 안 떠오르죠. 그래서 구체적인 번역 공식을 연습해야 합니다. 특정 패턴을 보면 자동으로 "이런 게 있으면 좋겠다"가 떠오르게요.
연습 템플릿 (예시):
1.
복잡한 코드를 확인합니다: “음, 이거 뭐 하는 코드지? 왜 이렇게 반복되는 코드가 많고 복잡하지?”
2.
요구사항 문서를 봅니다: "사용자는 제품 목록을 볼 수 있다"
3.
이상적인 형태를 적습니다: "아, 결국 List가 필요한거네"
4.
변환 공식을 적용합니다: "반복 → 자동으로" = <List items={products} />
이 연습을 반복하면, 요구사항을 보자마자 자연스럽게 추상화 패턴이 떠오르게 됩니다.
변환 공식 1: "단계가 많으면" → "한 번에 되면 좋겠다"
변환 공식 2: "반복되면" → "자동으로 되면 좋겠다"
변환 공식 3: "조건이 복잡하면" → "의도만 말하면 좋겠다"
4단계: What to How
같은 요구사항을 각 레벨에서 What만 생각하는 방식, How는 나중으로 미루는 방식으로 두 가지로 각각 보여줍니다. "세부사항부터"와 "희망사항을 먼저" 각각의 방식 간에 얼마나 큰 인지부하 차이가 있는지를 직접 체감해볼 수 있습니다.
AS-IS: How(세부구현) to What(본질):
// 1. 먼저 세부 구현부터 생각
function getBeansFromShelf(shelfNumber) {}
function getFilterFromDrawer(drawerNumber) {}
function setMachineTemperature(machine, temp) {}
function setMachinePressure(machine, pressure) {}
function extract(machine, beans, filter, time) {
const espresso = machine.brew(beans, filter, time);
return espresso;
}
// 2. 그걸 조합해서 커피 만들기
function makeAmericano() {
const beans = getBeansFromShelf(3);
const filter = getFilterFromDrawer(2);
const machine = equipment.espressoMachine;
setMachineTemperature(machine, 93);
setMachinePressure(machine, 9);
const espresso = extract(machine, beans, filter, 25);
const water = addHotWater(espresso, 200);
return water;
}
JavaScript
복사
TO-BE: What(본질) to How(세부구현):
// What부터 상상
orderCoffee('americano') // What: 아메리카노 주문
// 한 레벨 내려가서 What
function orderCoffee(menu) {
return cafe.make(menu); // What: 카페가 만듦
}
// 또 한 레벨 내려가서 What
cafe.make = function(menu) {
const recipe = getRecipe(menu); // What: 레시피 가져옴
return brew(recipe); // What: 레시피로 만듦
}
// 마지막에 How
function brew(recipe) {
const beans = getBeansFromShelf(3); // 이제서야 How
// ...
}
JavaScript
복사
5단계: Wishful Thinking 적용하기
직접 ‘주석 → 코드’를 실무 상황에서 작성하며 Wishful Thinking을 체화합니다.
각 화살표는 "한 단계 구체화"를 의미합니다. 필요하면 더 많은 단계로 나눌 수도, 더 적게 나눌 수도 있습니다. 중요한 것은 항상 추상(What)에서 시작해서 점진적으로 구체(How)로 내려간다는 것입니다.
// [추상] 의도
// 제품 목록을 보여준다
// [추상] 인터페이스 상상 (이런 게 있으면 좋겠다)
// const products = useProducts()
// <List items={products} />
// [구현] 실제 코드
const products = useQuery(productQueryOptions());
TypeScript
복사
주의: 추상화는 한 번으로 끝나지 않는다
Wishful Thinking을 한 번 하면 끝일까요? 아닙니다. 추상화는 재귀적으로 반복됩니다.
SICP는 모든 프로그래밍 언어가 제공해야 할 3가지 메커니즘을 제시합니다:
1.
Primitive expressions (기본 요소)
2.
Means of combination (조합 방법)
3.
Means of abstraction (추상화 방법)
핵심은, 이 3단계가 끝없이 반복된다는 것입니다. 추상화된 것이 다음 레벨의 Primitive가 되고, 그것을 조합하고, 다시 추상화합니다.
// 🔄 사이클 1: useProducts 만들기
// Wishful Thinking: "제품 가져오는 게 있으면 좋겠다"
const products = useProducts() // ← 아직 없지만 상상
// 구현 (How)
function useProducts() {
return useQuery(...)
}
TypeScript
복사
// 🔄 사이클 2: useProducts가 이제 Primitive!
// Wishful Thinking: "제품 페이지가 있으면 좋겠다"
function ProductPage() {
const products = useProducts() // ← Primitive처럼 사용
const filter = useFilter() // ← 또 다른 Primitive
return <List items={products} filter={filter} /> // ← 조합
}
TypeScript
복사
// 🔄 사이클 3: ProductPage가 이제 Primitive!
// Wishful Thinking: "앱이 있으면 좋겠다"
function App() {
return (
<Routes>
<Route path="/products" element={<ProductPage />} /> // ← Primitive
<Route path="/cart" element={<CartPage />} />
</Routes>
)
}
// 이 과정은 끝없이 반복됩니다...
TypeScript
복사
추상화 계층이 쌓일 수록 이전 레벨의 How는 점차 추상화 벽 뒤로 숨겨집니다:
•
useProducts 내부의 useQuery 호출 (How)
◦
useProducts는 "제품 가져오기"라는 What만 보임
▪
ProductPage 내부 구현 (How)
•
ProductPage는 "제품 페이지"라는 What만 보임
◦
…
이처럼 상위 레벨의 How가 하위 레벨의 What이 되면서, 계층적으로 추상화가 쌓여갑니다.
이는 마치 인간의 뇌세포가 분화하고, 기능적으로 발달하면서 주름이 안으로 말려들어가면서 상위 차원의 구조를 만들어내는 메커니즘(인폴딩, infolding)과도 같습니다.
인간의 인지 관점에서 좀 더 이어서 생각해보자면, How가 추상화 벽 안쪽으로 숨겨지는 과정을 기술의 숙달로 비유해볼 수도 있겠습니다. 어떤 기술이 숙달되면 더 이상 구분동작을 의식하지 않아도 자연스럽게 수행할 수 있게 됩니다. 이는 일종의 자동화 또는 절차적 기억의 형성으로 이해할 수 있습니다. 세부사항을 몰라도 된다는 점에서 일종의 추상화인 셈입니다.
7. 다른 교육 커리큘럼과의 차별점
검증된 방법론
Wishful Thinking은 우리가 새로 만든 개념이 아닙니다. MIT의 전설적인 교과서 SICP(Structure and Interpretation of Computer Programs, 1985)에서 이미 40년 전부터 가르쳐온 추상화 사고법입니다.
SICP는 "이름을 먼저 짓고(What), 사용법을 탐색한 뒤, 구현(How)한다"는 순서를 일관되게 훈련시킵니다. What이 안정되면 How는 교체 가능해지고, 변경 비용은 내부로 모입니다.
우리는 이 검증된 방법론을 현대 프론트엔드 맥락으로 번역했습니다. const products = useProducts()처럼 이상적 호출을 먼저 쓰고, 그 계약을 만족하도록 내부를 구현하는 것이 바로 SICP의 ‘Wishful Thinking’입니다.
추상화 역량의 명시적 분해
기존 추상화 교육은 "추상화 잘하기"라는 목표를 제시하지만, 정작 무엇을 어떻게 훈련해야 하는지는 모호합니다. "공통점을 찾아라", "본질을 파악하라"는 조언은 맞지만, 구체적으로 무엇을 연습해야 하는지 알 수 없습니다.
우리는 "추상화"라는 추상적인 역량을 구체적인 하위 역량으로 명시적으로 분해합니다.
학습자는 "지금은 'E(추상화 패턴 라이브러리)'를 배우는구나", "다음은 'F(상황 → 추상화 매핑)'를 해야겠구나"라고 명확히 알 수 있습니다.
더 중요한 것은, 각 역량마다 훈련 성공 기준을 제공한다는 점입니다.
예를 들어:
•
‘패턴 라이브러리’의 성공 기준: "List, Form, Dialog를 보고 각각 언제 쓰이는지 설명할 수 있다"
•
‘매핑’의 성공 기준: "기획서 문장을 보고 3초 안에 해당하는 추상화 패턴을 떠올릴 수 있다"
•
‘인터페이스 판단’의 성공 기준: "useProducts() vs fetchAndSetProductsAndNavigate()를 보고 어느 것이 더 좋은 인터페이스인지 근거와 함께 설명할 수 있다"
이것이 기존 교육과의 핵심 차이입니다. "추상화를 잘하라"는 막연한 목표가 아니라, 무엇을 훈련하고(명시적 분해), 얼마나 달성했는지(성공 기준)를 명확히 알 수 있습니다. 학습자는 스스로 점검하며 주도적으로 학습할 수 있습니다.
과정 중심
린다 플라워는 『글쓰기의 문제해결전략』에서 이렇게 말합니다:"
“나는 작문을 기존의 결과 중심의 수사학에서 과정 중심의 접근방법으로 전환하여 연구하기로 하였다. 잘 조직된 글은 어떠해야 하는지를 정의내리는 대신에 어떻게 글을 구성해 가는지에 대한 과정을 보여주고자 하였다.”
이 통찰은 추상화 교육에도 정확히 적용됩니다. 기존 추상화 교육은 결과를 정의합니다. "추상화란 공통점을 뽑아내는 것", "추상화란 불필요한 세부사항을 숨기는 것" - 이것은 완성된 추상화가 무엇인지(what)를 설명하지만, 어떻게 추상화를 만드는지(how)는 가르쳐주지 않습니다.
우리는 다릅니다. 추상화를 만드는 사고 과정 자체를 가르칩니다. "커피 주문"이라는 일상 경험에서 시작해, "이런 게 있으면 좋겠다"고 상상하고, 그 희망을 주석으로 적고, 인터페이스로 구체화하고, 마지막에 구현하는 - 이 전체 과정을 체험하게 합니다.
플라워가 말했듯, "능숙한 필자와 미숙한 필자가 각기 다른 전략을 사용"합니다. 마찬가지로 능숙한 개발자와 미숙한 개발자는 다른 사고 과정을 거칩니다. 미숙한 개발자는 구현(How)부터 생각하지만, 능숙한 개발자는 의도(What)부터 생각합니다. 우리는 이 "더 나은 전략"의 과정을 단계별로 보여줍니다.
Zehetmeier(2019)의 추상화 교육 연구 역시 "추상과 구체의 연결"을 강조합니다. 우리는 추상적 개념(What/How 분리)을 구체적 경험(커피 주문)에서 시작해 점진적으로 코드로 전이시킵니다. 중요한 건 결과가 아니라 과정입니다.
과학적 근거
30년 이상의 인지과학 연구가 이 교육 방법을 뒷받침합니다. Chi(1981)는 전문가가 표면이 아닌 깊은 구조(본질, What)로 문제를 범주화한다고 밝혔습니다. Wiedenbeck(1985)는 전문가가 Top-down으로 사고한다고 밝혔습니다. Prat(2020)는 프로그래밍이 언어 학습처럼 어휘(추상화 패턴)가 중요하다고 밝혔습니다.
이것은 "이렇게 하면 좋다"가 아니라 "과학이 증명한 추상화 사고법"입니다.
8. 예상 효과
이 교육을 마친 학습자는 구체적으로 다음과 같이 변합니다.
•
코드를 볼 때: "useEffect가 복잡해"라는 표면적 관찰에서, "데이터 페칭이 핵심이고 나머지는 부수효과"라는 본질 파악으로 전환됩니다. 문제의 깊은 구조를 인식하게 됩니다.
•
코드를 쓸 때: fetch() → res.json() → setProducts() 같은 세부 구현부터 고민하지 않고, const products = useProducts() 같은 이상적 인터페이스를 먼저 상상합니다. What과 How가 분리됩니다.
•
동료와 소통할 때: "이 부분 복잡해요"라는 막연한 불편함 대신, "List 패턴으로 분리하면 어떨까요"라는 구체적 해결책을 제시합니다. 공통 어휘로 소통합니다.
장기적으로는 이것이 단순한 코딩 기법을 넘어 사고방식의 전환으로 이어집니다.
초보자는 주어진 문제를 "어떻게 구현할까"라는 기술적 과제로 보지만, 전문가는 "무엇이 본질인가"라는 설계 과제로 봅니다. 우리 교육은 표면적 구현 능력이 아니라, 문제의 본질을 파악하고 올바른 추상화를 설계하는 근본적 능력을 키웁니다.
Brooks(1987)가 말한 소프트웨어의 본질적 복잡도를 다루려면, 바로 이런 추상화 사고 능력 자체를 기르는 과학적인 교육 방법론이 필수적입니다.







