저렴한 축(Cheap Axis)에 게이트를 설정하라
요약
에이전트가 구축한 코드베이스의 거버넌스 규칙 변화를 다룹니다. 비용이 낮고 오탐률이 낮은 기계적 체크(gate)는 실수가 발생하기 전이라도 선제적으로 구축해야 한다는 새로운 원칙을 제시합니다.
핵심 포인트
- 비용과 오탐률이 낮은 체크는 선제적으로 구축해야 함
- 비용이 높거나 오탐률이 높은 게이트는 실패 사례를 통해 검증 필요
- 규율(discipline)보다 기계적 체크(gate)가 더 확실한 가드레일 역할 수행
- 에이전트 기반 코드베이스 관리에서 결정론적 체크의 중요성
나의 지난 에세이에서는 모든 가드레일(guardrail)은 실패로부터 얻어야 한다고 말했다. 하지만 저렴하고 기계적인 체크(checks)의 경우, 그것은 잘못된 기본 설정이다. 무언가 고장 나기 전에 그것들을 구축해야 한다.
2026-06-22자로 작성된 거버넌스 문서(governance document)의 커밋 하나가 다음 규칙을 삭제했다:
클래스가 충분히 입증되었고 게이트가 저렴하며 오탐률(false-positive)이 낮을 때, 또는 첫 발생 사례가 파멸적일 때만 첫 번째 실패 이전에 게이트를 추가하라. 그렇지 않으면 실제 실수로 입증될 때까지 규율(discipline)에 의존하며, 그 후 실수가 테스트 피스처(test fixture)가 되어 게이트를 사후 대응적으로(reactively) 추가한다.
그리고 이를 다음 규칙으로 교체했다:
결정적인 축(axis)은 입증(attestation)이 아니라 비용과 오탐률(false-positive rate)이다. 변동 가능한 거버넌스 표면(governed surface)의 일관성 속성(consistency property)에 대해 저렴하고, 오탐률이 낮으며, 기계적으로 결정 가능한 체크(check)가 있다면, 입증된 실수가 발생하기 전에 선제적으로(proactively) 해당 게이트를 구축하라. 이러한 클래스의 체크를 대신하여 규율(discipline)을 사용하는 것은 허용되지 않는다.
이것은 단 하나의 디프(diff) 안에서 일어난 기본 설정의 반전(default-flip)이다. 이전 규칙은 대부분의 체크를 추가하기 전에 실패를 기다렸다. 새로운 규칙은 특정 클래스의 체크에 대해서는 기다리는 것 자체가 실수라고 말한다.
내가 이전 규칙을 작성한 당사자이기에, 이 어색함을 정면으로 마주해야 한다. 여기서 다루는 프로젝트는 에이전트가 구축한 코드베이스(agent-built codebase)로, 커밋 시 실행되며 명세(spec)와 어긋난 작업을 거부하는 100개 이상의 결정론적 체크 스크립트(이곳의 용어로는 게이트(gates))에 의해 개발이 관리된다. 몇 주 전, 나는 Gates Earned From Failure를 게시했다. 그 글의 논지는 이 모든 게이트가 사전에 설계된 것이 아니라, 구체적인 실수(miss)에 대응하여 추가되었다는 것이었으며, 가드레일(guardrail)이 그 존재 가치를 지닐 만큼의 무게를 갖는지 판단하기 위한 비용 테스트(cost test)를 제안했다. 후속 글인 Make It a Check는 동일한 핵심 논지를 더욱 날카롭게 다듬었다. 즉, 간직할 가치가 있는 교훈은 체크(check)의 형태로 존재해야 한다는 것이다. 왜냐하면 산문(prose)은 표류하지만, 게이트는 그렇지 않기 때문이다. 따라서 "입증된 실수가 발생하기 전에 선제적으로 게이트를 구축하라"는 커밋 메시지는 겉보기에는 이전의 논리를 뒤집는 것처럼 보일 수 있다.
하지만 뒤집는 것이 아니며, 이 둘을 화해시키는 것이 바로 핵심이다.
비용 테스트에는 항상 두 개의 축이 있었다
비용 테스트는 결코 "실패를 기다려라"는 것이 아니었다. 그것은 후보 게이트를 두 개의 축(axes)으로 측정했다. 하나는 게이트를 구축하고 유지하는 데 드는 비용이고, 다른 하나는 오탐률(false-positive rate, FP), 즉 실제로 문제가 없는 것을 얼마나 자주 지적하는가이다. "실제 실패로부터 얻어졌다"는 규칙은 이 축들에서 낮은 점수를 받는 게이트들을 위한 규칙이었다. 비용이 많이 들고, 까다로우며, 오탐률(FP)이 높은 게이트는 실질적인 유지 비용을 발생시킨다. 즉, 유지보수, 규칙 하나가 추가됨에 따른 읽기 부하, 오경보로 인한 마찰 등이 그것이다. 그 비용은 반드시 지불되어야 하며, 입증된 실수(attested miss)가 바로 그 비용을 지불하는 수단이 된다. 실패는 해당 게이트의 클래스가 실재함을 증명하며, 실패한 사례는 게이트의 첫 번째 테스트 픽스처(test fixture)가 된다.
반응형 프레임워크 (reactive framing)가 충분히 다루지 못했던 것은 매트릭스의 다른 한 축, 즉 저렴하고, 기계적으로 결정 가능하며(mechanically decidable), 거의 틀리지 않는 게이트였습니다. 그러한 게이트의 경우, 실패를 기다리는 것은 아무런 이득이 없습니다. 당신은 이미 그 검사가 정확하다는 것을 알고 있습니다. 또한 실행 비용이 거의 들지 않는다는 것도 이미 알고 있습니다. 실패가 하는 일이라고는 단지 예방 가능한 드리프트 (drift)가 먼저 통과하게 두어, 나중에 그것을 가리키며 "보세요, 이제 (게이트를 도입할) 자격이 생겼습니다"라고 말할 수 있게 할 뿐입니다. 그것은 수익이 없는 세금입니다.
따라서 반전(flip)은 좁고 정밀합니다. 결정적인 축은 비용과 허위 양성 (FP, False Positive)입니다. 후보 게이트를 먼저 클래스로 분류한 다음, 일치하는 규칙을 적용하십시오:
- 저렴하고, 낮은 FP를 가지며, 기계적으로 결정 가능하고, 통제된 표면 (governed surface) 위에 있는 경우 → 어떤 누락이 발생하기 전이라도 선제적으로 구축하십시오. 규율 (discipline)은 허용 가능한 대체재가 될 수 없습니다. 왜냐하면 이 프로젝트는 육안 감시 (by-eye vigilance)가 사소한 스크립트라면 잡아냈을 드리프트를 통과시킨다는 것을 반복적으로 증명했기 때문입니다.
- 비싸거나 FP가 더 높은 경우 → 반응형 규칙이 여전히 유효합니다. 관례는 실제 누락이 이를 입증할 때까지 규율과 한 줄의 작성된 규칙에 의존합니다. 그 후 누락이 픽스처 (fixture)가 되고 게이트가 도입됩니다.
- 첫 발생 시 치명적인 경우 → 별도의 탈출구 (escape hatch)입니다. 첫 발생이 용납될 수 없는 경우, 비용이 많이 들더라도 반드시 필요한 것은 어떤 누락이 발생하기 전이라도 도입될 수 있습니다.
이전 에세이는 처음 두 클래스를 하나의 기본값으로 통합했습니다. 이번 에세이는 이를 다시 분리하고, 저렴한 클래스에 대해서만 기본값을 뒤집습니다.
진심으로 실행할 때의 모습
기준을 낮추는 문서 수정은 작성하기 저렴하고 무시하기 쉽습니다. 반전이 실질적이었는지에 대한 테스트는 그 다음에 일어난 일입니다.
먼저 감사가 진행되었습니다. 이 과정은 기존의 모든 게이트(gate)의 결합 명세(coupling manifest) — 즉, 각 체크(check)가 어떤 파일들을 읽는지에 대한 선언 — 를 가져와서, 전체 집합을 _관리되는 표면(governed surface)_에서 _표류 축(drift axis)_으로의 맵(map)으로 반전시켰습니다. 프로젝트가 관리하는 각 파일에 대해, 어떤 방식으로 나머지 파일들과 조용히 불일치를 일으킬 수 있는지, 그리고 그 방식들 중 무엇을 감시하고 있는지 확인한 것입니다. 그런 다음, 게이트가 설정되지 않은 축(ungated axes)들을 훑으며 축당 하나의 질문을 던졌습니다: "이것이 실제로 문제가 발생하기 전에, 지금 게이트를 설정할 수 있을 만큼 충분히 저렴하고 기계적(mechanical)인가?"
다음 반복(iteration)에서는 해당 작업 목록을 바탕으로 네 가지 새로운 체크(check)를 출시했습니다. 하나는 명세(spec) 섹션의 열거형 멤버십(enum-membership) 주장과 그것이 참조하는 실제 열거형(enumeration)을 결합합니다. 하나는 단일 컴포넌트의 명세가 아키텍처 문서(architecture doc)에 의존하기 전에 얼마나 많은 컴포넌트 간 토폴로지(cross-component topology)를 끌어다 쓸 수 있는지 제한합니다. 하나는 각 워크플로(workflow) 단계의 진입을 이전 단계의 완료에 결합합니다. 정직하게 말하자면 네 번째는 마크다운 펜스(markdown-fence) 균형 체크인데, 이는 첫 번째 프로토타입 실행에서 실제 사례를 잡아냈으므로, 순수하게 선제적(proactive)이라기보다는 경계선에 있는, 절반 정도만 입증된(half-attested) 것이라고 할 수 있습니다. 나머지 세 개는 프로젝트 역사상 단 한 번도 발생하지 않았던 표류(drift)를 방어했습니다. 이전 규칙 하에서는 이 세 가지 중 어느 것도 존재하지 않았을 것입니다. 우리는 그것들이 허용된다는 것을 증명할 버그가 나타나기를 기다리고 있었을 것입니다.
이것이 바로 실현된 반전입니다. 저렴하고 기계적인 축(axes)들을 열거하는 감사를 수행하고, 흉터(scar)의 강도가 아니라 _저렴하고 기계적임_의 강도를 바탕으로 그 축들에 게이트를 설정하는 것입니다.
확산을 막는 조항
"모든 저렴하고 기계적인 축에 게이트를 설정하라"는 문장 자체는 위험합니다. 왜냐하면 작성하기 가장 저렴한 체크(check)들이 대개 가장 가치 없는 것들이기 때문입니다. 저렴하고 낮은 오탐률(low-FP)은 필요조건일 뿐, 충분조건은 아닙니다. 게이트는 반드시 실제 표류 축(drift axis)을 체크해야 하며, 결코 그것의 사소하게 참인 대리 지표(proxy)를 체크해서는 안 됩니다.
전형적인 나쁜 사례는 문서에 섹션 _제목(heading)_이 있는지 확인하는 것입니다. 이는 작성하기 매우 쉽고 거의 실패하지 않기 때문에, 두 가지 척도(비용과 낮은 허위 양성(FP)) 모두에서 저렴하고 효율적입니다. 하지만 이는 거의 쓸모가 없는데, 실제로 표류(drift)하는 것은 섹션의 _내용(content)_이지 제목의 존재 여부가 아니기 때문입니다. 제목 존재 여부를 확인하는 게이트는 제목 아래의 산문(prose)이 부패하고 있는 동안에도 '통과(green)'를 표시하며, 이로 인해 게이트가 없는 것보다 더 나쁜 상황이 발생합니다. 즉, 아무것도 커버되지 않았음에도
따라서 분업은 명확합니다. 기계가 기계적으로, 그리고 저렴하게 결정할 수 있는 모든 것은 커밋(commit) 시마다 매번 기계가 결정합니다. 인간에게 남는 것은 메커니즘 아래의 계층, 즉 의미(meaning)입니다. 이 프로젝트에서 문서가 시스템을 설명하는 것에서 벗어나 단순히 재진술(restating)하는 상태로 조용히 표류했는지에 대한 판단은, 의도적으로 각 반복(iteration)의 끝에 있는 인간 체크포인트(human checkpoint)로 넘깁니다. 왜냐하면 이러한 판단은 의미론적(semantic)이며 위양성(high-FP, False Positive) 비율이 높기 때문입니다. 기계적 축(mechanical axis)에 엄격하게 게이트(gate)를 설정하는 목적은, 해당 판단이 아닌 모든 것들로부터 인간의 업무를 비워내어, 희소한 주의력(attention)이 오직 주의력이 효과를 발휘할 수 있는 곳에 집중되도록 하는 것입니다.
규칙이 멈추라고 말하는 곳
규칙은 그것이 적용되지 않는 곳을 명시함으로써 신뢰를 얻습니다. 새로운 게이트를 분류한 것과 동일한 감사(audit)를 통해 게이트를 설정할 가치가 없다고 판단된 축들의 목록도 생성되었으며, 매 반복마다 재논쟁이 발생하지 않도록 기록되었습니다. 다섯 가지 항목은 다음과 같습니다:
- 헤딩(Heading)의 존재 여부: 진정으로 하중을 견디는(load-bearing) 필수 섹션의 작은 집합을 제외한 나머지. 위에서 언급한, 피해야 할 전형적인 사례로 명시된 사소하게 참인 대리 지표(trivially-true proxy).
- 게이트의 명세(manifest)가 실제 읽기 집합(read-set)과 일치하는지 여부: 체크가 실제로 어떤 파일을 읽는지 도출하는 것은 임의의 쉘(shell) 명령(glob, grep, 하드코딩된 경로 등)을 파싱해야 함을 의미합니다. 이는 저렴하지도 않고, 위양성(FP)이 낮지도 않습니다. 따라서 게이트를 설정하지 않은 채 남겨두었습니다.
- 문서 간의 자유 서술형 상호 참조(Free-prose cross-references): (예: "다른 파일에 있는 라우팅 섹션을 참조하세요"와 같은 유형). 구조화된 마크다운(markdown) 링크보다 위양성(FP)이 높습니다. 참조가 모호한 텍스트이기 때문에, 저렴한 방식(cheap version)을 사용할 경우 과도하게 플래그(flag)를 생성합니다.
- 상위 수준의 문서가 하위 수준의 메커니즘을 재진술하는 방향으로 표류했는지 여부, 그리고 워크플로우 기술(workflow skill)이 여전히 수명 주기 테이블(lifecycle table)에 충실한지 여부: 두 가지 모두 환원 불가능한 의미론적(semantic) 문제입니다. 게이트가 아닌 인간 체크포인트의 영역입니다.
- 아키텍처 다이어그램이 여전히 시스템의 실제 신뢰 경계(trust boundaries)를 반영하는지 여부: 다이어그램은 의도적으로 단순화되어 있으며, 수십 개의 그려진 엣지(edge)가 실제로는 약 100개의 권한 부여(permission grants)를 대신하고 있습니다. 따라서 어떤 기계적 일대일 대응(bijection)을 적용하더라도 과도하게 작동(over-fire)하게 됩니다. 이는 의미론적이면서 동시에 위양성(FP)이 높습니다. 따라서 인간의 영역으로 남겨둡니다.
그것들 각각은 시도하기에(to attempt) 저렴합니다. 하지만 모든 것이 제외되었습니다. 왜냐하면 '시도하기에 저렴함'은 기준이 아니기 때문입니다. 기준은 저렴하면서(cheap) 동시에 위양성(FP)이 낮고(low-FP), 실제 축(real axis)을 점검하는 것입니다. 이들은 두 번째 혹은 세 번째 조건에서 실패합니다. 레지스터(register)는 그것이 경계(edges)를 가지고 있음을 증명하는 규칙입니다.
선행 기술, 그리고 주장의 정직한 규모
결정론적 품질 검사(deterministic quality checks)를 그것들을 정당화할 버그가 발생하기 전, 즉 더 앞 단계로 옮기는 것은 새로운 아이디어가 아닙니다. 이러한 본능은 소프트웨어 이전부터 존재했습니다. 1960년대 도요타 생산 시스템(Toyota Production System)에 구축된 신고 시게오(Shigeo Shingo)의 포카요케(poka-yoke), 즉 실수 방지(mistake-proofing) 기법은 결함이 있는 제품을 출하 후에 잡아내는 대신, 애초에 오류가 발생할 수 없도록 프로세스를 재설계합니다. 테스트 분야에서는 2001년 _Dr. Dobb's Journal_에 게재된 래리 스미스(Larry Smith)의 _시프트 레프트 테스팅(shift-left testing)_을 따라, 소프트웨어 버전을 "시프트 레프트(shift left)"라고 부릅니다. 이는 품질 보증(QA)을 마지막에 덧붙이는 대신 라이프사이클의 시작 단계로 끌어오는 것을 의미합니다. [린터(Linters)](https://en.wikipedia.org/wiki/Lint_\(software
u)는 그보다 더 거슬러 올라가 1978년 벨 연구소(Bell Labs)의 스티븐 존슨(Stephen Johnson)이 만든 _린트(lint)_에 닿아 있습니다. 타입 시스템(type systems)과 지속적 통합(continuous-integration) 게이트는 모든 진지한 코드베이스에서 특정 결함이 발생하기 전, 선제적으로 구성됩니다. 이 중 어느 것도 제 아이디어가 아닙니다.
이 글이 기여하는 바는 어떤 검사가 선제적 처리를 받을 자격이 있는지에 대한 결정 규칙과, 이를 정직하게 유지해 주는 두 가지 조항입니다. 비용(Cost)과 위양성률(false-positive rate)은 선제적(proactive)인 것과 반응적(reactive)인 것을 구분하는 축이지, 흉터(scar)의 존재 여부가 아닙니다. 대리 제동 장치(proxy brake)는 "저렴한 것을 게이트(gate)하라"는 원칙이 "저렴하니까 가치 없는 것을 게이트하라"로 무너지는 것을 막아줍니다. 그리고 의미론적 잔여물(semantic-residue) 조항은 하한선을 설정합니다: 의미 아래에서 게이트를 설정하되, 의미 자체를 게이트하는 척하지 마십시오. 시프트 레프트가 검사를 더 앞 단계로 옮기라고 말한다면, 이 글은 어떤 검사를 옮겨야 하는지, 그리고 그 경계선이 어디인지를 말합니다.
두 가지 정직한 한계가 있습니다. 그 증거는 한 프로젝트의 거버넌스 계층 (governance layer)입니다. 이는 100개 이상의 게이트 (gates)를 거치며 유지되어 온 의사결정 규칙이며, 제가 수치로 제시할 수 있는 측정된 결과가 아닙니다. 그리고 이 규칙 전체는 '관리되는 표면 (governed surface)'을 전제로 합니다. 즉, 무엇이 "올바른지"에 대한 확정된 서면 개념이 있는 아티팩트 (artifacts)가 존재하여, 검사 (check)를 결합할 수 있는 안정적인 대상이 있어야 한다는 것입니다. 사양 (spec)이 발밑에서 여전히 움직이고 있는 탐색적 표면 (exploratory surface)에서는, 아직 게이트를 설정할 대상이 없습니다. 따라서 반응적인 기본값 (reactive default)이 다시 한번 옳습니다. 즉, 무언가가 불변량 (invariant)을 위반하기 전까지는 무엇이 불변량인지 진정으로 알 수 없습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기