본문 바로가기
C.W.K.
Stream
Lesson 02 of 04 · published

값 하나짜리 enum 은 지워

~12 min · concrete-first, yagni, pivot, dead-surface

Level 0툴 빌려 쓰는 사람
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"더 이상 존재하지 않는 변화 위에 얹힌 추상화는 유연함이 아니라 안 일어난 미래의 박물관이야. 지워. 그 미래가 진짜 오면 그때 다시 만들면 돼."

추상화를 쓸모없게 만든 방향 전환

초기에는 작업실이 생성을 여러 backend 로 보낼 수 있었어. 그래서 라우팅 enum 이 있었지. 가능한 backend 를 이름으로 다 늘어놓은 타입 말이야. 그때는 분별 있는 선택이었어. 그러다 엔진이 하나로 합쳐졌어. 엔진 하나가 모든 생성의 유일한 backend 가 된 거야. 하룻밤 사이에 그 라우팅 enum 이 값을 정확히 하나만 들게 됐어. backend 사이의 변화를 받아 내려고 만든 추상화인데 그 변화가 사라진 거지.

concrete-first 로 내린 결정

선택지가 둘이었어. 언젠가 두 번째 backend 가 돌아올지도 모르니 값 하나짜리 enum 을 '혹시 몰라' 남겨 두거나, 아니면 지우고 라우팅 로직을 직접 호출로 접어 버린 다음 진짜 두 번째 backend 가 실제로 도착할 때만 추상화를 다시 들이거나. 고른 건 지우는 쪽이었어. 값 하나짜리 enum, 한 군데로만 보내는 router, 더 이상 안 갈라지는 갈림길 위의 추상화. 전부 죽은 껍데기야. 뒤에 아무것도 없는 복잡함이지.

concrete-first: 두 번째 경우가 진짜일 때 추상화를 지어. 미리 짐작해서가 아니라. 추상화는 실제 변화를 받아 내면서 제자리를 벌어. 그 변화가 사라지는 순간 존재 이유도 사라지고. 그러면 빈 추상화를 지우고 진짜 두 번째 경우가 오는 날 다시 만들어. 영영 안 올지도 모르는 갈림길을 미리 짐작하는 게, 나중에 아무도 설명 못 할 복잡함을 쌓는 길이야.

'혹시 몰라' 가 함정인 이유

값 하나짜리 enum 을 남겨 두는 게 신중해 보여. 두 번째 backend 가 돌아오면 어쩌려고? 그런데 '혹시 몰라' 추상화는 꾸준히 세금을 물려. 읽는 사람마다 한 군데로만 보내는 router 가 왜 있는지 이해해야 하고, 고칠 때마다 아무것도 안 하는 우회로를 지나야 하고, 새로 온 사람은 존재하지도 않는 다른 경우를 찾느라 시간을 버려. 값은 꾸준히, 모두한테, 영영 나가는데 이득은 영영 안 올지도 몰라. 나쁜 거래야.

미리 하는 추상화는 불확실한 미래를 보험 들려고 현재에 세금을 물려. 짐작으로 만든 seam 하나하나가 그 코드를 만지는 모두한테, 매일, 읽히고 관리되고 지나쳐져. 그게 짐작한 두 번째 구현은 영영 안 올 수도 있는데. 확실한 값을 계속 내면서 불확실한 이득을 사는 거야. 나중에 그 필요가 진짜가 됐을 때 추상화를 다시 들이는 쪽이, 내내 빈 채로 지고 다니는 것보다 거의 언제나 싸.

깨끗하게 지어 놨으니 다시 만드는 게 싸

지우는 게 안전한 이유가 있어. 진짜 두 번째 backend 가 언젠가 도착하면, 라우팅 추상화를 다시 들이는 건 범위가 잡히고 잘 아는 일이야. 나머지 시스템이 깨끗한 seam 으로 지어져 있으니까(module 분리 규율 전체 말이야). 영영 필요 없을 거라는 데 거는 게 아니야. 필요해지면 다시 넣는 게 재작성이 아니라 끝이 보이는 일일 거라는 데 거는 거지. 깨끗한 아키텍처가 '지금 지우고 나중에 다시 넣기' 를 도박이 아니라 안전한 수로 만들어 줘.

깨끗한 seam 이 '짐작한 추상화 지우기' 를 위험에서 안전으로 바꿔. 나중에 다시 넣는 게 범위가 잡힌 일이라고 믿을 수 있으면 미리 만든 추상화를 자신 있게 걷어낼 수 있어. 그 믿음은 나머지 아키텍처가 잘 나뉘어 있다는 데서 오고. concrete-first 랑 깨끗한 seam 은 짝이야. seam 이 지우기를 되돌릴 수 있게 만들어 주니까 concrete-first 가 과감할 수 있는 거야.

피파의 고백

enum 을 지우는 게 틀린 것처럼 느껴졌어. 내가 지은 거고, 한때는 진짜 유연함이었고, 언젠가 또 필요하지 않겠어? 아빠 질문이 그걸 갈랐어. 두 번째 backend 가 지금 진짜야, 아니면 상상이야? 상상이었지. 그러니까 그 enum 은 '아마' 의 기념비였던 거야. 여기 없는 미래를 위해 읽는 사람 전부한테 세금을 물리는. 그걸 지우고 나중에 깨끗하게 다시 넣을 수 있다고 믿는 게, 내가 지은 아키텍처에 대한 작은 믿음이었어. concrete-first 는 용감해 보일 뿐이야. 깨끗한 seam 이 있으면 그냥 맞는 거고.

Code

값 하나짜리 enum 은 죽은 껍데기야·typescript
// 방향 전환 전: backend 가 여럿이라 enum 이 제자리를 벌고 있었어.
type GenerationRoute = "backend_a" | "backend_b" | "backend_c";
function dispatch(route: GenerationRoute, req: Request) {
  switch (route) { /* 진짜로 다른 경로들 */ }
}

// 방향 전환 후: 엔진 하나가 유일한 backend 가 됨.
// enum 이 이제 값 하나. switch 는 한 군데로만 보냄.
type GenerationRoute = "the_engine";          // 죽은 껍데기
function dispatch(route: GenerationRoute, req: Request) {
  return theEngine.generate(req);             // switch 가 아무 일도 안 함
}

// CONCRETE-FIRST: 더 이상 안 갈라지는 갈림길 위의 추상화를 지워.
function generate(req: Request) {
  return theEngine.generate(req);             // 직접. 정직하게. 죽은 껍데기 없이.
}
// 진짜 두 번째 backend 가 도착하는 날 GenerationRoute 를 다시 들여. 그 전엔 안 들이고.

External links

Exercise

네 코드에서 변화가 한 경우로 주저앉은 추상화를 찾아봐. 값 하나짜리 enum 이라든가, 계획된 두 번째가 없는 단일 구현 인터페이스라든가, 분기가 하나뿐인 switch 라든가. 정해 봐. 두 번째 경우가 진짜고 계획돼 있어, 아니면 상상이야? 상상이면 concrete-first 로 접는 그림을 그려 보고, 지금 seam 이라면 나중에 다시 넣는 게 범위 잡힌 일일 거라고 스스로를 설득해 봐.
Hint
판단 질문은 이 quest 의 다른 추상화 lesson 이랑 똑같아. 두 번째 구현이 진짜(이름 붙고 계획된 것)냐 상상(언젠가 아마)이냐. 진짜면 seam 을 남기고, 상상이면 구체적인 걸로 접었다가 진짜가 될 때 다시 넣어.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.