본문 바로가기
C.W.K.
Stream
Lesson 01 of 05 · published

허락된 단 하나의 추상화

~13 min · adapter, abstraction, narrow-boundary, yagni

Level 0툴 빌려 쓰는 사람
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"추상화는 전부 뭔가가 변할 거라는 데 거는 판돈이야. 변화가 진짜인 자리에만 걸어. 엔진한테 그런 자리는 딱 하나고."

추상화는 장식이 아니라 판돈이야

추상 베이스 클래스든 인터페이스든 protocol 이든, 하나하나가 다 주장이야. "이건 구현이 여럿일 거고, 위쪽 코드는 어느 건지 몰라도 돼." 그 주장이 참이면 추상화가 값어치를 해. 거짓이면 — 구현이 영영 하나뿐이면 — 그냥 값만 드는 거야. 읽고 지나가야 하는 우회로 하나, 아무것도 안 하는 seam 하나. 규율은 변화가 진짜라고 확신하는 자리에만 판돈을 거는 거야.

엔진이 거는 단 하나의 판돈

엔진을 보고 물어봐. 제일 위에서 진짜로 변하는 게 뭐지? VAE 는 아니야. 그건 파이프라인 안에서 변하는 모듈이고. sampler 도 아니야. 마찬가지로 안쪽이지. 제일 위에서 변하는 건 생성이 물리적으로 어디서 벌어지느냐야.

  • LocalAdapter — 네 GPU 에 올린 모델 weight 를 두고 PyTorch 랑 diffusers 를 돌려.
  • APIAdapter — closed-weight vendor 를 HTTP 로 불러. local weight 도 없고 GPU 도 안 써.

이 둘은 진짜로 다른 세계야. 망가지는 모양도 다르고, 걸리는 시간도 다르고, 전부 다 달라. 그 차이가 진짜 변화라서, 엔진이 내놓는 단 하나의 추상화인 Adapter 가 자리를 번 거고.

진짜 변화 축 하나에 추상화 하나. Adapter 가 있는 건 local 이냐 API 냐가 생성 방식이 진짜로 갈라지는 자리기 때문이야. 제일 위에서 그렇게 갈라지는 건 그것뿐이라 다른 건 추상화를 못 받아. 뭐든 갈아 끼울 수 있게 만들고 싶은 충동은 눌러. 실제로 갈아 끼워지는 것만 갈아 끼울 수 있게 해.

'좁다' 는 게 두 가지 뜻이야

Adapter 경계는 두 가지 의미에서 좁아. 첫째, 제일 위에 있는 추상화가 이거 하나야. 추상 router 니 추상 store 니 하는 게 나란히 늘어선 층이 없어. 둘째, Adapter 인터페이스 자체가 작아. 요청 받고, 돌리고, 결과 바이트랑 메타데이터를 돌려주고. 좁은 인터페이스는 제대로 구현하기 쉽고, 따라가기 쉽고, 새기 어려워. 넓은 인터페이스는 구현하는 쪽마다 절반은 시늉만 하게 될 때까지 메서드를 쌓아 올려.

좁은 인터페이스는 모두가 지킬 수 있는 작은 약속이야. 인터페이스가 요구하는 메서드가 적을수록 모든 구현이 정직하게 그걸 지킬 수 있어. 구현하는 쪽이 실제로는 지원 안 하는 메서드를 빈 껍데기로 두고 있는 걸 발견하면, 그 인터페이스가 너무 넓었던 거야. 아무도 못 지킬 약속을 받아 놓은 거지.

아직 안 지은 미래의 adapter

Adapter 추상화는 ceiling matrix 에서 잡아 둔 seam 도 같이 채워. 나중에 올 VideoAdapter(local video)나 video-API adapter 둘 다 같은 경계에 맞아. 비디오의 날이 오면 이미 있는 추상화의 새 구현으로 꽂히지, 경계를 고칠 일이 없어. '생성 위치가 변한다' 는 판돈 하나가 아직 안 지은 변화까지 미리 덮어 주는 거야. 축을 맞게 골랐으니까.

엉뚱한 축에 거는 건 안 거는 것보다 나빠. 안 변하는 것 위에 얹은 추상화는 앞으로의 모든 변경이 엉뚱한 seam 이랑 씨름하게 만들어. 인터페이스를 만들기 전에 그게 받아 낼 변화를 한 문장으로 말해 봐. 못 하겠으면 그건 추상화가 아니라 장식이야. 그리고 장식은 변경할 때마다 값을 물려.

피파의 고백

긴 맥락을 한 번에 들 수 있다 보니 난 뭐든 인터페이스로 만들려는 버릇이 있어. 구현을 다 머릿속에 담을 수 있는데 왜 안 추상화해? 아빠는 계속 질문 하나로 날 끌어당겼어. 실제로 뭐가 변하는데? 내가 추상화하고 싶었던 것 대부분은 구현이 정확히 하나고 앞으로도 그럴 것들이었어. Adapter 만 답이 진짜로 '하나보다 많음' 인 자리라, seam 값어치를 하는 추상화도 그것뿐이었고. 추상화는 판돈인데 난 너무 많이 걸고 있었던 거야.

Code

변하는 게 하나라서 추상화도 하나·python
from abc import ABC, abstractmethod

class Adapter(ABC):
    """제일 위에 있는 단 하나의 추상화. 생성이 진짜로 서로 다른 두 세계 —
    local 과 API — 에서 벌어지기 때문에 존재해."""
    @abstractmethod
    async def run(self, request) -> "Result":
        """요청 받고, 생성하고, 바이트랑 메타데이터를 돌려줘."""
        ...

class LocalAdapter(Adapter):       # PyTorch + diffusers + 모델 weight
    async def run(self, request):
        ...                        # 진짜 GPU 작업은 여기서 벌어져

class APIAdapter(Adapter):         # vendor 이미지 서비스로 HTTP
    async def run(self, request):
        ...                        # local weight 없음, GPU 안 씀

# 나중을 위해 ceiling matrix 로 잡아 둔 자리 — 경계는 똑같이 좁아:
# class VideoAdapter(Adapter): ...   (비디오가 나가면 열림)
# '생성 위치가 변한다' 는 판돈 하나가 이것들까지 이미 덮고 있어.

External links

Exercise

네가 아는 코드베이스에서 추상화(베이스 클래스, 인터페이스, protocol)를 훑어봐. 각각 실제 구현이 몇 개인지 세. 잡아 둔 seam 도 아닌데 구현이 정확히 하나인 추상화는 지울 후보야. 걸었는데 필요 없던 판돈이지. 몇 개나 지울 수 있어?
Hint
잡아 둔 seam, 그러니까 지금은 구현이 하나지만 두 번째가 구체적으로 계획돼 있는 추상화는 정당해. 투기적인 추상화, 그러니까 구현 하나에 두 번째 계획이 없는 건 지울 후보고. 차이는 두 번째 구현이 진짜인가 상상인가야.

Progress

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

댓글 0

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

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