Search

0장_왜_추상화인가

0장. 왜 추상화인가

개발자로 일하다 보면 한 번쯤 이런 생각이 들어요.
“코드가 복잡해서 함수도 쪼개고, 파일도 나눴는데… 나는 추상화 한거 같은데 왜 코드가 여전히 복잡하지?”
처음에는 코드를 작게 만들면 될 줄 알았어요. 함수가 길면 나누고, 파일이 커지면 분리하고. 그런데 막상 해보면 오히려 더 복잡해지는 경험을 해요.
비슷한 기능을 추가할 때마다 여러 곳을 고쳐야 해요
한 곳을 고쳤는데 다른 곳이 깨져요
“이 코드 뭐 하는 거야?”에 한 문장으로 답하기 어려워요
새 요구사항이 들어오면 기존 코드를 크게 뜯어고쳐야 해요
아니면 혹시 코드 리뷰에서 이런 피드백을 받아본 적 있나요?
“이 부분 추상화가 부족한 것 같아요. 좀 더 정리해볼 수 있을까요?”
무슨 말인지는 알 것 같은데, 구체적으로 뭘 어떻게 해야 할지 막막해요. 클래스를 더 만들라는 걸까요? 인터페이스를 뽑으라는 걸까요? 아니면 함수를 더 일반적으로 만들라는 걸까요?
이 책은 바로 그 막막함에서 시작해요.
이 책에서 말하는 추상화:
추상화는 What(무엇을 하는가)과 How(어떻게 하는가)를 분리하는 것이에요.
함수를 쪼개고 파일을 나누는 건 기법이에요. 진짜 추상화는 “이 코드가 무엇을 하는지”와 “어떻게 하는지”를 분리하는 거예요. 1장에서 이 정의를 자세히 다뤄요. 지금은 “왜 이게 중요한지”부터 볼게요.

왜 추상화가 어려운가

현상: 중간 단계를 건너뜀

코드 추상화가 잘 안 되는 이유가 있어요.
기본적으로 코드를 마구 짜도 괜찮아요. 고객에게 가치를 전달하는 게 가장 중요하니까요. 문제는 그게 쌓였을 때예요. 복잡한 코드가 쌓이면 인지부하가 되고, 인지부하는 프로젝트 전체의 비용이 돼요. 결국 장기적으로 고객에게 가치를 전달하기가 힘들어져요. 그래서 추상화를 잘 해야 해요.
추상화는 이런 흐름으로 일어나요. 일단 코드를 작성해요. 구체적인 코드가 눈앞에 생기면, 그걸 보면서 “아, 이것들의 본질이 같네!”라는 구조가 보여요. 그 본질에 이름을 붙이면 추상화가 되는 거예요.
그런데 많은 개발자가 이 흐름의 중간 단계를 건너뛰어요. 두 가지 방식으로요.
첫째, 코드를 쓰고 나서 표면만 건드리는 경우. 코드를 작성한 다음에 바로 형식을 정리하는 단계로 넘어가요. 함수를 어떻게 나눌지, 클래스를 어떻게 설계할지, 어떤 패턴을 적용할지를 고민해요. 패턴을 발견하는 단계를 건너뛰고 형식에 집중하는 거예요.
둘째, 코드 없이 패턴을 먼저 정의하려는 경우. 코드를 쓰기도 전에 “어떤 클래스가 필요하고, 어떤 인터페이스를 뽑아야 하고”를 먼저 정해요. 구체적인 코드 없이 머릿속에서 구조를 그리려는 거예요.
두 경우 모두 같은 문제가 있어요. 실제 비용이 줄지 않아요. 추상화의 목적은 인지부하를 낮추는 건데, 첫째는 형식만 바꾸니까 비용이 그대로예요. 둘째는 구체가 없으니 비용이 어디서 오는지도 모른 채 구조를 만들어요.
왜 이렇게 될까요? “패턴을 발견하는 단계”에는 비용이 들기 때문이에요. 코드를 이리저리 들여다보고, 같은 구조를 찾아내고, 거기에 이름을 붙이는 건 에너지가 드는 일이에요. 반면에 이익은 나중에 생기고, 생길지 안 생길지도 불확실해요. 뇌 입장에서는 그 단계를 건너뛸 이유가 충분하죠.
그래서 형식만 바꾸는 일이 벌어져요. 함수를 쪼개고, 파일을 나누고, 디자인 패턴 이름을 붙여요. 그런데 여전히 복잡해요. 왜냐하면 패턴을 발견한 게 아니라 형식만 정리했기 때문이에요.
“코드 추상화”라는 단어를 보면, 자연스럽게 코드에 집중하게 돼요. 하지만 이건 표면만 보는 거예요.
“코드 추상화”의 구조를 뜯어보면 이래요:
[코드 [[추상] 화]] 코드 추상화 └── 코드 + 추상화 └── 추상 + 화(化)
Plain Text
복사
코드는 가장 바깥 레이어예요. 우리가 실제로 작성하는 것이에요. 추상화는 그 안에 있어요. 추상을 만드는 과정이에요. 추상은 가장 안쪽에 있어요. 인간이 가진 인지 능력이에요.
문제는 대부분 바깥(코드)만 보고 안쪽(추상)은 보지 않는다는 거예요.
함수를 쪼개고, 파일을 나누고, 패턴을 적용해도 여전히 복잡한 이유가 여기 있어요. 형식만 바꿨을 뿐, 안쪽의 “추상”이라는 인지 능력을 제대로 발휘하지 않았기 때문이에요.
여기까지 읽으면 “그러면 복잡할 때 What으로 올라가면 되겠네”라고 생각할 수 있어요. 맞는 말이에요. 그런데 문제는 실천이 안 된다는 거예요. 왜 그럴까요?

원리: 자원 합리성

“내일부터 운동해야지”, “일단 급한 불부터 끄자”, “나중에 정리할게”… 추상화도 마찬가지예요. 좋다는 건 알아요. 그런데 왜 안 할까요? 의지 부족일까요? 실력 부족일까요?
둘 다 아니에요. 뇌가 원래 이렇게 작동해요.
인지과학에서 자원 합리성(Resource Rationality)이라는 개념이 있어요.
우리 뇌는 에너지를 아끼려 해요. 생각하는 것 자체가 비용이에요. 그래서 뇌는 항상 이 계산을 해요:
“이 일을 하는 데 드는 비용이, 얻을 수 있는 이익보다 크면 안 해.”
아침에 일어나서 “오늘 뭐 입지?”를 깊게 고민 안 하는 것도 이거예요. 고민하는 비용 대비 이익이 작으니까요. 뇌가 의식하기도 전에 “대충 아무거나”를 선택해요.
문제는 추상화가 이 계산에서 불리한 구조를 가지고 있다는 거예요.
추상화의 비용
추상화의 이익
언제
지금
나중
확실성
확실함
불확실함
누가
내가 지불
나 또는 남이 받음
지금 당장, 확실하게, 내가 시간을 써야 해요. 반면 이익은? 언젠가, 아마도, 누군가에게.
추상화 하려면 당연히 머리도 아프고, 시간도 걸리고, 노력도 필요하다는 걸 알고 있어요. 그렇다면 이건 게으른 게 아니에요. 오히려 뇌가 정상적으로 작동하는 거예요.

비용 발생 3축

이 원리를 알면, 추상화가 어려운 현상들이 한꺼번에 이해돼요. 인지 비용이 발생하는 3가지 독립적인 축이 있어요.
질문
비용 원천
시간
언제의 이익인가?
미래 이익 추정의 불확실성
관점
누구의 관점인가?
타자 시뮬레이션 비용
자동화
자동화되었나?
System 2 에너지 소모
축 1: 시간 (현재 vs 미래)
“시간 할인”은 행동경제학 용어예요. 미래의 이익을 현재의 이익보다 낮게 평가하는 현상이에요.
“지금 5만원” vs “6개월 뒤 10만원”. 이성적으로는 6개월 뒤 10만원이 이득이에요. 그런데 많은 사람들이 지금 5만원을 선택해요. 미래의 10만원은 뭔가 흐릿하고, 지금의 5만원은 확실하니까요.
추상화도 마찬가지예요. “지금 30분 더 써서 깔끔하게” vs “일단 돌아가게 하고 나중에 정리”. 나중에 정리하면 2시간이 걸릴 수도 있어요. 그런데 그 2시간은 “나중”이고 “불확실”해요. 지금의 30분이 더 크게 느껴져요.
그래서 “일단 동작하게”가 기본 모드가 돼요. 일단 동작하는게 무엇보다도 제일 중요해요. 합리적이고 올바른 선택이에요. 다만 쌓이면 정리가 필요한 시점이 와요.
축 2: 관점 (자기 vs 타자)
인터페이스를 설계할 때 “호출자 입장에서 생각하라”고 해요. 그런데 이게 왜 어려울까요?
다른 사람의 관점을 취하는 건 뇌의 전두엽을 많이 쓰는 고비용 작업이에요. 내 관점은 공짜로 떠올라요. 다른 사람의 관점은? “이 사람은 뭘 알고, 뭘 모르고, 뭘 원할까?”를 적극적으로 시뮬레이션해야 해요.
바쁘거나 피곤하면 뇌가 이 비용을 안 써요. 자동으로 “내 관점”으로 돌아가요. 그래서 구현하는 사람 입장에서는 완벽한 인터페이스가, 쓰는 사람 입장에서는 난해해지는 거예요.
“지식의 저주”도 관점 축의 특수 케이스예요. 일단 무언가를 알면, 모르는 상태를 상상하기 어려워지는 현상이에요. 이건 “과거의 나(모르던 나)” 관점을 취하지 못하는 것이에요. 타자가 “과거의 자기”인 관점 전환 실패예요.
예를 들어볼게요. 친구에게 “강남역 가는 법”을 설명한다고 해봐요. 여러분은 강남역을 수백 번 가봤어요. “2호선 타고 강남역에서 내려”가 당연하죠. 그런데 서울 처음 온 친구한테는? “2호선이 뭐야? 어디서 타?”
코드에서도 똑같아요. 내가 짠 코드는 나한테 당연해요. 변수명 n이 뭔지, 이 함수가 왜 여기 있는지 다 알아요. “다른 사람이 볼 때 명확할까?”를 생각하려면 추가 비용이 들어요. 바쁘거나 피곤하면? 뇌가 그 비용을 안 지불해요. “나한테는 명확한데?”로 끝나요.
축 3: 자동화 (자동 vs 의식)
심리학에서는 사고를 두 가지로 나눠요.
System 1: 빠르고, 자동적이고, 에너지가 적게 들어요. 친구 얼굴 알아보기 같은 것.
System 2: 느리고, 의식적이고, 에너지가 많이 들어요. “17×24=?” 같은 것.
“일단 돌아가게 짜기”는 System 1으로 가능해요. 익숙한 패턴 따라가면 돼요. 이건 나쁜 게 아니에요. 고객에게 가치를 전달하는 가장 빠른 경로예요. 반면 “나중에 읽기 좋게 구조화하기”는 System 2가 필요해요. 의식적으로 “이 코드의 역할이 뭐지? 어떻게 나눌까?”를 생각해야 해요.
문제는 System 2를 쓰면 뇌가 피로해진다는 거예요. 하루 종일 코딩하고 나면, 복잡한 판단을 할 에너지가 없어요. 그래서 오후에 짠 코드가 아침에 짠 코드보다 구조가 안 좋은 경우가 많아요.

증거: 뇌가 이렇게 작동한다

위에서 설명한 자원 합리성은 이론이 아니에요. 실제로 뇌가 이렇게 작동해요.
인지과학 박스: 자원 합리성 (Resource Rationality)
“인지 시스템은 제한된 자원 하에서 작동하며, 비용이 기대 이익을 초과하면 그 작업을 수행하지 않는다.” — Griffiths et al. (2015)
위에서 본 3가지 축—시간, 관점, 자동화—은 모두 이 하나의 원리에서 파생돼요. 그리고 이 3축은 겹치지 않고(ME) 인지 비용의 주요 원천을 빠짐없이(CE) 커버해요.
중요한 건 이게 결함이 아니라 특성이라는 점이에요. 뇌가 에너지를 아끼는 건 생존에 유리한 전략이었어요. 다만 추상화처럼 “지금 비용, 나중 이익” 구조에서는 불리하게 작동할 뿐이에요.
인지과학 박스: 전문가와 초보자의 차이
전문가와 초보자의 가장 큰 차이는 “지식의 양”이 아니에요. 지식의 구조예요.
초보자는 개별 사실들을 따로따로 기억해요. “이 상황에서는 이렇게, 저 상황에서는 저렇게.” 전문가는 개별 사실들 뒤의 패턴을 봐요. “결국 이건 다 같은 원리야.” 이 패턴이 지름길이에요. 전문가는 해당 도메인에서 많은 지름길을 축적한 사람이에요.
코드 추상화를 직접 배우면, 개별 패턴(함수 추출, 인터페이스, 전략 패턴…)을 따로따로 익히게 돼요. 하지만 “추상”이라는 원리를 먼저 이해하면, 모든 패턴이 같은 원리의 변형임을 알게 돼요.
원리를 알면 응용할 수 있어요. 원리를 모르면 외워야(!) 해요.
인지과학 박스: 작업기억의 병목 → 지름길의 탄생
인간의 작업기억은 동시에 4±1개의 청크만 처리할 수 있어요.
코드를 작성하다 보면 변수명, 문법, 로직, 구조를 동시에 생각하게 돼요. 작업기억이 꽉 차서 “이게 뭘 하는 건지”를 생각할 여유가 없어요.
여기서 역설이 있어요. 이 제약 때문에 오히려 지름길이 생겨요. 작업기억이 무한하다면? 모든 걸 다 기억하면 돼요. 패턴을 찾을 필요가 없어요. 하지만 제한이 있으니까 압축해야 해요. 압축 = 패턴 발견 = What/How 분리. 지능이란 “자기 계산 능력에 맞는 추상화 수준을 찾는 것”이에요.
그래서 복잡함이 느껴지거나 “이게 뭘 구현하라는 거지?” 싶을 때, 잠깐 멈추고 What을 먼저 정리하면 도움이 돼요. What만 생각하는 동안은 How를 안 봐도 되니까, 작업기억이 터지지 않아요.

그래서 어떻게 해야 하나

자원 합리성을 이길 수는 없어요. 뇌의 작동 방식이니까요. 대신 구조를 바꿀 수 있어요.
핵심: 추상화는 인지 비용을 낮추는 기술이에요.

1. 비용을 낮추기: 체화

추상화를 연습해서 자동화하면, System 1으로 할 수 있게 돼요. 비용이 줄어들어요.
3장: 일상에서 연습하기 — 코드 없이 추상화 훈련
9장: 체화의 세 단계 — 한다 → 안다 → 본다

2. 이익을 당기기: 빠른 피드백

추상화의 이점을 빨리 체감하면, “나중”이 아니라 “지금”의 이익이 돼요.
각 장: 즉시 적용 가능한 예시 제공
4장: Inside-Out 방식으로 바로 효과 확인

3. 외부 장치: 관점 주입

코드 리뷰, 페어 프로그래밍으로 “다른 관점”을 강제로 주입해요.
5장: 호출자 관점에서 인터페이스 설계
이 책이 하는 일이 바로 1번과 2번이에요. 추상화를 연습 가능한 절차로 만들어서 비용을 낮추고, 작은 단위로 피드백을 받아서 이익을 빨리 체감하게 해요.

이 책 전체에서 이 원리가 반복돼요

앞으로 “왜 이게 어려운가”를 다룰 때마다, 이 원리로 돌아와요.
3장: 왜 세 번 반복해야 패턴이 보일까? → 뇌가 “패턴화하는 비용 < 개별 처리 비용”을 판단하려면 증거가 필요해요.
5장: 왜 호출자 관점에서 생각하기 어려울까? → 관점 전환 비용이에요.
6장: 왜 이런 함정에 빠질까? → 각 함정이 어떤 인지적 특성에서 오는지 연결돼요.
7장: 왜 언어/프레임워크를 넘어 추상화가 필요할까? → 기술 스택이 바뀌어도 비용 구조는 동일해요.
8장: 왜 추상화가 코드 밖에서도 작동할까? → 인지 비용을 낮추는 원리는 도메인 무관이에요.
9장: 왜 체화가 필요할까? → System 2 → System 1 전환으로 비용을 최소화해요.
이 원리를 알면 달라져요. “나는 왜 추상화를 못 할까”가 “아, 뇌가 원래 이렇게 작동하는구나”로 바뀌어요. 자책 대신 전략을 세울 수 있어요.

프론트엔드에서는 어떻게 나타나는가

지금까지 설명한 비용 구조(시간 축, 관점 축, 자동화 축)는 모든 개발자에게 적용돼요. 그런데 프론트엔드에서는 이 비용이 더 증폭되는 특수한 상황들이 있어요.

빠르게 변하는 요구사항 — 시간 축이 더 극단적

프론트엔드는 사용자와 직접 맞닿아 있어요. 사용자 피드백이 바로 요구사항 변경으로 이어지고, A/B 테스트 결과에 따라 UI가 수시로 바뀌어요. 어제 만든 컴포넌트가 오늘 완전히 다른 모습이 되기도 해요.
시간 축 관점에서 보면, 변화 주기가 짧아서 “나중에 얻을 이익”이 더 불확실해져요. 지금 추상화에 30분을 투자해도, 다음 주에 요구사항이 바뀌면 그 투자가 물거품이 될 수 있어요. 뇌는 이 불확실성을 감지하고 더 강하게 “일단 돌아가게”를 선택해요.
그래서 변화가 잦을수록, 오히려 변하는 것과 변하지 않는 것을 분리하는 능력이 더 중요해요.

다양한 상태의 조합 — 자동화 축이 더 과부하

프론트엔드 코드는 수많은 상태를 다뤄요. 로딩 중인지, 에러가 났는지, 데이터가 있는지, 사용자가 로그인했는지, 권한이 있는지… 이 상태들이 조합되면 경우의 수가 폭발적으로 늘어나요.
// 상태가 늘어날수록 조건문이 복잡해져요 if (isLoading) return <Spinner />; if (error) return <ErrorMessage error={error} />; if (!data) return <EmptyState />; if (!user) return <LoginPrompt />; if (!user.hasPermission) return <PermissionDenied />; return <Content data={data} />;
TypeScript
복사
자동화 축 관점에서 보면, 이 모든 상태 조합을 머릿속에 담고 있으려면 System 2 과부하가 걸려요. 작업기억이 꽉 차서 “이걸 어떻게 구조화하지?”를 생각할 여유가 없어요.
그래서 상태가 많을수록, 상태를 다루는 패턴이 더 필요해요.

UI와 로직의 얽힘 — 관점 축이 더 혼란

프론트엔드에서는 “보이는 것”과 “동작하는 것”이 한 곳에 섞이기 쉬워요.
function ProductCard({ product }) { const [quantity, setQuantity] = useState(1); const handleAddToCart = () => { // 비즈니스 로직 if (product.stock < quantity) { alert("재고가 부족합니다"); return; } const price = product.price * quantity; const discountedPrice = user.isVIP ? price * 0.9 : price; // API 호출 addToCart({ productId: product.id, quantity, price: discountedPrice }); // UI 업데이트 setQuantity(1); showToast("장바구니에 담았습니다"); }; return <div className="card">{/* UI 코드 */}</div>; }
TypeScript
복사
어디까지가 “이 컴포넌트의 책임”인지 불분명해요. 가격 계산 로직이 바뀌면? 재고 체크 방식이 바뀌면? 모두 이 컴포넌트를 수정해야 해요.
관점 축 관점에서 보면, “이 컴포넌트를 사용할 사람”의 입장을 시뮬레이션하기가 어려워요. 여러 관심사가 섞여 있어서, 호출자가 뭘 기대해야 하는지 불분명해지거든요.
그래서 관심사가 섞이기 쉬울수록, 명확하게 분리하는 기준이 더 필요해요.

정리

프론트엔드의 특수성은 3축 각각에서 비용을 증폭시켜요.
프론트엔드 특수성
증폭되는 축
결과
빠른 요구사항 변화
시간 축
“나중 이익”이 더 불확실
상태 조합 폭발
자동화 축
System 2 과부하
UI/로직 얽힘
관점 축
호출자 관점 시뮬레이션 어려움
이 책에서 다루는 추상화 원리는 프론트엔드에 특화된 것은 아니에요. 하지만 프론트엔드에서 이 비용이 더 심하게 나타나기 때문에, 모든 예제는 프론트엔드 맥락에서 진행해요.

이 책의 접근법

이 책은 안쪽(추상)부터 다뤄요.
제목
내용
1장
추상이란
가장 안쪽. What과 How가 분리된 상태.
2장
추상화란
중간. 추상을 만드는 과정. 환원과 재구성.
3장
일상에서 연습하기
코드 없이 추상/추상화 수련.
4장
코드 추상화
추상을 코드에 적용. 구조(레이어, 협력, 축척).
5장
인터페이스
호출자 관점에서 What을 드러내는 설계.
6장
사례와 함정
실무 패턴과 피해야 할 것.
7장
심화 사례
언어 초월 추상화, 플랫폼 흡수.
8장
더 잘 살기
커리어, 학습, 의사결정에 적용.
9장
메타인지
한다 → 안다 → 본다. 0장으로 귀환.
부록
원칙들의 통합
10가지 부록 (원칙, 카탈로그, 신호 사전 등).
왜 이 순서일까요? 코드 없이도 추상/추상화를 연습할 수 있기 때문이에요.
사실 추상은 코드에만 쓰이는 게 아니에요. 알람 시계를 볼 때, 레스토랑에서 주문할 때, 길을 설명할 때 — 우리는 이미 추상을 사용하고 있어요. 다만 의식하지 않을 뿐이죠.
이 책에서는 먼저 추상이라는 상태(What과 How의 분리)가 무엇인지 정의해요. 그리고 그 상태를 만들어내는 과정(추상화)을 배워요. 일상에서 연습한 다음, 마지막에 코드라는 도메인에 적용해요.
추상화는 인간 본질적인 능력이자 지혜예요. 1637년 데카르트는 이렇게 썼어요. “문제를 풀고 싶다면, 먼저 그것이 풀렸다고 가정하라.” 고대 그리스 수학자 파푸스로부터 영향 받은 이 사고방식은 수학자 폴리아의 ’문제 해결 휴리스틱’으로, 다시 SICP의 ’Wishful Thinking’으로 이어졌어요. 우리가 배우게 될 코드 추상화는 단지 인간에게 내재된 오래된 지혜를 코드에 적용하는 것일 뿐이에요.

이 책의 목적

이 책의 목적은 명확해요.
“추상화해”라는 피드백을 받았을 때, 구체적으로 무엇을 해야 하는지 알게 되는 것.
이를 위해 이 책은 세 가지를 제공해요.
첫째, 추상화가 무엇인지 이해하기. 추상화는 막연한 개념이 아니에요. “복잡한 걸 단순하게”도 아니고, “공통점을 뽑아내는 것”도 완전한 설명이 아니에요. 이 책에서는 추상을 ‘What과 How의 분리’로 정의해요. 이 정의가 왜 유용한지, 그리고 실제 코드에서 어떻게 적용되는지 차근차근 설명해요.
둘째, 추상화하는 방법 익히기. 이해하는 것과 할 수 있는 것은 달라요. 이 책은 추상화를 연습 가능한 절차로 만들어요. 클린(환원 → 재구성 → 검증)과 저크(구조 전이) 방식을 다뤄요.
처음에는 이 절차를 의식적으로 따라가야 해요. 마치 운전을 처음 배울 때 순서를 외우듯이요. 하지만 반복하면 자연스러워져요.
셋째, 추상화를 체화하기. 궁극적인 목표는 “추상화를 의식하지 않고도 자연스럽게 하는 것”이에요. 숙련된 개발자가 코드를 볼 때 “이건 분리해야겠다”는 감각이 바로 드는 것처럼, 추상화도 감각이 될 수 있어요. 이 책은 그 과정을 세 단계로 설명해요: 의식적 절차 → 패턴 인식 → 자동화된 지각.

이 책을 읽고 나면

이 책을 다 읽고 나면, 적어도 이런 변화가 있을 거예요.
“추상화 해주세요”라는 피드백에 구체적인 다음 단계를 떠올릴 수 있어요.
코드가 복잡하게 느껴질 때, “세부사항”과 “본질”을 분리해볼 수 있어요.
새로운 패턴을 만났을 때, 같은 원리의 변형임을 알아차릴 수 있어요.
추상화는 재능이 아니에요. 연습으로 익힐 수 있는 기술이에요.
이제 시작해요.
1장에서는 추상이 무엇인지 정의해요.