2026년에 Bencher 만들기: 오픈 소스, 부트스트랩, 그리고 에이전트에 빠지다

Everett Pompeii

Everett Pompeii


이 에세이는 원래 2026년 10월 4일에 The Pragmatic Engineer’s How Software Engineering is Changing Essay Challenge에 제출한 글입니다.

올해는 제가 소프트웨어를 만드는 방식이 근본적으로 바뀐 해였습니다. 저는 스태프 소프트웨어 엔지니어입니다. 지난 6년 동안 YC와 a16z의 투자를 받은 유니콘 기업과 Fortune 500 기업 양쪽에서 Rust로 일해 왔습니다. C++ 개발에서 회복 중인 사람으로서, 저는 Rust가 요구하는 깊이와 기술에 끌렸습니다. 실시간 시스템 소프트웨어를 손으로 한 땀 한 땀 깎아 내는 숙련된 장인이 되어 있었죠. 그런데 지난 10개월 동안 그 정체성을 묻어야 했습니다. 직함은 여전히 “소프트웨어 엔지니어”이지만, 제 일은 이제 “컨텍스트 엔지니어”의 일이 되었습니다.

지난 4년 동안 저는 밤과 주말을 바쳐 오픈 소스이자 부트스트랩 비즈니스인 Bencher를 만들어 왔습니다. Bencher는 시스템 소프트웨어 엔지니어가 성능 회귀를 병합 전에 잡아낼 수 있도록 돕는 지속적인 벤치마킹 플랫폼입니다. 이를 위해서는 CLI, API 서버, 프런트엔드 웹 콘솔 UI라는 여러 도구가 필요합니다. 이 구성 요소들은 반올림 오차 수준을 빼면 전부 제가 작성했습니다. 그동안 눈에 띄는 오픈 소스 기여자가 몇 분 계셨지만, 오픈 소스 프로젝트로서의 Bencher는 대부분, 그리고 비즈니스로서의 Bencher는 100% 제가 직접 설계하고 구현했습니다.

이 4년 동안 제가 세상과 담을 쌓고 산 것은 아닙니다. 약혼하고, 결혼하고, 첫 아이를 얻었습니다. 큰 기능 하나를 구현해서 배포하기까지 몇 주, 때로는 몇 달이 걸렸습니다. 개발과 지원을 동시에 해내야 했습니다. Bencher에는 이미 사용자가 많았기 때문에, 질문에 답하고 이따금 나오는 버그를 고치는 데 꽤 많은 시간을 썼습니다.

2022년 당시 제가 LLM을 쓰는 방식이라고는 TabNine의 Rust 무료 버전이 전부였습니다. TabNine은 탭 한 번으로 자동 완성해 주는 개발자 도구로, 한 학생이 만들었는데 그는 OpenAI의 초기 인턴으로 Codex라는 재미있는 작은 프로젝트를 하고 있었습니다. GitHub Copilot이 출시되고 비공식적으로 Rust 지원이 추가되자, 저는 개인 라이선스 비용으로 월 $10를 기꺼이 냈습니다.

엉성했습니다. 그래도 여전히 약간은 마법처럼 느껴졌습니다. GitHub Copilot VSCode 확장에 채팅이 추가된 직후, Rust 절차적 매크로를 정말 잘 만들어 내는 걸 보고 감탄했던 기억이 납니다. 보통은 결과물을 조금 손봐야 했지만, 몇 번은 한 번에 완성해 냈습니다. 대박! 멋졌고 시간도 어느 정도 아껴 줬겠지만, 저는 여전히 대체로 예전과 같은 방식으로 일했습니다.

그때부터 저는 Microsoft가 GitHub Copilot으로 선두에 서 있다고 생각하게 됐습니다. 신생 연구소들이 “에이전트”를 내놓고 있어도, 쓸 만한 게 있다면 GitHub Copilot이 따라잡을 거라고 믿었습니다. Lenny’s Podcast에서 Dan Shipper 같은 사람들의 이야기를 들어도, 그들이 말하는 모델의 능력은 제 경험과도, 제 품질 기준과도 도무지 맞지 않았습니다.

작년 초, 저는 Bencher 개발 3년을 돌아보는 글 엔지니어링 리뷰: 2025 에디션을 썼습니다. 그 글에서는 프런트엔드, 백엔드, 개발자 환경, CI 등 Bencher를 만들면서 내린 주요 엔지니어링 결정을 빠짐없이 다뤘습니다. 2년 전 CUE lang을 이해하느라 얼마나 고생했는지 하소연하는 데 한 문단을 통째로 쓰기도 했습니다. 그런데 그 3,500단어짜리 글 어디에도 AI, LLM, 심지어 Copilot이라는 말이 단 한 번도 나오지 않습니다.

그로부터 1년도 채 지나지 않은 지금, 저는 We mourn our craft에 깊이 공감하고 있습니다.

Claude, 크리스마스를 구하다

많은 사람들처럼, 저도 2025년 겨울 휴가 동안 Claude Opus 4.5를 제대로 써 볼 기회가 있었습니다. 저는 아내와 아이를 데리고 런던에 사는 여동생 가족을 방문하고 있었습니다. 여동생이 얼마 전 쌍둥이를 낳아서 저는 일손을 거들러 간 것이었죠. 그런데 정작 저는 위층에 틀어박혀 Bencher를 노린 이메일 스팸과 DDoS 공격을 막아 내느라 씨름하고 있었습니다. Claude는 무슨 일이 일어나고 있는지 진단하고 가능한 해결책을 떠올리는 데 정말 큰 도움이 됐습니다.

결국 저는 Bencher를 Cloudflare 뒤로 옮기고 reCAPTCHA를 설정했습니다. 대부분의 작업은 여전히 제가 했지만, 서로 충돌하는 여러 설계 제약 조건 속에서 문제를 해결하는 능력은 Opus 4.5에서 눈에 띄게 향상되어 있었습니다. 다만, Claude가 제안한 변경 하나 때문에 Bencher CLI를 설치하는 편의 스크립트가 반나절 동안 먹통이 되기도 했습니다. 이런.

새해, 새 하네스

올해 1월쯤에는 Claude Code가 얼마나 인상적인지에 대한 이야기를 이미 몇 달째 듣고 있었습니다. 그전까지는 Opus 4가 제 작업을 믿고 맡길 만한 품질 기준에 미치지 못해서 써 보기를 미뤄 왔습니다. 이제 Opus 4.5가 그 기준을 넘었으니 Claude Code도 한번 써 보고 싶었습니다. 하네스를 Copilot에서 Claude Code로 바꿨을 때 체감한 향상 폭은, 모델을 Opus 4/GPT-5.2/Gemini 2.5 Pro에서 Opus 4.5로 바꿨을 때만큼이나 큰 도약이었습니다.

Claude Code를 쓴 첫 주말, 저는 Copilot과 그다지 통제되지 않은 비교 테스트를 해 봤습니다. Copilot에게는 PDF를 오디오북으로 바꾸는 일을 맡겼습니다. “Agent Mode”에서도 Copilot은 대여섯 단계쯤 진행하다가 제가 다시 쿡 찔러 줄 때까지 그냥 멈춰 버렸습니다. 같은 시간에 Claude Code는 꼼꼼하게 Plan mode를 거친 뒤 커스텀 하이퍼바이저를 만들겠다며 쉴 새 없이 일하고 있었습니다. 저는 추상화의 단계가 모델에서 하네스로 올라갔으며, Copilot은 다시는 따라잡지 못할 것이라고 완전히 확신하게 됐습니다.

Bencher Bare Metal을 꿈꾸며

Bencher를 시작한 아주 초창기부터, 저는 베어 메탈 벤치마킹 플릿을 만드는 꿈을 꿔 왔습니다. 전통적인 CI 러너는 가상 머신이라는 특성상 노이즈가 너무 커서 일관된 벤치마크 결과를 얻을 수 없습니다. 예를 들어 지연 시간이 200% 늘어난 것은 감지할 수 있어도, 20% 늘어난 것을 안정적으로 감지하기는 불가능합니다. CI에서 벤치마킹하는 한 가지 방법으로 명령어 카운트가 있습니다. 명령어 카운트는 대체로 결정적입니다. 하지만 명령어 카운트는 여러분이 실제로 신경 쓰는 것, 즉 벽시계 시간의 대리 지표일 뿐입니다. “CPU 시뮬레이션” 안에서 실행되어 명령어 카운트를 뱉어 내는 것은 무엇이든 속도와 상관관계만 가질 수 있습니다. 문제는 실제로 베어 메탈에서 측정해 보기 전까지는 그 값이 얼마나 많이, 혹은 얼마나 적게 어긋나 있는지 결코 알 수 없다는 것입니다.

Bencher의 가장 초기 사용자 중 하나가 Rustls 프로젝트였습니다. 저는 그들의 Rustls bench runner에 기여하는 것을 도왔습니다. 하지만 이것은 베어 메탈 벤치마킹 플릿을 쌓아 올릴 좋은 기반이 아니었습니다. 단일 호스트에서 돌아갔고 모든 벤치마크 워크로드를 신뢰할 수 있다고 간주했습니다. 즉, 포크에서 온 PR도 안 되고 멀티테넌시도 안 된다는 뜻입니다. 게다가 대부분의 팀은 베어 메탈 벤치마킹 서버 한 대당 매달 $100 이상을 내고 싶어 하지 않습니다.

오케스트레이션 계층으로 GitHub Actions를 쓰는 것도 고려했지만, 이 접근 방식에는 몇 가지 근본적인 한계가 있었습니다. 우선 GitHub Actions Runner는 C#으로 작성되어 있습니다. 즉, 실행 도중에 가비지 컬렉터가 돌기 시작해서 벤치마크 결과를 왜곡할 수 있습니다. 아, 그리고 실행 도중에 돌지 않도록 자동 업데이트 기능을 꼭 꺼 두세요. 그렇다고 너무 오래 잊고 있으면 안 됩니다. 안 그러면 작업이 더 이상 실행되지 않을 테니까요!

설령 GitHub Actions Runner가 조용하고 깔끔한 Rust 바이너리였다고 해도, 더 근본적인 문제는 그것이 GitHub Actions에 묶여 있다는 점이었습니다. Bencher는 처음부터 CLI 우선이었습니다. 좋든 나쁘든, 저는 Bencher를 특정 CI 제공자 하나에 너무 깊이 묶고 싶지 않았습니다. Bencher CLI GitHub Action이 있긴 하지만, 하는 일이라고는 CLI를 설치해 주는 것뿐입니다. 저는 Bencher Bare Metal이 GitHub Actions에서만이 아니라 CLI가 동작하는 곳이라면 어디서든 동작하기를 원했습니다.

제가 떠올린 아이디어는 OCI 이미지로 벤치마킹 워크로드를 묶고, 선택 사항인 아주 작은 샌드박스를 사용해 특정 베어 메탈 호스트에서 한 번에 오직 하나의 작업만 실행하는 것이었습니다. 이것을 밤과 주말에 혼자 만들어 낸다는 생각은 막막했습니다. 본업과 가족이 있는 상황에서, 혼자 조금씩 깎아 나갔다면 최소 1년은 걸렸을 겁니다.

Bencher Bare Metal 만들기

올해 1월, Opus 4.5와 Claude Code를 손에 쥐고 나니 마침내 Bencher Bare Metal을 만들어 낼 현실적인 길이 보이는 것 같았습니다. 저는 다시 한번 지갑을 열었고, 이번에는 Claude Max 20x 플랜에 무려 월 $200를 냈습니다. 아마 역대 최고의 사업 지출일 겁니다.

저는 미친 듯이 달리기 시작했고, 매주 Claude 플랜 사용량을 최대한 꽉 채우려고 애썼습니다. Bencher에서도, 본업에서도 코드를 손으로 쓰는 일을 그만뒀습니다. 이때만 해도 저는 꽤 촘촘한 루프로 반복하고 있었습니다. Plan mode를 쓰고, 출력을 전부 읽고, Accept edits 모드로 실행했습니다. 이 시점에는 에이전트가 git/jj를 건드리는 걸 믿지 못해서 버전 관리는 전부 제가 직접 했습니다. 스스로를 사람이 끼어 있는(human-in-the-loop) Ralph Loop라고 생각했죠. 에이전트를 다섯 개쯤 병렬로 돌리면 뇌가 녹아내리기 시작했습니다.

제가 들었던 제안 중 하나는 구현과 리뷰를 서로 다른 에이전트에게 맡기라는 것이었고, 그래서 저는 별도의 적대적 리뷰를 하기 시작했습니다. 이 적대적 리뷰는 결과물의 품질을 높이는 데 정말 도움이 되는 것 같았습니다. 저는 제 Claude Code 구독 API 키를 사용하는 GitHub Actions 리뷰 봇을 직접 만들었습니다. 그런 다음 로컬 머신의 자원을 아끼기 위해, 로컬 에이전트가 이 CI 리뷰어와 함께 반복 작업을 하도록 했습니다.

그러던 중 한때는 Claude에게 벤치마킹 샌드박스용 하이퍼바이저를 직접 만들게 할 생각이었습니다. 그런데 Claude에게 Linus Torvalds가 되어 그 계획을 적대적으로 리뷰해 달라고 했더니, 저더러 멍청하다며 이건 아주, 아주, 아주 바보 같은 아이디어라고 하더군요. 컨텍스트에 Linus가 있으면 아첨은 없습니다! 그래서 그 계획은 폐기하고 Firecracker를 택했습니다.

좋은 벤치마킹의 적은 속도 자체가 아니라 분산입니다. 그래서 Firecracker가 하이퍼바이저로서 오버헤드를 더하긴 하지만, 그 오버헤드는 매우 일관적입니다. 특히 한 번에 오직 하나의 microVM만 실행될 때는 더욱 그렇습니다. 덕분에 공유 Bencher Bare Metal 러너는 멀티테넌시와 매우 일관된 벤치마킹 결과를 모두 가질 수 있습니다. 또한 Claude와 함께 Plan mode로 샌드박스를 선택 사항으로 만드는 설계를 했습니다. 사용자가 모든 워크로드를 신뢰하는 자체 전용 서버에서 실행하고 싶다면, Firecracker 없이 오버헤드가 거의 0인 상태로 실행할 수 있습니다.

Bare Metal runner를 개발하면서 에이전트에게 촘촘한 피드백 루프가 얼마나 중요한지 크게 배웠습니다. Opus 4.6이 나온 뒤에도 Claude는 모든 것을 일관되게 동작시키는 데 애를 먹는 것 같았습니다. 그런데 KVM이 활성화된 개발 환경(Firecracker를 실행하려면 필수입니다)에 접근할 수 있게 해 주자, 일이 정말 술술 풀리기 시작했습니다. 이 에이전트들은 전지전능한 게 아니라, 그냥 정말 끈질길 뿐입니다.

Claude의 작업을 얼마나 꼼꼼히 들여다볼지는 코드베이스의 어느 부분에서 작업하느냐에 따라 달랐습니다. OCI 레지스트리나 runner 바이너리처럼 순전히 Bare Metal만을 위한 코드는 가볍게만 리뷰했습니다. 적대적 리뷰를 통과하고, 엔드투엔드 테스트가 통과하고, 너무 끔찍해 보이지만 않으면 병합했습니다. 작업 큐잉과 리포트 처리처럼 기존 코어를 건드리는 코드에 대해서는 언제나처럼 깐깐하게 굴었습니다.

올해 3월 말, 저는 v0.6.0의 일부로 Bencher Bare Metal을 출시했습니다. 공개 베어 메탈 플릿으로는 AWS EC2 Bare Metal을 고려하고 있었습니다. 하지만 이 머신들은 거대한 데다 ARM 전용입니다. 대부분의 실제 워크로드에 맞추기 위해, 저는 평범한 일꾼 같은 Intel x86 머신을 원했습니다. 설계 제약 조건을 충족하는 플릿의 최적의 보금자리를 찾기 위해 Claude와 함께 조사했습니다. 그 결과 Bencher Cloud에서 intel-v1 Spec을 제공할 수 있게 됐는데, 4 vCPU, 48 GB 메모리, 128 GB 디스크를 분 단위로 과금합니다. 잘 구성된 벤치마크에서는 플릿 전체에 걸쳐 실행 간 분산이 꾸준히 <2%로 나왔습니다.

에이전트 인증

Bencher Bare Metal 이전까지 모든 인증은 JWT였습니다. 크고, 아름답고, 도무지 알아볼 수 없는 JWT 말이죠. Bare Metal 러너의 인증은 이름 접두사가 붙은 API 키였습니다. 예를 들면 bencher_runner_abc123... 같은 것이죠.

클라이언트 쪽에서는 사용자 본인의 API 토큰 JWT 말고 에이전트가 쓸 수 있는 다른 무언가를 주고 싶었습니다. 그래서 찾은 절충안은 오랫동안 요청받아 온 기능, 즉 프로젝트 범위 인증을 마침내 구현하는 것이었습니다. Claude는 제가 안전한 프로젝트 범위의 접두사 API 키를 만드는 것을 도와줬습니다. 이 API 키들은 bencher run CLI 명령이 수행하는 것과 동등한 권한, 즉 프로젝트 범위의 읽기와 파괴적이지 않은 쓰기로 제한됩니다. 덕분에 이 API 키들은 지속적인 벤치마킹 CI 워크플로에서 쓰기에도 자연스럽게 잘 맞습니다.

나중에 Bencher MCP를 추가했을 때도, 이 프로젝트 범위 API 키를 그곳의 인증에 사용했습니다. MCP 표준은 OAuth 2.1을 명시하고 있지만, OAuth 2.1은 아직 초안 단계이라서 당장 구현하고 싶지는 않았습니다. 솔직히 저는 MCP에 다소 회의적인 편입니다. 저는 여전히 좋은 CLI와 스킬의 조합이 에이전트에게 서비스를 노출하는 더 효과적이고 이식성 높은 방법이라고 생각합니다. 다만 CLI의 가장 큰 문제는 표준 인증 메커니즘이 없다는 점입니다. 그러니 OAuth 2.1이 아직 초안이라 해도, 적어도 MCP는 그 부분을 해결하고 있습니다. 그리고 좋은 인증 체계는 엔터프라이즈에게 정말 중요합니다.

다국어 능통자 Claude

2023년에 저는 Bencher 문서를 영어, 중국어, 스페인어, 브라질 포르투갈어, 러시아어, 일본어, 프랑스어, 독일어, 한국어의 9개 언어로 제공하기로 했습니다. 이 아홉 개 언어는 어떻게 골랐냐고요? GitHub 문서가 제공되는 언어들이었기 때문에, 그 정도면 충분히 괜찮은 근사치라고 생각했습니다. 유일한 문제는 제가 유창하게 하는 언어가 영어뿐이라는 것이었습니다. 그래서 GPT-4에게 문서 번역을 맡겼습니다. 당시 GPT-4의 컨텍스트 윈도는 고작 8k 토큰이었습니다. 그래서 모든 문서 페이지를 8k 토큰보다 작은 “청크”로 쪼개야 했습니다. 그다음에는 청크를 번역하고, 청크가 수정된 뒤에는 아주 자주 다시 번역하는 일을 처리할 CLI 도구를 만들어야 했습니다.

이 과정은 매우 지루하고 오류가 나기 쉬웠습니다. 아주 명시적인 시스템 프롬프트 지시를 줘도 모델이 import 경로를 망가뜨리거나 모든 내용을 Markdown 블록 한 겹 안에 또 집어넣어 버리곤 해서, 번역된 파일을 손으로 고쳐야 했습니다. 왠지 모르게 특히 일본어에서 그랬습니다.

Opus 4.5와 함께 Claude Code를 쓰기 시작하자, 이 모든 문제가 사라졌습니다. 이제는 에이전트가 그냥 알아서 합니다. 무엇이 청크가 되는지에 대한 규칙이 코드베이스에 있고, Claude는 그저 그 규칙을 따릅니다. Bencher Bare Metal의 기술 문서를 작성할 때도, 청크로 나누는 일과 번역을 조율하는 일은 Claude가 그냥 처리했습니다. 이제 컨텍스트 크기가 페이지 전체를 다루고도 남을 만큼 커졌지만, 저는 청크가 있는 쪽이 좋습니다. 변경 사항을 격리하는 데 도움이 되어서, 수정할 때 페이지에서 관련된 부분만 다시 번역되기 때문입니다.

2026년에 하네스 안 만든 사람 있나요?

Bencher Bare Metal을 만드는 동안, 저는 Claude에게 플릿을 관리할 자기 자신용 도구도 만들게 했습니다. 이 도구는 두 부분으로 이뤄져 있었습니다. 일상적인 작업을 위한 bencher 저장소 안의 CLI, 그리고 새로운 메타 저장소(meta-repo)입니다. 이 meta-repo에는 제품으로서의 Bencher에 관한 모든 문서와 컨텍스트가 담겨 있습니다. bencherdev GitHub 조직의 다른 모든 저장소는 이 meta-repo의 서브모듈입니다. meta-repo 덕분에 에이전트는 여러 저장소에 걸친 작업을 쉽게 처리하고, 제가 공개하고 싶지 않은 문서(제품 전략, 장애 보고서 등)도 작성할 수 있습니다.

저는 Claude Code CLI 위에 저만의 에이전트를 만들어서, 이 meta-repo를 하나의 산출물에서 개발 사이클의 능동적인 일부로 끌어올리고 싶었습니다. Fable 5가 나오자, 저는 이 에이전트를 만드는 데 많은 힘을 쏟았습니다. 이 에이전트가 자율적으로 실행되도록 믿고 맡길 수 있기를 바랐습니다. 그 핵심 중 하나가 보안(즉 프롬프트 인젝션 완화)이었습니다. 저는 워커 에이전트가 절대 어떤 시크릿도 갖지 않도록 설계했습니다. 모든 시크릿은 네트워크 프록시가 주입하며, 허용 목록에 있는 엔드포인트로만 제한됩니다. 에이전트 자체는 또 하나의 Firecracker microVM 안에서 실행됐는데, 이번에는 병렬로 돌아갔습니다. 에이전트 제어 박스와, 네트워크 프록시 및 샌드박스는 완전히 다른 호스트에서 실행됐습니다.

제 원대한 비전은 인터페이스를 작업 우선순위 순으로 정렬된 큐로 만드는 것이었습니다. 다시 말해, 이 에이전트의 목표는 바로 그 순간 가장 중요한 작업을 저에게 보여 주는 것이었습니다. Facebook/Instagram/Twitter/X/TikTok 피드가 참여도에 최적화되어 있다면, 이 피드는 저에게 얼마나 중요한지에 최적화되는 것이죠.

저는 저 자신을 API 아래에 두는 도구를 만들고 싶었습니다. 저는 대부분의 시간을 컨텍스트 전환과 이 스레드 저 스레드를 오가는 데 쓰고 있다는 걸 깨달았습니다. 에이전트가 일의 순위를 매겨 줌으로써 이런 저글링을 덜어 줄 수 있기를 바랐습니다. Reddit 같은 추천/비추천 시스템으로, 방금 온 Slack 메시지가 정말 지금 제가 가장 신경 써야 할 일인지 에이전트가 알도록 훈련시킬 수 있을 테니까요.

또 요즘 제 일의 상당 부분이 제 에이전트의 루비우스 해그리드, 즉 “열쇠지기”가 되는 것이라는 걸 알게 됐습니다. 제한된 엔드포인트 허용 목록을 둔 네트워크 프록시 수준의 주입은, 에이전트가 시크릿에 절대 접근하지 못하게 하면서도 gh CLI 같은 도구를 바로 쓸 수 있게 하는 방법으로 Claude와 제가 찾아낸 최선의 방법이었습니다.

또 다른 핵심 목표는 에이전트 인터페이스를 절대 떠나지 않는 것이었습니다. 어떤 이유로든 에이전트를 벗어나 다른 곳으로 가야 한다면 그것은 하네스의 실패로 간주됩니다. 저는 절차적 UI 컴포넌트 시스템을 만들어서, 작업을 처리하는 에이전트가 그때그때 새로운 인터페이스를 즉석에서 만들거나 당면한 작업에 맞춰 라이브러리의 기존 컴포넌트 중 하나를 고를 수 있게 했습니다. 코드, 이메일, Slack, 캘린더, 프로덕션 텔레메트리 데이터, 오류 모니터링, 이 모든 것이 하나의 인터페이스, 하나의 우선순위 큐 안에 있는 것이죠.

이 모든 것의 최소 버전은 돌아가게 만들었습니다. 하지만 아직 거친 부분이 많습니다. 지금은 그냥 Claude 데스크톱 앱을 쓰는 편이 훨씬 생산적입니다. 그리고 지금 당장은 쏟아지는 수요를 따라가려면 즉각적인 생산성을 최대한 끌어모아야 합니다.

개발자 수가 100배가 되면 무슨 일이 일어날까요?

2022년, 저는 새로운 사이드 프로젝트를 찾고 있었습니다. 그 전의 창업 지망생다운 도전은 2020년에 접은 상태였습니다. 꿀팁: Jason Cohen의 말을 들으세요. 마켓플레이스를 부트스트랩하려고 하지 마세요.

당시 저는 본업에서 Rust로 정적 bash 파서와 분석기를 만들고 있었는데, 벤치마크 결과를 추적하려고 스프레드시트를 써야 하는 처지라는 걸 깨달았습니다. Rust 프로젝트에는 컴파일러 자체의 성능을 추적하는 rustc-perf가 있습니다. 하지만 제 코드에 같은 일을 해 줄 좋은 도구는 없었습니다.

저는 이 분야의 선행 기술을 아주 많이 조사했습니다. 몇 달에 걸쳐, 지속적인 벤치마킹 도구를 직접 만들었거나 만들자고 주장해 온 여러 개발자와 통화했습니다. 모두가 바퀴를 다시 발명하고 있었습니다. 저는 시장이라는 물결 속에서 조용하고 아늑한 자리를 찾았다고 생각했습니다. 분명하고 지속적인 수요가 있었습니다. 많은 팀이 이미 자체 베어 메탈 러너에 매달 $100 이상을 내고 있었습니다. 즉, 돈을 낼 의향이 있었다는 뜻입니다. 하지만 사용 사례는 틈새였습니다. 대부분의 현대 소프트웨어는 서비스 형태로 배포되기 때문에, 성능 테스트를 앞단으로 당기는(shift left) 일은 대부분의 팀에게 그리 우선순위가 높지 않았습니다. 그들은 그냥 배포 후 Grafana에 알림을 설정해 두고, 빠져나간 문제는 사후에 잡아내곤 했습니다.

하지만 매우 유능한 에이전트들이 등장하면서, 두 가지 요인이 Bencher 사용량을 크게 늘렸습니다.

  1. 에이전트의 출력을 결정적으로 테스트하기 위해 소프트웨어 엔지니어링 모범 사례를 도입해야 할 필요성
  2. 에이전트의 도움으로 소프트웨어 엔지니어링 모범 사례를 쉽게 도입할 수 있게 된 것

LLM과, 더 나아가 에이전트는 비결정적이고 확률적인 시스템입니다. 사람 개발자와 마찬가지로, 코드 품질을 유지하려면 가드레일이 필요합니다. 그 방법은 새로운 것이 아닙니다. 견고한 타입 시스템, 표준 포매터, 최대치로 끌어올린 린터, 테스트, 테스트, 그리고 더 많은 테스트. 이 모든 것을 CI에서 실행합니다. 성능에 민감한 워크로드라면, 이 테스트에는 추적되는 벤치마크도 포함됩니다. 소프트웨어 성능을 시간에 따라 추적하면 CI에서 성능 회귀를 잡아낼 수 있습니다. 이것을 지속적인 벤치마킹이라고 합니다. 지속적인 벤치마킹을 구현하는 일은 늘 좀 귀찮은 일이었습니다. 성능에 정말, 정말 신경 쓰는 팀만 했고, 그런 팀은 훌륭한 Bencher 사용자가 되어 줬습니다!

그런데 에이전트가 등장하면서, Bencher로 워크플로에 지속적인 벤치마킹을 추가하는 수고는 짧은 프롬프트 하나면 되는 일이 됐습니다. 완벽하게 추적하기는 어렵지만, 지금 Bencher에 들어오는 가입의 대다수는 에이전트의 추천이나 에이전트가 직접 해 준 덕분이라는 데 걸겠습니다. 더 많은 개발자가 에이전트를 도입하고 에이전틱 커머스로 에이전트에게 권한을 부여할수록, 이는 시간이 갈수록 더욱 사실이 될 것입니다. 그것이 x402 프로토콜일지 아닐지는 모르겠지만, 앞으로 개발 도구에 쓰는 돈의 상당 부분은 에이전트를 통해 오갈 것이라고 생각합니다. 아직 안 하셨다면 Cloudflare Wallet과 Stripe Wallet을 미리 확보해 두시길 권합니다.

에이전트 시대에는 거의 모든 개발 도구가 사용량 기반 가격 책정으로 옮겨 가야 할 것입니다. 서비스를 쓰는 주체가 에이전트라면 좌석 기반 가격 책정은 말이 되지 않습니다. Bencher는 처음부터 사용량 기반 가격 책정을 써 왔습니다. 하지만 최근 Claude의 도움을 받아 가격 모델을 에이전트에게 훨씬 더 친화적으로 개편했습니다. 이전에 Bencher는 메트릭당 요금을 부과했습니다. 메트릭은 특정 시점의 단일 벤치마크 결과입니다. 예를 들어 벤치마크 1개를 5번 실행하면 메트릭이 5개 생성됩니다. Claude는 제가 사용자 피드백과 사용 패턴을 분석하는 것을 도와줬습니다. 저는 사용량 기반 가격 모델에서 쓰던 단위를 바꿔야 한다는 결론에 이르렀습니다. 이제 Bencher는 벤치마크 시리즈당 요금을 부과합니다. 벤치마크 시리즈는 시간에 따라 추적되는 하나의 벤치마크입니다. 앞의 예로 돌아가면, 벤치마크 1개를 5번 실행하면 벤치마크 시리즈는 1개입니다. 이 새로운 가격 모델은 사용자에게 훨씬 더 큰 예측 가능성을 줍니다. 에이전트에게 최적화 문제를 맡기면, 에이전트는 추가 비용 없이 여러분의 과거 벤치마크를 바탕으로 힐 클라이밍을 할 수 있습니다.

지난 1년 동안 변하지 않았다고 느낀 것 중 하나는 오픈 소스 기여입니다. Bencher는 AI 슬롭 PR을 두어 개 받았습니다. 이런 PR의 주된 문제는 작업하다가 우연히 발견한, 관련 없는 버그들을 이것저것 고쳤다는 점이었습니다. 그래도 진짜 버그이긴 했습니다! 그래서 저는 그냥 어깨 한 번 으쓱하고, 물론 제 에이전트에게 리뷰를 시킨 뒤에 PR을 병합했습니다. 좀 서글프긴 하지만, 이제는 오픈 소스 기여자를 유치하는 데서 큰 이점을 느끼지 못합니다. 그들의 토큰이든 제 토큰이든, 코드를 리뷰하는 데는 여전히 같은 노력이 듭니다. 이제는 기여자의 PR을 리뷰하는 쪽이 제가 직접 Claude와 반복 작업하는 것보다 훨씬 더 많은 에너지가 듭니다.

지속적인 벤치마킹의 미래는?

미래가 어떻게 될지 점쳐 보려 할 때, 프런티어 연구소들이 직접 무엇을 하고 있는지 살펴봐야 한다는 것이 하나의 패턴처럼 보입니다. 6개월에서 12개월이면 우리 모두 그곳에 도착해 있을 것 같으니까요. The Pragmatic Engineer의 Inside OpenAI’s agentic software factory는 지속적인 벤치마킹 관점에서 이 부분에 흥미로운 빛을 비춰 줍니다.

신규: “perf 하네스”: 에이전트는 perf 하네스도 사용해 문제가 있는 PR을 Synthetics A/B 프레임워크로 보내 성능에 미치는 영향을 평가합니다. 앞서 언급했듯이, 지난 6개월 동안 CI 시스템에 걸리는 부하가 크게 늘었습니다.

OpenAI의 “perf 하네스”는 이미 확립된 관행인 상대적 지속적 벤치마킹과 매우 비슷해 보입니다. 새로운 AI 요소는 A/B 프레임워크의 합성(synthetic) 부분입니다. 합성 테스트 데이터 자체는 새로운 것이 아닙니다. 하지만 당면한 변경 세트의 성능을 평가하기 위해 그 합성 데이터를 자율적으로 만들어 낼 수 있다는 것은 분명 새로운 일입니다! 개발자가 실제로 벤치마크를 작성하게 만드는 일은 늘 고역이었습니다. 이제는 그것이 자동화됐습니다. 에이전트가 기능 테스트 커버리지를 대폭 늘린 것과 마찬가지로, 성능 테스트 커버리지도 대폭 늘릴 수 있게 해 주고 있습니다.

OpenAI만 이런 시도를 하는 것은 아닙니다. Anthropic도 곧이어 How we made claude.ai 3x faster in two weeks를 공개했습니다. 이 글에서도 벤치마크를 즉석에서 만들어 내는 과정을 설명합니다. 한 가지 핵심적인 차이는 Anthropic이 성능과 상관관계가 있는 결정적인 카운트들을 찾아냈다는 점입니다. 명령어, 상호작용당 커밋 수, 함수 호출, 스타일 재계산, DOM 변경이 그것입니다. 그런 다음 Claude가 이 카운트들을 힐 클라이밍해서 앱의 성능을 최적화했습니다. 최적화 단계가 끝나면, 카운트 기반 최적화가 실제로 현실의 벽시계 시간 개선으로 이어졌는지 확인했습니다.

이런 방법론은 제가 Bencher를 작업하면서 직접 겪어 온 것과 맞아떨어집니다. 다만 제 A/B 성능 테스트는 CI 루프가 아니라 모두 로컬이나 에이전트의 작업 머신에서 실행됐습니다. 쿼리를 크게 바꾸거나 의미 있는 스키마 마이그레이션을 하려고 할 때마다, 저는 Claude에게 그 변경에 대한 철저한 성능 평가를 시킵니다. 여기에는 항상 벽시계 시간이 포함되고, 가끔은 그에 따른 결정적인 카운트(예: SQLite 가상 머신 명령어)도 포함됩니다.

시끄러운 이웃 문제 때문에, 에이전트가 주도한 이런 성능 최적화 작업의 오차 범위는 꽤 넓었습니다. 저는 에이전트가 이런 성능 최적화 작업을 더 높은 신뢰도로 수행할 수 있도록, Bencher Bare Metal에 픽스처(추가 벤치마크 입력)와 아티팩트(추가 벤치마크 출력)를 추가하려고 합니다. 에이전트는 여전히 최적화 작업의 대부분을 로컬에서 하면서 벽시계 시간이나 결정적인 카운트를 기준으로 최대한 힐 클라이밍을 할 것입니다. 그런 다음 일종의 벽시계 캘리퍼처럼 Bencher Bare Metal을 사용해 자기 작업을 검증할 것입니다.

1년쯤 뒤면 Bencher의 “사용자” 대부분이 에이전트가 될 거라고 생각하지만, 그래도 대부분의 사람은 상황을 확인할 때 시각적인 인터페이스를 원할 거라고 봅니다. 저는 지금 Claude의 도움을 받아 Bencher UI를 완전히 다시 디자인하는 작업에 푹 빠져 있습니다. GitHub Copilot의 탭 자동 완성 시절에 Anyscript를 쓰던 Rust 엔지니어가 만든 탓에, 지금의 UI는 아쉬운 점이 많습니다. 하지만 UI 재작성은 그보다 훨씬 더 야심 찬 또 다른 대개편, 즉 Bencher Metric Format (BMF)의 새 버전에 막혀 있습니다.

BMF는 Bencher 안에서 벤치마크 결과를 정규화하는 핵심 포맷입니다. 모든 것을 관통하죠. 이 새 버전의 BMF에서는 벤치마크를 매개변수화할 수 있습니다. my_benchmark_16_mb와 my_benchmark_32_mb라는 두 개의 별도 벤치마크를 두는 대신, my_benchmark에 size: 16 MB와 size: 32 MB라는 매개변수를 지정할 수 있게 됩니다. 새 버전의 BMF에서는 임의의 메트릭 이름도 쓸 수 있습니다. Latency 측정값에 대해 mean만 두거나 Latency (mean), Latency (p95), Latency (p99)를 별도의 측정값으로 만들 필요 없이, mean, p95, p99 메트릭을 제공할 수 있게 됩니다.

이 새 BMF 버전을 지원하는 것은 Bencher 코어의 대대적인 개편입니다. Fable 5 이전의 그 어떤 모델로도 이 작업을 하는 것이 마음 편하지 않았을 겁니다. 앞서 이야기했듯이, Bare Metal 작업의 대부분은 Bencher의 코어, 즉 시간에 따른 성능 추적과 회귀 알림과는 직교하는 위치에 있었습니다. BMF는 그 핵심 가치 제안의 중심에 있습니다. Fable 5, 그리고 그보다 더 Fable 5.1과 Opus 5.5에 대한 신뢰 덕분에, 저는 또다시 밤과 주말을 몇 년은 바쳐야 끝났을 프로젝트를 시작할 수 있었습니다. 예전에는 Bencher를 위해 SQLite를 최적화하는 데 꽤 많은 시간을 써야 했습니다. 이제는 모델을 발전시킬 때마다 Claude에게 에이전트를 띄워 철저한 성능 조사를 하고 모든 것이 여전히 빠른지 확인하라고 부탁하기만 하면 됩니다. 앞으로는 부탁할 필요조차 없을 거라고 생각합니다.

요즘 제가 코딩하는 방식

GitHub Copilot을 쓰던 시절에는 VSCode의 확장이었습니다. Claude Code로 처음 넘어왔을 때는 CLI를 썼습니다. 터미널 창 세 개를 각각 별도의 macOS Space에 띄워 두곤 했습니다. 터미널 창마다 탭이 두 개 있었습니다. 하나는 Claude용, 다른 하나는 Jujutsu (jj)용이었습니다. 버전 관리와 jj 워크스페이스는 여전히 제가 직접 관리하고 있었습니다.

요즘은 그냥 Claude Code 데스크톱 앱을 씁니다. 새 세션은 모두 worktree 체크박스를 켠 상태로 제 meta-repo에서 시작합니다. Plan mode는 몇 달 전에 그만 썼습니다. Matt Pocock의 /grill-me 스킬도 설치한 적이 없습니다. 그냥 프롬프트에 Claude에게 “모든 설계 결정에 대해 나를 집요하게 캐물어 줘”라고 쓰면, 이제는 모델이 알아서 할 일을 압니다. 제 CLAUDE.md AGENTS.md는 모델이 제가 원하는 대로 움직이도록 꽤 잘 다듬어져 있습니다.

Claude Review CI 워크플로는 사실상 퇴역시켰습니다. 이제는 제가 따로 부탁하지 않아도 에이전트가 로컬에서 적대적 리뷰어를 띄웁니다. 그런 다음 둘이 합의에 이를 때까지 반복하는데, 때로는 여섯 라운드까지 갑니다. 최근에는 개발 작업을 외부 작업용 박스로 넘기고, 로컬 머신은 오케스트레이터로만 남겨 두는 실험을 시작했습니다.

제가 버전 관리를 직접 건드리는 경우는 직접 테스트해 보려고 빌드를 체크아웃할 때, 또는 태그가 붙은 버전 릴리스를 만들 때뿐입니다. 각각 대략 일주일에 한 번, 한 달에 한 번 정도입니다. 그 외에는 이제 그냥 Claude에게 맡깁니다. 드래프트 PR을 적극적으로 활용하고, GitHub에서 쓸 수 있게 된 지금은 스택형 PR도 씁니다. PR이 열리기 전까지는 코드를 보지 않습니다. Bencher 코드는 여전히 훑어보긴 하지만, 이제는 제대로 된 코드 리뷰라기보다는 정상인지 확인하는 수준입니다.


1년 뒤에 돌아보며 여기 쓴 글을 다시 읽을 때, 저는 또다시 “AI 얘기는 한 마디도 안 했잖아‽” 하는 순간을 맞게 될까요? 제 절반은 그러면 얼마나 멋질까 생각합니다. 나머지 절반은 완전히 겁에 질려 있습니다.


Bencher: 지속적인 벤치마킹

Bencher는 지속적인 벤치마킹 도구 모음입니다. 성능 회귀가 사용자에게 영향을 미친 경험이 있나요? Bencher가 그런 일이 일어나는 것을 막을 수 있었습니다. Bencher를 이용하면 성능 회귀를 병합되기 전에 탐지하고 예방할 수 있습니다.

  • 실행: 완전히 동일한 베어 메탈 러너와 즐겨 사용하는 벤치마킹 도구를 사용하여 로컬 또는 CI에서 벤치마크를 실행합니다. bencher CLI는 베어 메탈에서 벤치마크 실행을 조율하고 결과를 저장합니다.
  • 추적: 벤치마크 결과를 시간이 지남에 따라 추적합니다. 소스 브랜치, 테스트 베드, 측정 기반의 Bencher 웹 콘솔을 사용하여 결과를 모니터링, 쿼리, 그래프로 만듭니다.
  • 캐치: 완전히 동일한 베어 메탈 하드웨어를 사용하여 로컬 또는 CI에서 성능 회귀를 잡아냅니다. Bencher는 최첨단, 사용자 정의 가능한 분석을 사용하여 병합되기 전에 성능 회귀를 탐지합니다.

단위 테스트가 기능 회귀를 방지하기 위해 실행되는 것처럼, 벤치마크는 Bencher와 함께 실행되어 성능 회귀를 방지해야 합니다. 성능 버그도 버그입니다!

성능 회귀를 잡아내기 시작하세요 - Bencher Cloud를 무료로 시도해보세요.

🤖 이 문서는 AI에 의해 자동으로 번역되었습니다. 정확하지 않을 수도 있고 오류가 있을 수도 있습니다. 오류를 발견하면 GitHub에서 문제를 열어주세요.