AI와 함께한 10만 줄의 Rust 개발을 통해 얻은 교훈 (2025)
요약
작성자는 AI 코딩 에이전트를 활용하여 Azure의 RSL을 현대화한 Rust 기반 multi-Paxos 합의 엔진을 구축하는 스트레스 테스트를 진행했습니다. 약 3개월의 기간 동안 10만 줄 이상의 코드를 작성했으며, 성능 최적화를 통해 초당 연산 횟수를 23K에서 300K로 대폭 향상시키는 성과를 거두었습니다.
핵심 포인트
- AI 코딩 에이전트(Claude Code, Codex CLI 등)를 활용한 전례 없는 개발 생산성 달성
- 코드 계약(code contracts)과 경량 스펙 주도 개발(spec-driven development)을 통한 코드 정확성 확보
- 현대적 하드웨어(NVM, RDMA)와 파이프라이닝을 고려한 Rust 기반 분산 시스템 구축
- CLI 기반의 AI 코딩 워크플로우가 비동기적 생산성 극대화에 효과적임
지난 몇 달 동안, 저는 실제 운영 환경 수준의 분산 시스템 (distributed systems)을 구축할 때 AI 코딩 에이전트 (AI coding agents)가 우리를 어디까지 이끌 수 있는지 스트레스 테스트를 진행해 왔습니다.
그 결과: Azure의 주요 서비스 대부분의 기반이 되는 Replicated State Library (RSL) [1]의 모든 기능을 구현할 뿐만 아니라, 이를 현대적인 하드웨어에 맞게 최신화한 Rust 기반의 multi-Paxos 합의 엔진 (consensus engine)을 만들어냈습니다.
전체 프로젝트에는 약 3개월이 소요되었으며, 약 4주 만에 10만 줄의 Rust 코드를 작성했고, 약 3주 만에 성능 최적화를 통해 초당 23,000회 (23K operations/sec)에서 초당 300,000회 (300K ops/sec)의 연산으로 성능을 끌어올렸습니다.
전례 없는 생산성 외에도, 저는 결정적인 역할을 했던 몇 가지 기술들을 발견했습니다. 이 포스트에서는 코드 계약 (code contracts)을 통한 정확성 보장, 경량 스펙 주도 개발 (spec-driven development) 적용, 그리고 공격적인 성능 최적화 추구에 관한 가장 가치 있는 학습 내용과 더불어, AI 지원 코딩의 미래에 대한 저의 희망 사항을 공유합니다.
왜 RSL을 현대화해야 하는가?
Azure의 RSL은 multi-Paxos 합의 프로토콜 (consensus protocol)을 구현하며 많은 Azure 서비스의 복제 (replication)를 위한 중추 역할을 합니다. 하지만 RSL은 10년도 더 전에 작성되었습니다. 견고하기는 하지만, 현대적인 하드웨어와 워크로드 (workloads)에 맞춰 진화하지는 못했습니다.
이 프로젝트를 시작하게 된 세 가지 주요 격차 (gaps)는 다음과 같습니다:
파이프라이닝 (Pipelining) 부재: 투표 (vote)가 진행 중일 때 새로운 요청이 대기해야 하므로 지연 시간 (latency)이 늘어납니다.
NVM 지원 부재: 비휘발성 메모리 (Non-volatile memory)는 이제 Azure 데이터 센터에서 흔히 사용되며, 커밋 시간 (commit time)을 획기적으로 줄일 수 있습니다.
제한적인 하드웨어 인식: RSL은 현재 Azure 데이터 센터에 널리 퍼져 있는 RDMA를 활용하도록 설계되지 않았습니다.
이러한 제한 사항들을 제거하면 현대적인 클라우드 워크로드와 AI 기반 서비스에 필수적인 현저히 낮은 지연 시간과 더 높은 처리량 (throughput)을 확보할 수 있습니다.
Rust와 AI 가속 개발 (AI-accelerated development)에 대한 저의 관심을 바탕으로, 저는 처음부터 현대적인 RSL 대안을 구축하기로 했습니다.
엄청난 생산성 향상
약 6주 만에 저는 AI를 활용하여 multi-Paxos, 리더 선출 (leader election), 로그 복제 (log replication), 스냅샷 (snapshotting), 그리고 구성 변경 (configuration changes)을 포함한 RSL의 전체 기능 세트를 아우르는 13만 줄 이상의 Rust 코드를 구현했습니다.
저는 GitHub Copilot, Claude Code, Codex, Augment Code, Kiro, Trae 등 사용 가능한 많은 AI 코딩 에이전트 (AI coding agents)를 활용했습니다. 저의 워크플로 (workflow)는 빠르게 진화했지만, 현재 저의 주요 동력은 Claude Code와 Codex CLI이며, VS Code는 차이점 확인 (diffs) 및 사소한 편집을 처리하는 데 사용됩니다.
CLI에서 코딩하는 것이 저의 생산성을 극대화하는 완벽한 비동기 흐름 (asynchronous flow)을 만든다는 것을 발견했습니다. 또한 간단한 심리적 트릭도 발견했습니다.
저는 Anthropic의 최대 요금제 (max plan)를 위해 월 100달러를 지불합니다. 이것은 강제 기제 (forcing function)가 되었습니다. 잠들기 전에 Claude로 코딩 작업을 시작하지 않으면 돈을 낭비하고 있다는 기분이 듭니다.
Codex CLI가 출시되었을 때, 저는 속도 제한 (rate limits)을 처리하기 위해 두 번째 ChatGPT Plus 구독을 추가했습니다. 하나는 월요일부터 수요일까지, 다른 하나는 목요일부터 일요일까지 사용하는 방식입니다.
코드 계약 (Code Contracts) — AI에 의해, AI를 위해
제가 가장 자주 받는 질문은 이것입니다: AI가 어떻게 Paxos처럼 복잡한 것을 올바르게 구현할 수 있는가?
테스트는 첫 번째 방어 계층입니다. 저의 시스템에는 이제 단위 테스트 (unit tests)부터 최소 통합 테스트 (minimal integration tests, 예: proposer + acceptor만 포함), 그리고 결함 주입 (injected failures)을 포함한 다중 복제본 전체 통합 테스트 (multi-replica full integration tests)에 이르기까지 1,300개 이상의 테스트가 포함되어 있습니다. 프로젝트 상태를 확인하세요.
하지만 진정한 돌파구는 AI 기반의 **코드 계약 (code contracts)**에서 나왔습니다.
코드 계약은 핵심 함수에 대한 사전 조건 (preconditions), 사후 조건 (postconditions), 그리고 *불변량 (invariants)*을 명시합니다. 이러한 계약은 테스트 중에 런타임 단언 (runtime asserts)으로 변환되지만, 성능을 위해 프로덕션 빌드 (production builds)에서는 비활성화할 수 있습니다. 제가 이 접근 방식을 .NET [2]와 함께 오래전부터 사용해 오긴 했지만, AI는 계약을 훨씬 더 강력하게 만들었습니다.
제가 세 가지 수준에서 이를 적용하는 방법은 다음과 같습니다:
1. AI에게 계약을 작성하도록 요청하기. Opus 4.1은 좋은 계약을 작성하지만, GPT-5 High는 탁월한 계약을 작성합니다. 저는 검토하고 다듬는 데 집중합니다. 예를 들어, process_2a
메서드(Paxos의 2a 단계 메시지 처리)에는 다음을 포함하여 **16개의 계약 (contracts)**이 있습니다:
2. 계약으로부터 테스트 생성. 계약이 정의되면, 저는 AI에게 각 사후 조건 (post-condition)에 대한 타겟팅된 테스트 케이스를 생성하도록 요청합니다. AI는 이 작업에 매우 뛰어나며, 의미 있는 엣지 케이스 (edge cases)를 자동으로 생성합니다.
3. 계약을 위한 속성 기반 테스트 (Property-based tests). 제가 가장 좋아하는 방식입니다. AI는 계약을 속성 기반 테스트로 변환하여, 무작위 입력 (randomized inputs)의 방대한 공간을 탐색합니다. 어떤 계약 위반이라도 발생하면 패닉 (panic)을 트리거하여, 심층적인 버그를 조기에 노출합니다.
예를 들어, AI가 생성한 하나의 계약이 미묘한 Paxos 안전성 위반 (safety violation)을 발견했습니다:
그 단 하나의 계약이 프로덕션에 배포되기 훨씬 전에, 심각한 복제 일관성 (replication consistency) 문제로 이어질 수 있었던 상황을 방지했습니다.
경량 사양 주도 개발 (Lightweight Spec-Driven Development)
저는 다양한 사양 주도 개발 (Spec-Driven Development, SDD) 도구들을 시도해 보았습니다. 실제로 초기 컴포넌트들(리더 선출 (leader election), proposer, acceptor, learner 등)은 모두 엄격한 SDD 접근 방식을 따라 구현되었습니다. 저는 요구사항 마크다운 (requirement markdown)으로 시작하여, 이를 설계 마크다운 (design markdown)으로 바꾸고, 다시 작업 목록 마크다운 (task list markdown)으로 변환하곤 했습니다. 하지만 점차 이 과정이 너무 경직되어 있다는 것을 깨달았습니다. 진행 과정에서 변경 사항을 반영하고 모든 문서의 일관성을 유지하는 것이 골칫거리가 되었습니다.
이제 저는 더 경량화된 접근 방식으로 전환했습니다. 기능을 작업할 때(예: 스냅샷 생성 (snapshotting)), 저는 spec kit [3]의 /specify 명령어를 사용하여 사양 마크다운 (spec markdown)을 생성합니다. 이 사양은 몇 가지 사용자 스토리 (user stories)와 수락 기준 (acceptance criteria)으로 구성됩니다.
다음은 스냅샷 생성을 위한 사용자 스토리 예시입니다:
그 후 저는 /clarify 명령어를 사용하여 AI가 사용자 스토리와 기준을 스스로 비판하고 개선하도록 요청합니다. 또한 초기 사양에서 다뤄지지 않은 추가 사용자 스토리를 제안하도록 요청하기도 합니다. 저는 이 과정에 대부분의 시간을 할애합니다.
만족스러운 결과가 나오면, 저는 **계획 모드 (plan mode)**로 전환하여 AI에게 특정 사용자 스토리 (user story)에 대한 계획을 생성하도록 요청합니다. 오늘날 AI 코딩 에이전트 (coding agents)의 능력을 고려할 때, 단일 사용자 스토리는 에이전트가 효과적으로 관리할 수 있는 "최적의 (sweet spot)" 작업 단위처럼 느껴집니다. 이 과정에서 추가 사항이나 수정 사항을 발견할 수도 있는데, 이는 동일한 코딩 세션 내에서 쉽게 처리할 수 있습니다 (에이전트가 컨텍스트 (context)를 압축할 수도 있지만, 저는 보통 너무 많은 정보를 잃는 것에 대해 크게 걱정하지 않습니다).
다음은 설정 변경에 대한 /clarify 상호작용의 예시입니다:
● 질문 4: 시작 슬롯 결정
새로운 설정의 시작 슬롯을 종료 슬롯 (ending slot)과 비교하여 어떻게 결정해야 합니까?
권장 사항: 옵션 A - 항상 정확히 ending_slot + 1
...
공격적인 성능 최적화 (Aggressive Performance Optimization)
성능 최적화는 AI가 진정으로 빛을 발하는 영역입니다. 초기 정확성을 확보한 후, 저는 순수하게 처리량 (throughput) 튜닝에만 약 3주를 보냈으며, 이때 AI는 성능 엔지니어링 (performance engineering)의 부조종사 (co-pilot)가 되었습니다.
반복적인 사이클을 통해, 우리는 단일 노트북에서 처리량을 약 23K ops/sec에서 약 300K ops/sec로 끌어올렸습니다. 제가 반복적으로 수행한 루프는 다음과 같습니다:
- AI에게 모든 코드 경로에 걸쳐 지연 시간 (latency) 메트릭 (metrics)을 계측 (instrument)하도록 요청합니다.
- 성능 테스트를 실행하고 트레이스 로그 (trace logs)를 출력합니다.
- AI가 지연 시간 분석 (latency breakdowns)을 수행하도록 합니다 (AI는 분위수 (quantiles)를 계산하고 병목 현상 (bottlenecks)을 식별하기 위해 Python 스크립트를 작성합니다).
- AI에게 최적화 방안을 제안하도록 요청하고, 하나를 구현한 뒤, 다시 측정하고, 이 과정을 반복합니다.
이 프로세스를 통해 제가 놓쳤을 수도 있는 통찰력들을 발견할 수 있었습니다. 예를 들어, 비동기 (async) 경로에서의 락 경합 (lock contention), 불필요한 메모리 복사 (redundant memory copies), 그리고 불필요한 태스크 생성 (unnecessary task spawns) 등이 그것입니다.
Rust의 안전 모델 (safety model) 덕분에 이러한 최적화들을 확신을 가지고 밀어붙일 수 있었습니다. 주요 개선 사항은 할당 (allocations) 최소화, 제로 카피 (zero-copy) 기술 적용, 락 (locks) 회피, 그리고 선택적인 비동기 오버헤드 (async overhead) 제거에서 나왔습니다. 각 개선 단계는 메모리 오염에 대한 두려움 없이, 고성능 엔진에서 지연 시간이라는 껍질을 한 겹씩 벗겨내는 듯한 기분이었습니다.
AI 지원 코딩을 위한 위시리스트 (Wish List for AI-Assisted Coding)
저의 여정을 되돌아보며, AI가 어디에서 더 많은 가치를 제공할 수 있을지 계속 고민하게 됩니다. 다음은 제 위시리스트(Wish List)에 있는 항목들입니다:
엔드 투 엔드 사용자 스토리 실행 (End-to-End User Story Execution): 저는 여전히 사용자 스토리(User Story)를 직접 정의하는 것을 선호합니다. 아키텍트(Architect)로서 제가 무엇을 만들고 있으며, 그것을 어떻게 만들고 싶은지에 대해 더 나은 감각을 가지고 있다고 느끼기 때문입니다. 하지만 완벽한 실행을 전달하는 것은 AI가 점점 더 잘 처리할 수 있는 영역이라고 믿습니다. 현재로서는 AI가 멈췄을 때 계속하라고 말하거나, 리팩터링(Refactoring)을 제안하고, 테스트 커버리지(Test Coverage)를 검토하며, 추가 테스트를 제안하는 등 AI를 유도하는 데 여전히 상당한 시간을 소비해야 합니다. 저는 AI가 이러한 엔드 투 엔드 과정을 주도할 수 있도록 더 많은 자율성(Autonomy)을 갖기를 바랍니다.
자동화된 계약 워크플로 (Automated Contract Workflows): 계약(Contract)을 적용하는 흐름은 상당 부분 자동화가 가능해 보입니다. 저는 여전히 계약을 검토하고 제안을 하고 싶지만, 나머지 부분은 AI가 주도하기를 바랍니다. 즉, 계약을 기반으로 테스트를 생성하고, 개별 테스트 케이스를 디버깅(Debugging)하며, 테스트와 계약 사이의 일관성을 보장하고, 속성 기반 테스트(Property-based Tests)를 작성하는 일들입니다. 테스트가 실패했을 때, AI가 사소한 문제들을 자동으로 디버깅하고 수정하며, 계약이나 구현(Implementation)에 진정한 정답성(Correctness) 문제가 있을 때만 저에게 알림을 주기를 바랍니다.
자율적 성능 최적화 (Autonomous Performance Optimization): 성능 튜닝(Performance Tuning)은 더 많은 자동화가 이루어질 준비가 된 것으로 보입니다. 제가 해온 작업의 상당 부분은 반복적이고 병렬화(Parallelizable)가 가능합니다. AlphaEvolve (또는 OpenEvolve)와 같은 프로젝트들이 이 방향에서 가능성을 보여주고 있습니다. 이상적으로는 제가 잠재적인 최적화 경로를 제안하면, AI가 완전히 스스로 실험을 실행하는 방식입니다. 현재의 도구들은 작은 코드 덩어리들을 다루지만, 유사한 기술을 엔드 투 엔드 측정(End-to-end Measurement)과 함께 더 큰 코드베이스(Codebase)에 적용하는 것도 가능해 보입니다.
부록: 프로젝트 상태 (Appendix: Project Status)
이 프로젝트의 씨앗은 Microsoft Research의 Jay Lorch [4]가 작성한 우아한 디자인 마크다운(Design Markdown)입니다. 이 디자인은 multi-Paxos의 모든 구성 요소를 크게 단순화하여, 구현하고 추론하기 더 쉽게 만들어 줍니다.
지금까지 3가지 RSL의 한계점 중 2가지가 해결되었습니다: 파이프라이닝 (pipelining)과 NVM 지원 (Jay는 OSDI 2025에서 발표된 PoWER Never Corrupts 논문 [5]에 게시된 NVM용 완전 검증된 지속성 로그 (persistence log)를 통합했습니다). RDMA 지원은 아직 미정 (TBD)입니다.
현재까지 이 프로젝트는 13만 줄 이상의 Rust 코드로 성장했으며, 1,300개 이상의 테스트가 코드베이스의 65% 이상을 차지하고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기