AI 설계 발표자료 25장을 만들었다. 공감은 반년 뒤에 왔는데 그때 내 하네스는 이미 낡아 있었다
AI 설계 발표자료 25장을 만들었다. 공감은 반년 뒤에 왔는데 그때 내 하네스는 이미 낡아 있었다
지금 하던 업무를 처음부터 다시 개발해야 했다. Rust로 코어를 두고 그 위에 Node와 Electron을 얹고 화면은 React로 그리는, 언어 세 개가 프로세스 하나 안에서 겹치는 데스크톱 앱이었다. 나는 이걸 AI로 밀어붙이면 된다고 생각했다. 바로 직전 프로젝트에서 같은 방식으로 결제까지 붙은 기능을 실제로 완성했으니까.
그래서 그 방식을 그대로 가져왔다. 문서를 먼저 깔고, AI 여러 개를 붙이고, 설계 범위를 크게 잡고 시작했다. 초반은 예상대로였다. 빠르고, 그럴듯하고, 컴파일도 통과하고, 화면도 떴다.
그리고 두 달쯤 뒤에 적용을 중단했다.
실패한 건 프로젝트가 아니라 방법론이었다. 앞에서 통했던 그 방식이 여기서는 안 통했다. 왜 안 통했는지를 나 자신한테 먼저 설명해야 했고, 그다음엔 팀한테 설명해야 했다. 그 설명이 1월에 슬라이드 25장이 됐고, 3월에 다시 14장짜리 가이드 문서로 정리됐다. 표지에 이렇게 적어놨더라. "AI 활용이 아니라, 설계 중심 사고가 어떻게 작동했는가."
그 자료를 들고 다니면서 사람들한테 얘기했다. 반응은 거의 없었다. 없었다기보다는, 있었는데 방향이 달랐다. "그래서 AI를 쓰지 말자는 거냐"거나 "우리 규모에선 그렇게까지 안 해도 된다"거나, 제일 자주 들은 건 "문서 쓸 시간에 코드를 짜는 게 낫지 않냐"였다.
반년이 지났다. 지금 커뮤니티에 도는 얘기가 그때 내가 하던 말과 거의 같다. 하네스가 자산이라는 얘기, 모델보다 그걸 감싸는 구조가 중요하다는 얘기, AI는 설계를 대신해주지 않는다는 얘기.
반가울 줄 알았는데 안 반갑다. 씁쓸하다. 그런데 왜 씁쓸한지가 처음엔 나도 정리가 안 됐다. 내가 맞았는데 인정을 못 받아서인가 싶었는데, 그건 아니었다. 그거였으면 지금 같은 말이 도는 걸 보고 통쾌했어야 맞다. 이 글은 그 씁쓸함을 분해해본 기록이다.
그때 자료에 적었던 말
25장을 압축하면 문장 하나로 줄어든다. AI는 설계를 줄여주지 않는다. 우리가 설계를 건너뛰고 있을 뿐이다.
그 아래에 원칙을 다섯 개 박아뒀다. AI는 설계자가 아니라 구현 도구라는 것. 설계 문서가 없으면 코드 생성을 시작하지 않는다는 것. 구조를 바꾸려면 문서를 먼저 바꾼다는 것. 같은 설계 정보는 문서 한 곳에만 존재한다는 것. 그리고 AI가 짠 코드의 설계 책임은 커밋한 사람에게 있다는 것.
지금 읽어도 반박할 데가 없다. 그게 문제였다.
반박할 데가 없는 말은 설득력이 없다. "설계가 중요하다"는 명제에 반대하는 개발자는 없다. 사람들이 반대한 건 명제가 아니라 비용이었다. AI로 30분이면 나올 것 같은 걸 앞에 문서 네 종을 깔고 시작하자는 제안은, 그 문서가 없어서 두 달을 태워본 적이 없는 사람한테는 그냥 절차 늘리기로 들린다.
나도 그 두 달을 태우기 전엔 같은 편이었다.
80%까지는 진짜 잘 된다
바이브 코딩이 안 된다는 얘기가 아니다. 이건 정확하게 짚고 가야 한다. 슬라이드 2장에 이렇게 적었다. "바이브 코딩은 처음 80%까지는 진짜 잘 된다."
요구사항 몇 줄 던지면 그럴듯한 코드가 나오고, 컴파일이 통과하고, 화면이 뜨고, 기본 동작이 된다. 피드백 루프가 짧으니까 체감 속도가 폭발적이다. 이 구간에서 느끼는 생산성은 착시가 아니라 진짜다. 실제로 빠르다.
문제는 남은 20%다. 그리고 그 20%는 앞의 80%와 성질이 다르다.
수정 단계에 들어가면 이런 순서로 진행된다. 이슈가 하나 뜬다. 프롬프트를 바꿔본다. 안 풀린다. 다르게 물어본다. 여전히 안 풀린다. 이 지점에서 AI가 원인을 지목하는데, 그게 틀렸다. 그런데 굉장히 확신에 차서 말한다. 그 확신에 끌려서 그쪽으로 몇 시간을 판다. 아니었다. 돌아온다. 다른 방향으로 시도한다. 같은 패턴이 반복된다. 그러다 한 곳을 고치면 다른 데가 깨진다. 비슷한 코드가 여기저기 쌓이기 시작한다.
이걸 나는 세 번 겪었다.
처음은 사내 시스템 하나를 리팩토링하는 일이었다. 시작 프롬프트가 "코드 재설계 해줘"였다. 지금 보면 이 여섯 글자가 실패 원인 전부다. 범위가 무제한이고, 무엇을 향해 재설계하라는 기준이 없다. AI는 매번 자기가 생각하는 "더 나은 구조"를 새로 만들어냈다. 어제의 판단과 오늘의 판단이 달라도 둘 다 나름 타당했다. 기준이 없으니 틀렸다고 말할 근거도 없었다. 결과는 그럴듯한데 진행 속도가 점점 느려지는 상태였고, 원인은 AI가 아니라 설계 기준점이 없다는 것이었다.
그다음은 그걸 반성해서 문서를 먼저 깔고 시작한 판이었다. 이번엔 docs 디렉터리를 만들고 구조를 적었다. 그런데도 같은 일이 벌어졌다. 버그가 하나 나올 때마다 AI가 큰 구조 변경을 제안했다. 유틸 함수와 훅이 여기저기 중복 생성됐다. 나중에 세어보니 같은 일을 하는 함수가 세 곳에 따로 있었다.
여기서 배운 게 이 자료에서 제일 중요한 문장이 됐다. 문서를 만들었다는 것과 설계를 했다는 것은 다르다. 내가 만든 건 구조 설명서였지 판단 기준이 아니었다. "이 모듈은 사용자 설정을 관리한다"는 설명은 AI가 새 유틸을 하나 더 만드는 걸 막지 못한다. 막으려면 "이 모듈은 저장소를 직접 호출하지 않는다"처럼 위반 여부를 판정할 수 있는 문장이어야 한다. 설명문과 판정문은 다르다. 나는 설명문만 잔뜩 써놓고 설계를 했다고 생각했다.
마지막 판은 성공했다. AI를 여러 개 붙이고, 같은 문서를 참조시키고, 서로 다른 관점의 답을 받아서 내가 교차 검증했다. 결제까지 포함해서 기능이 실제로 완성됐다. AI가 내 의도를 훨씬 정확하게 반영하기 시작했다.
그런데 이게 제일 위험한 성공이었다. 병목이 설계자 한 사람의 도메인 이해에 있었기 때문이다. 문서가 좋아서 된 게 아니라 내가 그 도메인을 잘 알아서 AI의 헛소리를 그때그때 걸러낸 거였다. 다른 사람이 같은 문서를 들고 같은 방식으로 하면 같은 결과가 안 나온다. 재현이 안 되는 성공은 방법론이 아니라 개인기다.
그걸 모르고 다음 판에 그대로 들어갔다.
각 레이어의 판단은 전부 옳았다
이번 건은 복잡도가 한 단계 위였다. 화면은 React로 그리고, 렌더러와 메인 프로세스 사이엔 프리로드와 IPC 채널이 있고, 메인은 Node이고, 거기서 FFI로 Rust 코어를 부른다. 여기에 윈도우와 맥 두 플랫폼 차이가 얹힌다. 경계를 세어보면 여섯 개다.
증상은 항상 UI에서 먼저 보였다. 그런데 원인은 UI에 없었다.
AI에게 문제를 던지면 각 레이어에서 아주 합리적인 답을 준다. React 쪽을 물으면 상태 관리 관점에서 타당한 답을 준다. IPC 쪽을 물으면 메시지 스키마 관점에서 타당한 답을 준다. Rust 쪽을 물으면 타입 경계 관점에서 타당한 답을 준다. 하나하나 다 맞는 말이다.
문제는 그 여섯 개의 타당한 판단을 하나로 묶는 설계가 없다는 거였다. 어느 한 레이어의 오류가 아니었다. 레이어를 넘어가면서 전제가 조용히 변형되는 게 문제였다. 렌더러에서 확정된 전제가 IPC 메시지로 직렬화되면서 하나 빠지고, 메인에서 다시 해석되면서 하나 추가되고, FFI 경계에서 타입이 변환되면서 의미가 미묘하게 달라진다. 각 구간에서는 아무도 잘못하지 않았는데 끝에서 값이 틀려 있다.
AI 검증은 여기서 무력하다. 정확히 말하면 무력한 게 아니라 겉보기 일관성만 보장한다. 타입이 맞고, 함수 시그니처가 맞고, 호출 순서가 그럴듯하면 통과시킨다. 다중 언어 시스템에서는 그 표면 일관성이 진짜 정합성과 자주 어긋난다. 그리고 얕은 설계 위에서는 구현이 진행될수록 모순이 누적된다. 초반엔 안 보이다가 후반에 한꺼번에 터진다.
그래서 슬라이드 12장에 이렇게 적었다. "AI의 한계가 아니라, 내가 인지한 설계 깊이가 부족했다."
이 문장을 적는 데 시간이 좀 걸렸다. AI 탓으로 돌리는 게 훨씬 편했으니까. 모델이 아직 부족하다고 쓰면 다음 버전을 기다리면 되는데, 내 설계 깊이가 부족했다고 쓰면 다음 버전이 나와도 안 풀린다는 뜻이 된다.
실제로 안 풀렸다. 그 사이에 모델은 두 번 올라갔다.
판정할 수 있는 문장만 남겼다
그래서 문서를 다시 썼다. 이번엔 설명문을 빼고 판정문만 남겼다.
이번에 문서 맨 앞에 놓은 건 불변식이었다. 코드 어디에서나 항상 참이어야 하는 조건. 이걸 어기면 버그가 아니라 설계 붕괴로 본다. 전역, 모듈, 인터페이스 세 계층으로 나누고 번호를 붙였다. 전역은 INV-G, Electron 메인은 INV-E, 렌더러는 INV-R, Rust 코어는 INV-RS로 접두어를 나눴다.
예를 들면 이런 것들이다.
- 데이터 흐름은 UI에서 앱, 도메인, 인프라 방향으로만 흐른다. 역방향 참조 금지.
- 코어 크레이트에는 바인딩 의존성이 들어가지 않는다.
napi::나wasm_bindgen임포트가 보이면 위반. - 코어 함수는
Vec<u8>을 반환한다.Buffer나Uint8Array는 어댑터에서만 변환한다. - 렌더러는 저장소를 직접 호출하지 않는다.
여기서 중요한 건 문장의 내용이 아니라 형태다. 전부 위반 여부를 기계나 사람이 판정할 수 있는 형태로 쓰여 있다. "코어를 순수하게 유지한다"가 아니라 "코어에 napi 임포트가 있으면 위반"이다. 앞 문장은 AI에게 아무 제약도 걸지 못하고, 뒷 문장은 grep 한 줄이면 검사된다.
불변식 옆에 하나 더 붙인 게 결정 기록이다. 구조를 바꿀 때마다 한 페이지짜리 문서를 남긴다. 어떤 상황이었고, 뭘 골랐고, 어떤 대안을 왜 버렸는지. 마지막 항목이 핵심인데, 대안과 기각 이유가 없으면 그건 기록이 아니라 통보다.
이게 왜 필요한지는 AI를 여러 개 붙여보면 바로 안다. 같은 문서를 물려줘도 각자 다른 답을 낸다. 처음엔 이게 오류인 줄 알고 어느 쪽이 맞는지 가리려고 했다. 그게 아니었다. 답이 갈리는 자리가 곧 문서에 빈틈이 있는 자리다. 문서가 그 지점을 결정해두지 않았으니 각자 자기 판단으로 메운 거다. 그래서 지금은 답이 갈리면 누가 맞는지 따지는 대신 그 자리를 결정 기록으로 못 박는다. 기각된 대안까지 같이 적어두면 석 달 뒤에 다른 AI가 같은 제안을 다시 들고 왔을 때 "이미 버린 안"이라고 답할 근거가 생긴다. 이걸 안 적어두면 같은 논쟁을 분기마다 다시 한다.
실제로 검사 스크립트도 붙였다. 코어 순수성, 바이트 타입 경계, 이벤트 경계 세 가지를 CI에서 돌리고 위반이면 머지를 막는다. 여기까지는 완전 자동화가 됐다.
그런데 전체 레이어를 놓고 보면 자동화 비율이 생각보다 처참했다.
| 레이어 | 검증 대상 | 자동화 수준 |
|---|---|---|
| Rust 코어 | 바인딩 의존성, 바이트 타입, 이벤트 경계 | 완전 자동화, 머지 차단 |
| TypeScript 공통 | 순환 의존성, import 방향 | 부분 자동화, 린트 규칙 |
| Electron 메인 | IPC 채널 규칙, 서비스 경계 | 수동, PR 체크리스트 |
| 렌더러 | 레이어 규칙, 상태 관리 패턴 | 수동, 코드 리뷰 |
| 레이어 간 계약 | IPC 스키마 정합성, FFI 타입 계약 | 미구현 |
제일 중요한 마지막 줄이 미구현이다. 앞에서 실패한 원인이 바로 레이어 간 전제 변형이었는데, 그 층이 지금도 자동 검증이 없다. 나머지는 다 잡아놓고 정작 나를 두 달 태운 자리만 못 잡았다.
이게 그 자료의 진짜 결론이다. 체계를 만들었다는 자랑이 아니라, 만들고 나서 자동화 가능한 영역과 아닌 영역의 경계를 봤더니 내가 다친 자리가 여전히 밖에 있더라는 것.
자동으로 못 잡는 구간은 대신 경보를 걸어뒀다. 코드에서 이런 게 보이면 손을 멈추고 문서부터 다시 본다는 목록이다. 같은 일을 하는 유틸이 두 곳 이상에서 따로 정의되고 있을 때. 모듈끼리 직접 참조하는 횟수가 늘어날 때. 구조를 바꾸는 PR이 한 달에 세 번을 넘길 때. 버그가 날 때마다 AI가 구조 변경을 제안할 때. 그리고 문서에 적힌 것과 실제 동작이 어긋나는 걸 발견했을 때.
마지막 항목이 제일 위험하다. 문서와 코드가 어긋나면 대개 문서를 고치는데, 그러면 문서가 기준선이 아니라 코드의 사후 요약으로 강등된다. 요약본은 아무것도 막지 못한다. 그래서 이 경우엔 순서를 뒤집기로 했다. 문서를 기준선으로 다시 선언하고 코드를 문서에 맞춘다. 물론 실제로는 문서 쪽이 틀렸을 때도 있으니 매번 그렇게 하진 못한다. 다만 어느 쪽을 고칠지를 그때그때 편한 대로 정하지 않고 한 번 결정 기록을 거치게 만들어두면, 문서가 슬금슬금 요약본으로 내려가는 건 막힌다.
원리를 파는 대신 감싸는 쪽을 골랐다
여기까지 오는 동안 나는 한 번 갈림길에서 선택을 했다.
한쪽은 LLM 자체를 공부하는 길이다. 어텐션이 어떻게 도는지, 토크나이저가 무엇을 자르는지, 샘플링 파라미터가 출력 분포를 어떻게 바꾸는지. 원리를 알면 더 잘 쓸 수 있을 거라는 기대가 있는 길이다.
다른 한쪽은 모델을 상수로 두고 그걸 감싸는 구조를 짜는 길이다. 어떤 문서를 항상 물려주고, 어떤 순서로 일을 시키고, 어디에 게이트를 걸고, 무엇을 자동으로 검사하고, 언제 멈추게 할지. 요즘 하네스 엔지니어링이라고 부르는 쪽이다.
나는 후자를 골랐다. 이유는 고상하지 않다. 전자를 파봤는데 내 문제가 안 풀렸기 때문이다.
어텐션 구조를 이해한다고 해서 IPC 경계에서 전제가 변형되는 게 잡히지 않는다. 샘플링 온도를 알아도 AI가 유틸 함수를 세 곳에 중복 생성하는 걸 막지 못한다. 내가 겪은 실패는 모델 내부의 문제가 아니라 모델을 둘러싼 절차의 공백에서 나왔고, 공백은 절차로만 메워진다.
원리 공부가 쓸모없다는 얘기는 아니다. 컨텍스트 윈도우가 왜 뒤로 갈수록 흐려지는지 알면 긴 세션을 어디서 끊을지 감이 잡히고, 토크나이저를 알면 왜 한글이 영어보다 토큰을 더 먹는지 계산이 된다. 다만 그건 도구를 아끼는 요령이지 내 프로젝트가 무너진 이유에 대한 답은 아니었다. 답이 있을 것 같은 쪽이 아니라 내 문제가 실제로 있는 쪽을 파야 했다.
이 감각을 나중에 다른 사람 글에서도 확인했다. Addy Osmani가 Own the Outer Loop에서 정리한 구도가 딱 이거였다. 에이전트는 이미 안쪽 루프를 돈다. 조사하고, 구현하고, 테스트하고, 보고한다. 사람이 소유해야 하는 건 그 바깥의 루프, 즉 이 일이 할 가치가 있는지 판단하고 결과의 증거를 검증하고 승인하거나 막는 층이다. Anthropic이 효과적인 에이전트 설계에서 강조한 것도 결이 비슷하다. 화려한 프레임워크보다 단순하고 검증 가능한 구성 요소를 조립하라는 쪽.
나는 이 구분을 나중에 내가 짠 건 하네스가 아니라 아웃터 루프였다에서 한 번 더 정리했는데, 그때는 이미 개인 블로그 레포에 오케스트레이터와 발행 게이트와 세션 훅을 반년 넘게 짜놓은 뒤였다. 이름을 모르고 짜고 있었던 셈이다.
그런데 하네스는 썩는다
여기서부터가 그때 자료에 없던 내용이다. 그리고 지금 씁쓸함의 절반이 여기서 나온다.
하네스를 짜고 반년쯤 돌려보니 이상한 게 보였다. 모델 버전이 올라갈 때마다 하네스의 일부가 무효화된다.
몇 가지 예를 들어보겠다.
내 블로그 레포에는 한동안 발행 게이트가 있었다. 문체 검사 결과 파일에서 "판정: 합격"이라는 문자열을 grep해서, 없으면 발행 스크립트를 막는 구조였다. 그럴듯해 보였다. 그런데 어느 날 깨달았다. 그 문자열을 쓰는 게 검사받는 에이전트 본인이었다. 검문소와 통행증 발급처가 같았다. 이건 모델이 나빠서가 아니라 모델이 좋아져서 생긴 문제다. 예전 모델은 형식을 자주 어겨서 통과 자체가 어려웠는데, 지시를 잘 따르게 되니까 항상 합격을 찍었다. 게이트가 성능 향상 때문에 무력해졌다. 결국 제거했다.
다른 예도 있다. 벤치마크 1위와 2위 차이가 실제 태스크 개수로 0.36개밖에 안 된다는 걸 계산해보다가, 내 하네스에 두 달 반 동안 죽어 있던 게이트가 있다는 걸 발견했다. 모델을 갈아탈지 고민하던 시간 내내 내가 켜뒀다고 믿은 검사는 안 돌고 있었다. 시크릿 스캔을 걸어뒀는데 가짜 AWS 키 여섯 개가 전부 그냥 통과한 적도 있다. 걸어둔 것과 도는 것은 다르다.
이 사례들에서 나오는 결론은 이렇다. 하네스는 한 번 짜서 쌓아두는 자산이 아니다. 모델 쪽 지형이 바뀌면 같이 갱신해야 하는 소모품에 가깝다. 프롬프트 템플릿, 스킬 라우팅, 검증 게이트, 컨텍스트 주입 방식은 전부 지금 모델의 약점을 전제로 설계된다. 그 약점이 사라지면 그걸 막던 장치는 쓸모없어지거나, 더 나쁘게는 쓸모없어진 채 켜져 있는 것처럼 보인다.
이걸 반감기라고 부르기로 했다. 내 감각으로는 모델 메이저 버전 하나마다 하네스의 20~30% 정도가 다시 손을 봐야 하는 상태가 된다. 정확한 수치는 아니고 내가 갈아엎은 파일 수를 눈으로 센 감이다.
반감기가 다른 두 가지를 섞어 쓰고 있었다
그런데 여기서 재미있는 게 나온다. 전부 썩는 건 아니다.
"코어 크레이트에 napi 임포트 금지"는 모델이 몇 번 올라가든 안 바뀐다. 이건 우리 아키텍처의 성질이지 모델의 성질이 아니기 때문이다. "데이터 흐름은 한 방향" 같은 것도 마찬가지다. Rust와 Node 사이 바이트 타입을 어디서 변환할지도 그렇다.
반대로 "구현 완료 후 AI에게 불변식 위반 여부를 스스로 검토하게 시킨다" 같은 항목은 모델 의존적이다. 자기 검토 능력이 모델마다 다르고, 어느 시점부터는 이 지시가 형식적인 통과 도장으로 변한다. 위의 발행 게이트가 정확히 그 경로로 죽었다.
그래서 지금은 문서를 쓸 때 두 종류를 물리적으로 분리한다.
오래 가는 것은 아키텍처 사실이다. 레이어 경계, 의존성 방향, 타입 계약, 도메인 규칙. 이건 사람이 결정했고 모델과 무관하게 참이다. 여기에 투자한 시간은 감가상각이 느리다.
빨리 낡는 것은 모델을 다루는 요령이다. 프롬프트 형식, 컨텍스트를 얼마나 넣을지, 어떤 검사를 모델에게 맡길지, 어떤 지시를 반복해야 지켜지는지. 여기에 투자한 시간은 반년이면 절반이 사라진다.
빨리 낡는 쪽에 시간을 쓰는 게 낭비라는 얘기가 아니다. 지금 당장의 생산성은 거기서 나온다. 다만 그걸 자산이라고 착각하면 안 된다는 것뿐이다. 계획 문서를 정교하게 쓰는 습관에 대해서도 계획서대로 짰으면 그 버그는 그대로 나갔다에서 비슷한 얘기를 한 적이 있는데, 정교한 절차가 정확한 판단을 대신해주지는 않는다.
그리고 이 구분이 아까 그 발표자료를 다시 읽게 만들었다. 25장 중에서 지금도 유효한 부분과 이미 낡은 부분이 갈린다. 원칙 다섯 개와 불변식 체계는 그대로 살아 있다. 반면 "AI에게 이렇게 물어라" 쪽 프롬프트 템플릿은 절반쯤 손을 봐야 한다. 내가 그때 제일 공들여 쓴 게 후자였다.
왜 그때는 안 통했나
이제 씁쓸함의 정체로 돌아간다.
처음엔 "내가 6개월 앞섰는데 아무도 몰라줬다"는 서운함이라고 생각했다. 그런데 그렇게 정리하니까 뭔가 안 맞았다. 내가 앞섰다는 감각 자체가 좀 이상했기 때문이다. 나는 남들보다 똑똑해서 먼저 안 게 아니다. 밥 먹는 시간 빼고 하루 열여덟 시간씩 AI를 붙들고 있었으니까 먼저 깨진 것뿐이다.
이게 실은 전부다. 나는 6개월 앞선 게 아니라, 같은 시간 동안 표본을 더 많이 뽑았다.
표본을 많이 뽑으면 무슨 일이 생기냐면, 남들이 아직 한 번도 못 본 실패 유형을 여러 번 보게 된다. 하루에 스무 번 시키는 사람과 두 번 시키는 사람이 있으면, 열 번에 한 번 나오는 붕괴 패턴을 앞사람은 매일 두 번 보고 뒷사람은 닷새에 한 번 본다. 그러면 앞사람은 그걸 "이 도구의 성질"로 인식하고 뒷사람은 "어쩌다 한 번 이상했던 일"로 기억한다. 같은 현상을 보고도 한쪽은 법칙을 만들고 한쪽은 예외로 처리한다.
여기까지는 그냥 노출량 차이다. 문제는 그다음이다. 노출량으로 얻은 지식에는 근거를 붙일 수가 없다. 논문도 벤치마크도 아니고 "제가 많이 해봤는데요"밖에 없다. 그런데 이 판에서는 많이 해본 사람이 넘쳐난다. 다들 자기가 많이 해봤다고 말한다. 그러니 노출량은 신뢰의 근거가 못 된다.
그리고 솔직히 말하면 그 시간 자체가 자랑거리도 아니다. 열여덟 시간을 붙들고 있었다는 건 그만큼 비효율적으로 헤맸다는 뜻이기도 하다. 나는 그 시간에 뭘 알아낸 게 아니라 그 시간을 쓰고 나서야 알아낸 거다. 그걸 근거로 남을 설득하려고 하면 이상해진다. "제가 고생을 많이 했으니 제 말을 들으세요"는 논증이 아니니까.
그러면 왜 그 표본이 전달되지 않았을까. 몇 가지가 겹쳤다고 본다.
우선 이 판에는 권위가 쌓이지 않는다. 반감기가 짧기 때문이다. 어떤 분야에서 누군가의 말이 무게를 가지려면 그 사람이 옳았다는 게 나중에 확인되고, 그게 몇 번 반복되면서 정설이 만들어져야 한다. 그런데 하네스 얘기는 확인될 때쯤 대상이 바뀌어 있다. 내가 1월에 "이렇게 게이트를 걸어라"라고 말하고, 8월에 그게 맞았는지 확인하려고 보면 그 게이트는 이미 다른 이유로 죽어 있다. 맞았다고도 틀렸다고도 판정이 안 된다. 판정이 안 되는 주장이 반복되면 듣는 사람 입장에서는 전부 개인 취향으로 분류하는 게 합리적이다.
실제로 그렇게 들렸을 거다. "저 사람은 문서 쓰는 걸 좋아하는구나" 정도로.
그리고 임계점은 말로 설명이 안 된다. 복잡도가 낮으면 바이브 코딩은 유효하다. 이건 내 자료에도 적어놨다. 단일 레이어에 단일 언어면 그냥 시키면 된다. 문제는 다중 언어와 플랫폼 경계가 얽히는 지점을 넘을 때인데, 그 지점은 넘어봐야 안다.
임계점 아래에 있는 사람에게 임계점 얘기를 하면 겁주기로 들린다. 그 사람 경험 안에서는 AI가 잘 돌고 있으니까. 그리고 그 사람이 틀린 게 아니다. 그 사람 프로젝트에서는 진짜로 잘 도는 거다. 내가 든 반례는 내 프로젝트에서만 참인 얘기였고, 나는 그걸 일반 명제처럼 말했다.
지금 생각하면 그때 내가 해야 했던 건 "설계를 먼저 하라"가 아니라 "당신 프로젝트가 임계점 위인지 아래인지 이 세 가지로 판별해보라"였다. 처방을 먼저 내밀었으니 안 먹힌 거다.
제일 큰 건 마지막이다. 공감은 논증으로 오지 않고 손실로 온다.
나를 바꾼 건 슬라이드가 아니라 두 달이었다. 두 달을 태우고 적용 중단을 선언하는 경험이 없었으면 나도 원칙 다섯 개를 안 믿었을 거다. 그런데 내가 남한테 전달하려고 한 건 그 두 달이 아니라 두 달에서 뽑아낸 결론이었다. 결론만 옮기면 비용 감각이 안 따라온다. 비용 감각이 없으면 그 결론은 그냥 신중한 사람의 신중한 말이다.
이건 조직 단위에서도 똑같이 보인다. AX는 회사 단위로 팔리는데 실제 격차는 옆자리 사이에서 벌어진다고 쓴 적이 있는데, 도구를 똑같이 열어줘도 어떤 사람은 주간보고를 자동화하고 옆자리는 아무것도 못 뽑는다. 차이는 도구가 아니라 그 도구로 한 번 크게 데어봤느냐에서 온다. 사이드 프로젝트 네 개를 하면서 네 번 같은 자리에서 막혔던 기록도 결국 같은 얘기다. 같은 자리에서 네 번 막혀야 그게 자리라는 걸 안다.
돌아온 말은 내가 하던 말과 조금 다르다
그리고 이게 씁쓸함의 마지막 조각이다.
지금 도는 말들을 자세히 보면 내가 하던 말과 미묘하게 다르다. "하네스가 중요하다"까지는 같은데, 그다음이 다르다. 지금 유행하는 쪽은 하네스를 잘 짜면 모델을 갈아 끼울 수 있다는 얘기, 즉 하네스를 축적 자산으로 보는 시각이 강하다. 나는 반년 굴려보고 그 반대에 가까운 결론에 왔다. 하네스의 상당 부분은 소모품이고, 진짜 축적되는 건 그 아래 깔린 아키텍처 사실이다.
그러니까 사람들이 내 말에 동의하게 된 게 아니다. 다른 경로로 비슷하게 생긴 문장에 도착한 거다. 문장이 같아도 가리키는 게 다르면 같은 얘기가 아니다.
이걸 깨닫고 나니까 "거봐 내가 맞았지"라고 말할 자리가 사라졌다. 애초에 그런 자리가 있었던 적이 없다. 내가 맞았다고 확인해줄 심판이 없는 판이니까.
남은 건 좀 더 실용적인 질문이다. 같은 씁쓸함을 6개월 뒤에 또 겪지 않으려면 무엇을 다르게 해야 하나.
답은 이미 내 자료 안에 있었는데 내가 그걸 사람한테 적용할 생각을 못 했다. 문서에 이렇게 써놨더라. 코어 순수성 검사는 CI에서 돌고 머지를 막는다고. 레이어 규칙은 PR 체크리스트로 사람이 본다고. 둘의 차이는 강제력이다.
주장은 체크리스트다. 사람이 읽고 동의해야 작동한다. 동의를 안 하면 아무 일도 안 일어난다.
검사 스크립트는 CI다. 동의랑 무관하게 빨간불이 뜬다.
내가 반년 동안 한 건 전부 전자였다. 슬라이드를 만들고, 가이드를 쓰고, 사람들한테 설명했다. 만약 그때 슬라이드 대신 순환 의존성을 잡는 린트 규칙 하나를 PR에 걸었으면 어땠을까. 아무도 설득당하지 않았겠지만 순환 의존성은 안 들어왔을 거다. 그리고 그게 두어 달 쌓이면 그때는 사람들이 먼저 물어봤을 거다. 이거 왜 이렇게 해놨냐고.
설득은 그 질문에서 시작하는 거였다. 슬라이드 1장에서 시작하는 게 아니라.
지금 남은 문제
그래서 지금은 자료를 다시 돌리는 대신 아까 그 표의 마지막 줄을 붙들고 있다. 레이어 간 계약 검증, 미구현.
IPC 스키마와 FFI 타입 계약을 실제로 대조해서 어긋나면 빨간불이 뜨게 만드는 것. 이건 아직 못 만들었다. 렌더러에서 확정된 전제가 메인을 거쳐 코어까지 가는 동안 변형되지 않았는지를 기계가 판정하려면, 그 전제가 무엇인지 먼저 기계가 읽을 수 있는 형태로 적혀 있어야 한다. 지금은 사람 말로 적혀 있다.
이걸 풀면 두 달 태웠던 그 자리에 자동 검사가 하나 생긴다. 못 풀면 다음에도 같은 자리에서 막힐 거다. 그리고 그때는 아마 다른 사람이 나한테 "설계를 먼저 해야 한다"고 말해줄 텐데, 나는 또 그 말이 옳다는 걸 알면서도 그것만으로는 아무것도 안 바뀐다는 것도 알고 있을 거다.
하나만 덧붙이면, 반년 전에 그 얘기를 들어주지 않은 사람들이 틀렸다고 생각하지 않는다. 그 사람들은 그때 자기 자리에서 정확하게 판단했다. 임계점 아래에서는 문서 네 종이 진짜로 낭비다. 내가 틀린 건 내 임계점을 남의 임계점이라고 착각한 부분이었다.
씁쓸한 건 여전한데, 이제는 그게 인정받지 못한 서운함이 아니라 전달 방식을 잘못 골랐다는 자각에 더 가깝다. 어느 쪽이든 다음에 할 일은 같다. 말을 줄이고 검사를 하나 더 거는 것.
댓글
댓글 쓰기