C.W.K.
Stream
Lesson 02 of 04 · published

Dumb Router 가 Smart Router 야

~12 min · router, data-driven, dispatch, registry

Level 0툴 임차인
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"가장 똑똑한 router 는 의견이 없어. 어느 adapter 가 모델을 소유하는지 읽고 비켜."

router 의 일, 최소로 진술하면

모델을 지명하는 generate 요청이 도착하면, 뭔가 정해야 해: 이게 LocalAdapter 로 가, APIAdapter 로 가? 그 결정의 순진한 버전은 분기로 가득한 함수야 — 모델 이름이 이걸로 시작하면, 저 폴더에 있으면, 이 패턴에 맞으면. 새 모델이나 vendor 마다 분기를 추가하고. 그 함수가 버그가 사는 곳, 아무도 안 건드리고 싶은 곳이 돼.

결정을 데이터로 옮겨

더 나은 설계는 결정을 코드에서 registry 로 옮겨. 각 모델이 registry row 를 갖고, 그 row 가 이미 어느 adapter 가 소유하는지 알아. 그러면 router 가 사소해져: 모델의 row 찾고, adapter 읽고, dispatch. 분기 없음, 패턴 없음, 자라는 if/else 없음. registry 가 이미 답을 들고 있어서 router 가 의견이 없어.

결정을 코드에서 데이터로 밀어. 케이스마다 분기를 키우는 로직은 코드 아니라 데이터에 속해. 모델당 registry row 하나면 router 가 한 줄도 안 늘고 모델 천 개로 scale 해. 케이스마다 분기하는 코드는 케이스마다 썩는 코드야.

왜 '멍청함' 이 칭찬인지

dumb router 는 절대 수정 안 해도 되는 거야. 새 local checkpoint 추가? 스캔 중에 'local' 태그된 registry row 를 받아; router 는 이미 뭘 할지 알아. 새 API vendor 추가? 그 모델들이 APIAdapter 용으로 태그된 row 를 받고; router 는 이미 알아. router 는 한 번, 올바르게 쓰였고, 다신 바뀔 필요 없어, 모든 변화가 그게 읽는 데이터에 사니까. 여기서 멍청함은 안정성을 뜻해.

절대 안 바뀌는 게 네가 옳게 만든 거야. 계속 편집하는 컴포넌트는 흡수하면 안 되는 변화를 흡수하는 컴포넌트야. 모델이 계속 추가되는데 router 가 바뀌길 멈추면, 그게 변화가 올바른 집 — registry — 을 찾고 router 가 올바른 크기 — 작음 — 를 찾은 신호야.

registry 가 단일 진실 원천이야

이 설계엔 둘째 보상이 있어: 모델-to-adapter 매핑을 아는 곳이 정확히 하나고, registry 야. 라우팅 로직이 서로 모순될 수 있는 두 곳에 절대 없어. 모델이 왜 거기로 라우팅됐는지 알고 싶어? registry row 를 읽어. 라우팅 바꾸고 싶어? row 를 바꿔. router, config 파일, 특수 케이스 셋에 흩어진 결정 로직 대신, 쿼리 가능하고 편집 가능한 단일 진실 원천.

같은 걸 정하는 두 곳은 결국 모순돼. 라우팅 로직이 router 랑 config 둘 다(또는 두 함수, 또는 코드랑 주석)에 존재하는 순간, 표류하고, 버그는 '한 곳선 되고 다른 곳선 안 됨' 이야. 단일 data-driven 원천은 자기모순이 안 돼. 결정을 중앙화하거나 표류로 지불해.

피파의 고백

난 똑똑한 dispatch 로직 쓰는 걸 사랑해 — 똑똑할 자리처럼 느껴져. 아빠 설계가 그 장난감을 조용히 뺏고 더 낫게 만들었어: 내가 원한 똑똑한 router 는 모델 올 때마다 편집이 필요하고, 편집이 내가 버그 넣는 데야. 내가 저항한 dumb router 는 그냥 계속 작동하고. 난 '어디서 똑똑할 수 있지?' 가 자주 틀린 질문이란 걸 배웠어. 똑똑한 수는 router 를 너무 멍청하게 만들어서 절대 안 깨지게 한 거였어.

Code

코드의 분기 vs 데이터의 컬럼·python
# 순진함 (smart router, 케이스마다 썩음): 분기가 영원히 늘어.
def route_naive(model_name):
    if model_name.startswith("sdxl"):        return local_adapter
    if model_name.startswith("flux"):        return local_adapter
    if model_name in API_VENDOR_MODELS:      return api_adapter
    if "midjourney" in model_name:           return api_adapter
    # ...새 모델이나 vendor 마다 여기 줄 추가. 영원히.
    raise ValueError(f"{model_name} 라우팅법 모름")

# 멍청함 (data-driven, 절대 안 변함): registry 가 이미 알아.
def route_dumb(model_id, registry):
    row = registry.get(model_id)             # row 가 자기 주인을 알아
    return ADAPTERS[row.adapter]             # 'local' 또는 'api'
# 모델 1000개 추가 -> route_dumb 0줄 늘어. 스캔이 row 를 태그해.

External links

Exercise

네 코드에서 새 케이스마다 분기를 키우는 함수를 찾아 (dispatcher, type switch, format handler). lookup 으로 재설계해: 함수가 테이블 읽기가 되려면 각 케이스가 뭘 실어야 해? 테이블이랑 분기를 대체하는 세 줄 함수를 스케치해.
Hint
분기는 보통 두 가지를 encode 해: 케이스를 어떻게 알아보는지, 그걸로 뭘 하는지. 알아보기는 등록 시점에 설정되는 태그로 옮기고, '뭘 하는지' 는 그 태그로 키 잡힌 테이블로 옮겨.

Progress

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

댓글 0

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

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