개발자가 다양한 AI 코딩 에이전트를 활용하여 구식화된 Azure의 분산 합의 엔진을 최신 하드웨어에 맞게 러스트(Rust)로 처음부터 다시 구현하며 극강의 생산성을 입증한 후기입니다. 10만 줄 이상의 코드가 약 한 달 만에 작성되었으며, 코드 계약(Code contracts)과 명세 기반 개발을 통해 복잡한 시스템의 정확성과 성능을 크게 향상시킨 구체적인 작업 방식을 공유합니다.
번역된 본문
지난 몇 달 동안, 저는 실제 프로덕션급 분산 시스템을 구축할 때 AI 코딩 에이전트가 어디까지 우리를 이끌어줄 수 있는지 한계를 테스트해 보았습니다. 그 결과물은 Azure의 RSL(Replicated State Library) [1] — 대부분의 주요 Azure 서비스를 뒷받침하는 라이브러리 — 의 모든 기능을 구현할 뿐만 아니라, 이를 오늘날의 하드웨어에 맞게 현대화한 Rust 기반의 멀티-Paxos 합의 엔진입니다. 이 프로젝트 전체에는 약 3개월이 걸렸습니다. 약 4주 만에 10만 줄의 Rust 코드가 작성되었고, 약 3주 만에 초당 2만 3천 건(23K ops/sec)이던 성능을 초당 30만 건(300K ops/sec)으로 최적화했습니다. 전례 없는 생산성을 경험하는 것은 물론이고, 이에 결정적인 역할을 한 여러 기법들을 발견했습니다. 이 글에서는 코드 계약(code contracts)을 통한 정확성 보장, 가벼운 명세 기반(spec-driven) 개발 적용, 공격적인 성능 최적화 추진 과정에서 얻은 가장 가치 있는 교훈을 공유하고, 더불어 AI 지원 코딩의 미래를 위한 저의 위시리스트를 다룹니다.
왜 RSL을 현대화해야 했나?
Azure의 RSL은 멀티-Paxos 합의 프로토콜을 구현하여 수많은 Azure 서비스의 복제를 담당하는 핵심 뼈대입니다. 하지만 RSL은 10년이 넘게 전에 작성되었습니다. 견고함에도 불구하고 현대의 하드웨어와 워크로드에 맞춰 발전하지 못했습니다. 이 프로젝트를 기획하게 만든 세 가지 주요 한계는 다음과 같습니다:
파이프라이닝(Pipelining) 부재: 투표가 처리 중일 때 새로운 요청은 대기해야 하므로 지연 시간이 늘어납니다.
NVM(Non-Volatile Memory) 미지원: NVM은 이제 Azure 데이터센터에서 흔히 사용되며 커밋 시간을 획기적으로 줄일 수 있습니다.
제한된 하드웨어 인식: 이제 Azure 데이터센터에 널리 보급된 RDMA를 활용하도록 RSL이 설계되지 않았습니다.
이러한 한계를 극복하면 상당히 낮은 지연 시간과 높은 처리량을 달성할 수 있습니다. 이는 현대적인 클라우드 워크로드 및 AI 기반 서비스에 매우 중요합니다. 저의 Rust 및 AI 가속 개발에 대한 관심을 고려하여, 최신 버전의 RSL 동등한 시스템을 밑바닥부터 구축해 보기로 했습니다.
대규모 생산성 폭발
대략 6주 만에 저는 AI를 활용하여 멀티-Paxos, 리더 선출, 로그 복제, 스냅샷 생성 및 구성 변경을 포함하여 RSL의 전체 기능을 아우르는 13만 줄 이상의 Rust 코드를 구현했습니다. GitHub Copilot, Claude Code, Codex, Augment Code, Kiro, Trae 등 사용 가능한 많은 AI 코딩 에이전트를 활용했습니다. 저의 워크플로는 빠르게 발전했지만, 현재 주된 동력은 Claude Code와 Codex CLI이며, VS Code는 diff 확인 및 사소한 편집을 담당합니다. CLI를 통한 코딩은 제 생산성을 극대화하는 완벽한 비동기 흐름을 만들어낸다는 것을 발견했습니다.
또한 간단한 심리적 트릭도 발견했습니다: 저는 Anthropic의 Max 플랜에 매달 100달러를 지불하고 있습니다. 이는 강력한 강제 기능이 되었습니다. 만약 잠자리에 들기 전 Claude에게 코딩 작업을 시작하지 않으면 돈을 낭비하는 기분이 들기 때문입니다. Codex CLI가 등장했을 때, 저는 속도 제한을 처리하기 위해 두 번째 ChatGPT Plus 구독을 추가했습니다. 하나의 구독은 월요일수요일에, 다른 하나는 목요일일요일에 사용합니다.
코드 계약 — AI에 의한, AI를 위한
제가 가장 자주 받는 질문은 다음과 같습니다: 도대체 AI가 Paxos처럼 복잡한 것을 어떻게 올바르게 구현할 수 있습니까? 테스트는 이에 대한 첫 번째 방어선입니다. 저의 시스템은 현재 1,300개 이상의 테스트를 포함하고 있습니다. 유닛 테스트부터 최소 단위의 통합 테스트(예: 제안자(proposer) + 수락자(acceptor)만 있는 경우)까지, 나아가 실패 상황이 주입된 여러 복제본의 전체 통합 테스트까지 포함됩니다. 프로젝트 상태를 참조하세요.
하지만 진정한 돌파구는 AI 기반 코드 계약에서 나왔습니다. 코드 계약은 중요한 함수에 대해 사전 조건(preconditions), 사후 조건(postconditions), 그리고 불변 조건(invariants)을 명시합니다. 이러한 계약은 테스트 중에는 런타임 어서트(assert)로 변환되지만, 성능을 위해 프로덕션 빌드에서는 비활성화할 수 있습니다. 예전에 .NET [2]과 함께 이 접근 방식을 사용하기 시작했지만, AI는 계약을 훨씬 더 강력하게 만들었습니다. 저는 이를 세 가지 수준에서 적용하고 있습니다:
AI에게 계약 작성을 요청합니다. Opus 4.1도 괜찮은 계약을 작성하지만, GPT-5 High는 훌륭한 계약을 작성합니다. 저는 리뷰하고 다듬는 데 집중합니다. 예를 들어, process_2a 메서드(Paxos에서 2a단계 메시지 처리)는 다음을 포함하여 16개의 계약을 가지고 있습니다:
계약으로부터 테스트를 생성합니다. 계약이 정의되면, AI에게 각 사후 조건에 대한 목표 테스트 케이스를 만들어달라고 요청합니다. AI는 이 작업에 탁월하며, 의미 있는 엣지 케이스를 자동으로 생성해 냅니다.
In the past few months, I’ve been stress-testing how far AI coding agents can take us when building real, production-grade distributed systems. The result: a Rust-based multi-Paxos consensus engine that not only implements all the features of Azure’s Replicated State Library (RSL) [ 1 ] — which underpins most major Azure services — but also modernizes it for today’s hardware. The entire project took me ~3 months, with 100K lines of Rust code written in ~4 weeks and performance optimization from 23K operations/sec to 300K ops/sec achieved in ~3 weeks. Besides unprecedented productivity, I discovered several techniques that were instrumental. This post shares my most valuable learnings on: ensuring correctness with code contracts, applying lightweight spec-driven development, and pursuing aggressive performance optimization — plus my wish list for the future of AI-assisted coding. Why Modernize RSL? Azure’s RSL implements the multi-Paxos consensus protocol and forms the backbone of replication in many Azure services. However, RSL was written more than a decade ago. While robust, it hasn’t evolved to match modern hardware and workloads. There are three key gaps motivated this project: No pipelining: When a vote is in flight, new requests must wait, inflating latency. No NVM support: Non-volatile memory is now common in Azure datacenters and can drastically reduce commit time. Limited hardware awareness: RSL wasn’t built to leverage RDMA, which is now pervasive in Azure data centers. Removing these limitations could unlock significantly lower latency and higher throughput — critical for modern cloud workloads and AI-driven services. Given my interest in Rust and AI-accelerated development, I set out to build a modern RSL equivalent from scratch. Massive Productivity Boost In roughly six weeks, I’ve driven AI and implemented over 130K lines of Rust code covering the full feature set of RSL, including multi-Paxos, leader election, log replication, snapshotting, and configuration changes. I utilized many available AI coding agents: GitHub Copilot, Claude Code, Codex, Augment Code, Kiro, and Trae. My workflow evolved quickly, but today my main drivers are Claude Code and Codex CLI , with VS Code handling diffs and minor edits. I’ve found that coding from the CLI creates a perfect asynchronous flow that maximizes my productivity. I also discovered a simple psychological trick: I pay $100/month for Anthropic’s max plan. This became a forcing function — if I don’t kick off a coding task with Claude before bed, I feel like I’m wasting money. When Codex CLI arrived, I added a second ChatGPT Plus subscription to handle rate limits — one subscription for Monday–Wednesday, the other for Thursday–Sunday. Code Contracts — By AI, For AI The question I get most often is: How can AI possibly implement something as complex as Paxos correctly? Testing is the first layer of defense. My system now includes 1,300+ tests — from unit tests to minimal integration tests (e.g., proposer + acceptor only), all the way to multi-replica full integration tests with injected failures. See the project status . But the real breakthrough came from AI-driven code contracts . Code contracts specify preconditions , postconditions , and invariants for critical functions. These contracts are converted into runtime asserts during testing but can be disabled in production builds for performance. While I started using this approach long ago with .NET [ 2 ], AI has made contracts vastly more powerful. Here’s how I apply them at three levels: 1. Ask AI to write contracts. Opus 4.1 writes good contracts, but GPT-5 High writes excellent ones. I focus on reviewing and refining. For example, the process_2a method (handling phase 2a messages in Paxos) has 16 contracts , including this one: 2. Generate tests from contracts. Once contracts are defined, I ask AI to create targeted test cases for each post-condition. It excels at this, generating meaningful edge cases automatically. 3. Property-based tests for contracts. This is my favorite. AI translates contracts into property-based tests, exploring a vast space of randomized inputs. Any contract violation triggers a panic, exposing deep bugs early. For instance, one AI-generated contract found a subtle Paxos safety violation: That single contract saved what could have been a serious replication consistency issue — well before it ever hits production. Lightweight Spec-Driven Development I’ve tried various Spec-Driven Development (SDD) tools. In fact, the earlier components (such as leader election, proposer, acceptor, and learner) were all implemented following a rigid SDD approach. I would start with a requirement markdown, turn it into a design markdown, and then a task list markdown. However, I gradually found this process too rigid; making changes along the way and ensuring all documents remained consistent became a headache. I’ve now switched to a more lightweight approach. When I work on a feature (e.g., snapshotting), I use /specify from spec kit [ 3 ] to generate a spec markdown. This spec consists of a few user stories and acceptance criteria. Here is an example user story for snapshotting: I then use /clarify to ask the AI to self-critique and improve the user stories and criteria. I also ask it to suggest additional user stories not covered in the initial spec. I spend the majority of my time here. Once satisfied, I jump into plan mode and ask AI to generate a plan for a specific user story. Given the capability of today’s AI coding agents, a single user story feels like the “sweet spot” unit of work they can manage effectively. Along the way, we may discover additions or tweaks, which are easy to handle in the same coding session (agents might compress context, but I typically don’t worry about losing too much). Here is a sample /clarify interaction for configuration changes: ● Question 4: Starting Slot Determination How should the starting slot for the new configuration be determined relative to the ending slot? Recommended: Option A - Always exactly ending_slot + 1 This ensures no gaps in the slot sequence and maintains continuity between configurations, preventing any slots from being orphaned or unassigned. | Option | Description | |--------|----------------------------------------------------------------| | A | Always exactly ending_slot + 1 | | B | Allow operator to specify any value > ending_slot | | C | Next multiple of 1000 after ending_slot for cleaner boundaries | | D | Same as ending_slot (both configs share final slot) | You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer. Aggressive Performance Optimization Performance optimization is where AI really shines. After ensuring initial correctness, I spent about three weeks purely on throughput tuning — and AI became my co-pilot in performance engineering. Through iterative cycles, we boosted throughput from ~23K ops/sec to ~300K ops/sec on a single laptop. Here’s the loop I followed repeatedly: Ask AI to instrument latency metrics across all code paths. Run performance tests and output trace logs. Let AI analyze latency breakdowns (it writes Python scripts to calculate quantiles and identify bottlenecks). Ask AI to propose optimizations, implement one, re-measure, and repeat. This process surfaced insights I might have missed — for example, lock contention on async paths, redundant memory copies, and unnecessary task spawns. Rust’s safety model made it easy to push these optimizations confidently. Key gains came from minimizing allocations, applying zero-copy techniques, avoiding locks, and selectively removing async overhead. Each improvement felt like peeling another layer of latency off a high-performance engine — without fear of corrupting memory. Wish List for AI-Assisted Coding Reflecting on my journey, I keep wondering where AI could deliver even more value. Here are some items on my wi