////////
Search

연습 방법: Wishful Thinking + 일상 속에서 발견하기(분해 / 조립)

“Wishful Thinking”의 교육적 의도
SICP에서 반복적으로 등장하는 패턴이 있어요. 문제를 풀 때 “이런 함수가 있다면 좋겠다”라고 먼저 가정하고 그걸 사용해서 문제를 푸는 거예요. 그 다음에 그 가정한 함수를 실제로 구현하죠.
이건 추상화의 본질을 가르치는 거예요 - “어떻게(how)“를 먼저 생각하는 게 아니라 “무엇을(what)“이 필요한지를 먼저 생각하게 만드는 거죠. 추상화는 결국 what과 how의 분리니까요.
1. 희망사항을 주석으로 먼저 적는다 (구현 대신 의도 중심)
2. 주석을 조금 더 작은 의도로 나누어 적는다
3. 더 이상 반영할 의도가 없다고 느껴지면, 주석을 하나씩 구현으로 바꾼다.
구현 과정에서도 다시 1로 돌아가 구현 레벨에서의 희망을 먼저 적는다.(ex. 아, 이 훅은 이런 식으로 넘겨주고 받아 쓸 수 있으면 좋겠다)
일상속에서 추상화 발견하기 → 분해 / 결합
이걸 쓸 때 알아야 하기 때문에 불편한거
다 표준으로 통일되어 있어서 편한 거 → 뭘 꽃아도 상관 없다 = ex. USB-C, prop으로 React.ReactNode
SICP에서 Wishful Thinking은 정말 핵심적인 교육 철학이야. 자세히 풀어볼게.

SICP의 Wishful Thinking

핵심 아이디어

*"이런 함수가 있다면 문제를 쉽게 풀 수 있을 텐데"**라고 먼저 가정하고, 그 함수가 실제로 존재한다고 믿으며 문제를 푸는 거야. 그리고 나중에 그 함수를 실제로 구현하는 거지.

SICP 예시: 제곱근 구하기

전통적 접근 (Bottom-up):
; 1. 먼저 세부 구현부터 생각 (define (average x y) (/ (+ x y) 2)) (define (improve guess x) (average guess (/ x guess))) (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) ; 2. 그걸 조합해서 제곱근 만들기 (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
Scheme
복사
Wishful Thinking 접근 (Top-down):
; 1. 먼저 "이런 게 있으면 좋겠다" (define (sqrt x) (sqrt-iter 1.0 x)) ; "sqrt-iter가 있으면 좋겠다" ; 2. sqrt-iter를 사용하면서 "이런 게 필요하겠다" (define (sqrt-iter guess x) (if (good-enough? guess x) ; "good-enough?가 있으면 좋겠다" guess (sqrt-iter (improve guess x) x))) ; "improve가 있으면 좋겠다" ; 3. 이제서야 실제 구현 (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) (define (improve guess x) (average guess (/ x guess))) (define (average x y) (/ (+ x y) 2))
Scheme
복사

왜 이게 중요한가?

1. What과 How의 분리
; What: 제곱근을 구한다 (define (sqrt x) (sqrt-iter 1.0 x)) ; How: 반복적으로 추측을 개선한다 (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
Scheme
복사
먼저 "무엇을 하고 싶은가"를 명확히 하고, "어떻게"는 나중에 생각하는 거야.
2. 추상화 레벨 유지
; 높은 레벨: 제곱근은 반복적 개선이다 (sqrt-iter guess x) ; 중간 레벨: 개선은 평균을 사용한다 (improve guess x) ; 낮은 레벨: 평균은 더해서 나눈다 (average x y)
Scheme
복사
각 레벨에서 생각을 멈추고, 다음 레벨로 내려가지 않아도 되는 거야.
3. 복잡도 관리
; Bad: 모든 걸 한번에 생각 (define (sqrt x) (define (iter guess) (if (< (abs (- (* guess guess) x)) 0.001) guess (iter (/ (+ guess (/ x guess)) 2)))) (iter 1.0)) ; Good: 단계별로 생각 (define (sqrt x) (sqrt-iter 1.0 x)) ; 1단계: 이것만 생각 (define (sqrt-iter guess x) (if (good-enough? guess x) ; 2단계: 이것만 생각 guess (sqrt-iter (improve guess x) x)))
Scheme
복사

SICP의 실제 설명

SICP 1.1.7절에서 이렇게 말해:
"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."
(희망적 사고는 추상화를 구축하는 강력한 도구입니다. 실제로 대규모 시스템은 이렇게 설계됩니다. 무언가에 이름을 붙이고, 구현하기 전에 그것이 존재한다고 가정하고 사용법을 탐색하는 것입니다.)

프론트엔드로 번역하면?

전통적 접근:
// 1. 세부 구현부터 function validateEmail(email: string) { /* ... */ } function formatError(error: Error) { /* ... */ } function sendToAnalytics(data: any) { /* ... */ } // 2. 조합 function handleSubmit(data: FormData) { if (!validateEmail(data.email)) { const error = formatError(new Error('Invalid email')); sendToAnalytics({ error }); return; } // ... }
TypeScript
복사
Wishful Thinking 접근:
// 1. 먼저 "이상적인 형태" function SignupForm() { return ( <Form onSubmit={handleSignup}> {/* 이런 게 있으면 좋겠다 */} <EmailInput /> {/* 이런 게 있으면 좋겠다 */} <PasswordInput /> {/* 이런 게 있으면 좋겠다 */} <SubmitButton /> {/* 이런 게 있으면 좋겠다 */} </Form> ); } // 2. 이제 구현 function Form({ onSubmit, children }) { // Form의 책임만 구현 } function EmailInput() { // EmailInput의 책임만 구현 }
TypeScript
복사

HDD(Hope-Driven Development)와의 연결

문서에서 언급한 HDD가 바로 이거야:
// 1. 희망사항을 주석으로 function ProductList() { // 제품 목록을 보여준다 // 제품을 클릭하면 상세로 간다 // 빈 목록이면 empty 상태를 보여준다 } // 2. 더 작은 의도로 나눔 function ProductList() { // const products = 제품 목록을 가져온다 // const handleClick = 제품 클릭 시 상세로 이동한다 // products가 비었으면 EmptyState를 보여준다 // 아니면 ProductCard들을 보여준다 } // 3. 주석을 구현으로 function ProductList() { const products = useProducts(); // "이런 훅이 있으면 좋겠다" const handleClick = useProductNavigation(); // "이런 훅이 있으면 좋겠다" if (products.length === 0) { return <EmptyState />; // "이런 컴포넌트가 있으면 좋겠다" } return products.map(p => <ProductCard product={p} onClick={handleClick} /> ); }
TypeScript
복사

핵심 통찰

Wishful Thinking의 본질:
"어떻게 만들지"가 아니라 "이런 게 있으면 좋겠다"
구현이 아니라 인터페이스 중심 사고
Bottom-up이 아니라 Top-down 설계
What과 How의 분리
이게 바로 추상화의 핵심이야. 추상화는 "복잡한 걸 숨기는 게" 아니라 **"필요한 것을 먼저 상상하는 것"**이거든.
이제 2번 챕터에서 Wishful Thinking을 어떻게 가르칠지 감이 와?
일상으로부터 “해줘”를 단계적으로 빈칸채우기? 학습지? 느낌으로 해보다가 → 코드로 가는거임
차력쇼 하지 말고, 무조건 멈춰서서 “아, 귀찮아. 그래서 뭐 해달라는거지?” 라고 스스로 되뇌이기.
완전 핵심 질문이야! 이게 바로 교육 설계의 핵심이지.

문제: 초보자는 "희망"조차 상상 못함

왜?
어휘(vocabulary)가 없어: "Form", "Dialog" 같은 일반해를 몰라
판단 기준이 없어: 뭐가 "좋은" 인터페이스인지 몰라
경험이 없어: "이런 게 가능하다"는 걸 몰라

브릿지 1: 일상에서 이미 아는 것 → 코드로 전이

단계 1: 일상 속 Wishful Thinking 발견

"당신은 이미 Wishful Thinking을 하고 있습니다"
❌ 초보자의 커피 만들기: 1. 원두 위치 찾기 2. 필터 위치 찾기 3. 머신 온도 설정하기 4. 압력 조절하기 5. 추출하기 ✅ 당신의 실제 행동: "아메리카노 주세요"
Plain Text
복사
인식: "어? 나 이미 이렇게 하고 있었네?"

단계 2: 일상 → 코드 번역 공식

"복잡한 행동"을 "간단한 희망"으로 바꾸는 연습
일상
코드
"아메리카노 주세요"
cafe.order("americano")
"불 켜줘"
light.turnOn()
"10% 할인해줘"
price.discount(0.1)
패턴 발견:
세부사항 숨기고
동사 + 명사
"나는 몰라도 된다"

브릿지 2: 변환 공식 - "복잡함" → "희망"

공식 1: 단계가 많으면 → "한 번에 되면 좋겠다"

Before (복잡):
const res = await fetch('/api/products'); const data = await res.json(); setProducts(data); if (data.length === 0) navigate('/empty');
TypeScript
복사
질문: "이게 한 번에 되면 좋겠다"
Hope:
const products = useProducts(); // 이런 게 있으면 좋겠다 if (products.isEmpty) navigate('/empty');
TypeScript
복사

공식 2: 반복되면 → "자동으로 되면 좋겠다"

Before (반복):
<div> <ProductCard product={products[0]} /> <Separator /> <ProductCard product={products[1]} /> <Separator /> <ProductCard product={products[2]} /> </div>
TypeScript
복사
질문: "구분자를 자동으로 넣어주면 좋겠다"
Hope:
<SeparatedList items={products} separator={<Separator />}> {product => <ProductCard product={product} />} </SeparatedList>
TypeScript
복사

공식 3: 조건이 복잡하면 → "의도만 말하면 좋겠다"

Before (복잡):
if (user && user.role === 'admin' && user.permissions.includes('write')) { return <Editor />; }
TypeScript
복사
질문: "이 의도를 한마디로 말하면?"
Hope:
<PermissionGuard require="admin.write"> <Editor /> </PermissionGuard>
TypeScript
복사

브릿지 3: 패턴 라이브러리 먼저 보기

"이런 게 있을 수 있다"를 먼저 보여주기

일반해 갤러리

// 1. Form - 입력과 검증 <Form onSubmit={handleSubmit}> <Input name="email" /> <Button>제출</Button> </Form> // 2. Dialog - 모달 상호작용 <Dialog open={isOpen} onClose={handleClose}> <DialogTitle>확인</DialogTitle> <DialogContent>정말 삭제하시겠습니까?</DialogContent> </Dialog> // 3. List - 목록과 구분자 <SeparatedList items={data} separator={<Divider />}> {item => <Card item={item} />} </SeparatedList>
TypeScript
복사
학습 순서:
1.
"이런 게 있구나" (인지)
2.
"나도 써보자" (모방)
3.
"이렇게 만들 수 있구나" (이해)
4.
"이런 것도 만들 수 있겠다" (창조)

브릿지 4: 3단계 비교 템플릿

반복 학습 구조

템플릿

[1] Before: 복잡한 코드 → "뭐가 불편하지?" (1번 챕터에서 학습한 징후 감지) [2] Hope: 이런 게 있으면 좋겠다 → "이상적으로는?" (변환 공식 적용) [3] After: 실제 깔끔한 코드 → "실제로 만들면 이렇게" (구현)
Plain Text
복사

예시 1: 커피사일로

// [1] Before const beans = storage.warehouse.shelf3.beans; const filter = storage.drawer2.filters; machine.setTemperature(93); machine.setPressure(9); const espresso = machine.extract(beans, filter, 25); // "너무 많이 알아야 해" → 불편 // [2] Hope cafe.order("americano") // 이런 게 있으면 좋겠다! // [3] After export function order(menu: string) { const beans = storage.warehouse.shelf3.beans; const filter = storage.drawer2.filters; // ... (내부 구현 숨김) }
TypeScript
복사

예시 2: 제품 목록

// [1] Before useEffect(() => { fetch('/api/products') .then(res => res.json()) .then(data => { setProducts(data); if (data.length === 0) navigate('/empty'); }); }, [navigate]); // "얽혀있어" → 불편 (1번 챕터) // [2] Hope const products = useProducts(); // 이런 훅이 있으면 좋겠다 if (products.isEmpty) navigate('/empty'); // 이렇게 쓸 수 있으면 좋겠다 // [3] After (실제 구현) function useProducts() { const { data } = useQuery({ queryKey: ['products'], queryFn: fetchProducts }); return { data, isEmpty: data?.length === 0 }; }
TypeScript
복사

브릿지 5: 주석으로 연습 (HDD)

"희망을 코드로 바로 쓰기 어려우면 주석으로"
function SignupForm() { // 1단계: 주석으로 희망 적기 // 이메일을 입력받는다 // 비밀번호를 입력받는다 // 제출하면 회원가입한다 // 성공하면 홈으로 간다 // 2단계: 희망을 인터페이스로 // <EmailInput /> // <PasswordInput /> // <Form onSubmit={handleSignup}> // onSuccess → navigate('/') // 3단계: 실제 구현 return ( <Form onSubmit={handleSignup}> <EmailInput /> <PasswordInput /> <SubmitButton /> </Form> ); }
TypeScript
복사

학습 순서 정리

1. 일상 인식: "나 이미 이렇게 해" ↓ 2. 패턴 학습: "이런 게 있구나" ↓ 3. 변환 공식: "복잡한 거 → 희망" ↓ 4. 반복 연습: Before → Hope → After ↓ 5. 주석 연습: 희망을 주석으로 ↓ 6. 실전 적용: 내 코드에서
Plain Text
복사

핵심 인사이트

초보자에게 필요한 건:
1.
어휘 제공 (패턴 라이브러리)
2.
번역 공식 (복잡함 → 희망)
3.
반복 노출 (Before → Hope → After)
4.
점진적 연습 (주석 → 인터페이스 → 구현)
가장 중요한 건:
"이미 너는 하고 있어" (일상 비유)
"이런 게 있을 수 있어" (예시)
"따라해봐" (연습)
이렇게 하면 "희망"을 상상할 수 있는 스키마가 점진적으로 쌓일 거야.
어때? 이 브릿지들이 2번 챕터 구조에 들어갈 수 있을 것 같아?