버그는 핸드셰이크에 있다
요약
대부분의 시스템 버그는 개별 컴포넌트가 아닌, 서비스(Service), 큐(Queue), 워커(Worker) 간의 경계(Seam)에서 발생합니다. 이 글은 각 구성 요소가 서로에게 기대하는 책임과 동작 방식에 대한 명확한 '핸드셰이크' 정의의 중요성을 강조합니다. 시스템 설계 시 이러한 인터페이스와 소유권자를 문서화해야 합니다.
핵심 포인트
- 버그는 코드 내부보다 컴포넌트 간의 경계(Seam)에서 발생한다.
- 각 구성 요소가 기대하는 책임과 동작을 명확히 정의해야 한다.
- 단순한 견고성 추가만으로는 부족하며, 인터페이스 소유권자 지정이 핵심이다.
- AI 에이전트 시대에는 핸드셰이크 문서화가 더욱 중요해진다.
대부분의 버그는 코드 안에 있지 않습니다. 그것들은 박스들 사이의 경계에 있습니다.
모든 함수를 읽어봐도 아무것도 잘못된 것을 찾을 수 있습니다. 서비스(Service)는 괜찮습니다. 큐(Queue)도 괜찮습니다. 워커(Worker)도 괜찮습니다. 버그는 두 부분이 누가 무엇을 할지에 대해 조용히 의견이 불일치하는, 그 이음매에 존재합니다.
제가 한 번 이상 목격한 사례가 있습니다.
한 매장이 주문을 받았습니다. 서비스는 주문을 데이터베이스(Database)에 기록하고, "영수증 전송" 작업을 큐에 넣은 다음, 고객에게 확인 메시지를 반환했습니다. 워커가 이 작업을 가져와서 이메일 제공업체(email provider)를 호출합니다. 세 개의 박스, 두 번의 인계 과정, 모든 것이 검토되었습니다. 그러다 어느 날 밤, 이메일 제공업체가 시간 초과(timeout)를 일으킵니다. 워커는 전송 도중에 충돌합니다. 고객은 영수증을 받지 못하고, 월요일에 지원 티켓이 도착할 때까지 아무도 모릅니다.
서비스 코드를 읽어보면 올바릅니다. 작업을 큐에 넣었고, 큐가 재전송(redeliver)해야 하는 것이 맞습니다. 큐를 읽어봐도 올바릅니다. 워커가 작업을 가져가는 순간 완료로 표시되도록 설정되었기 때문입니다. 이것이 기본값이기 때문입니다. 워커 코드를 읽어도 올바릅니다. 충돌하면 큐가 작업을 다시 전달해 줄 것이라고 가정했기 때문입니다. 모든 박스는 통과했습니다. 하지만 영수증은 여전히 사라진 상태입니다.
누가 재시도(retry)를 담당하는지 아무도 기록하지 않았습니다. 서비스는 큐가 담당한다고 생각했고, 큐는 워커가 담당한다고 생각했으며, 워커 역시 큐가 담당한다고 생각했습니다. 세 가지 자신감 넘치는 답변이 나왔지만, 주인은 아무도 없었습니다.
모든 시스템은 같은 일곱 개의 블록으로 구축되며, 그 시스템 자체는 이들 사이의 인계 과정입니다. 서비스가 외부 서비스(External Service)를 호출할 때: 시간 초과는 누가 책임지나요? 워커가 서비스가 방금 작성한 행을 읽을 때: 그것이 아직 거기에 있을 것이라고 누가 보장하나요? 큐가 작업을 워커에게 전달할 때: 재시도는 누가 담당하며, 몇 번까지인가요? 박스들은 읽기 쉽습니다. 질문들이 존재하는 곳은 이음매이며, 대부분의 질문들은 입 밖에 나오지 않습니다.
이것은 지금보다 덜 중요해진 것이 아니라, 더 중요한 문제입니다. AI 코딩 에이전트가 각 박스를 완벽한 자신감으로 작성합니다. 그것은 깨끗한 서비스, 깨끗한 워커, 깨끗한 큐 클라이언트를 구축할 것이며, 그들 사이의 핸드셰이크(handshake)는 보지 못할 것입니다. 왜냐하면 그 핸드셰이크가 프롬프트에 포함된 적이 없었기 때문입니다.
흔히 하는 잘못된 접근 방식은 '이것을 더 견고하게 만들어 달라'고 요청하는 것입니다. 그러면 실제로 그렇게 합니다. Service에 재시도(retry)를 추가하고 Worker에도 재시도를 추가하며, 이제 영수증(receipt)이 세 번 나갑니다. 견고한 상자들(robust boxes)이 견고한 시스템을 만드는 것은 아닙니다. 모든 이음매(seam)마다 명확한 소유권자(owner)가 있는 것이 그렇게 만듭니다.
그러니 구축하기 전에, 그 이음매들을 문서로 작성하세요. 각각 한 줄씩입니다. 누가 재시도를 책임지는지. 누가 클럭(clock)을 책임지는지. 각 측면이 상대방에게 어떤 보증을 기대하는지를요. 그 목록은 짧고 지루하며, 코드 리뷰가 찾아낼 수 없는 버그를 발견해 주는 것은 바로 이 검토 과정입니다.
Course 0에서는 이 목록이 에이전트(agent)가 코드를 한 줄 쓰기 전에 가장 먼저 작성하는 것이며, 그것이 구축하는 계획은 대부분 핸드셰이크(handshakes)의 목록입니다.
당신은 상자들을 검토하는 것이 아닙니다. 당신은 핸드셰이크를 검토합니다.
Kay
P.S. 네 단계와 그 배경 지식을 갖춘 플랜-퍼스트 루프(plan-first loop)는 여기에 작성되어 있습니다: https://systemthinkinglab.ai/learn/plan-first-loop/
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기