DHH의 Campfire 재작성, AI로는 부족함을 드러내다
원제 I'm sorry, but you still have to think
109 포인트댓글 35
Key Point
AI 에이전트만으로는 아키텍처와 성능 트레이드오프를 올바르게 판단할 수 없으며, 프로그래밍은 여전히 깊은 이해와 비판적 사고를 요구한다는 점을 실제 사례로 보여준다.
핵심 요약
- DHH가 Ruby on Rails로 만든 Campfire를 Rust로 재작성했으며, Elixir, Go 등 다른 언어로도 재작성하도록 했는데 AI 에이전트에만 의존하면서 코드 직접 검토를 거부했다.
- 명확하지 않은 프롬프트는 후보 결정이 동전 던지기가 되는 문제를 드러냈다. 역하위 호환성, 지연시간 vs 처리량, 메모리 제한, 장애 후 알림 손실 용인 여부 같은 결정이 LLM에 의해 암묵적으로 내려진다.
- Rust 판본은 CSRF 토큰을 제거하고 Redis 대신 인메모리 큐를 썼지만, Elixir 판본은 Rails 원본에 훨씬 더 가깝다. 이런 차이는 언어 선택과 무관한 설계 결정이다.
- Elixir 판본은 단일 프로세스에서 SQL 쿼리를 순차 처리하는 문제가 있고, Rust 판본은 일부 DB 작업이 비동기가 아니어서 async 런타임의 협력적 스케줄링에서 성능 문제를 일으킨다.
- Zach Daniels가 측정한 결과 Rust 판본은 고부하에서 알림 배달 성공률이 1%에 불과했다. 벤치마크는 처리량만 측정했고 다른 시스템 속성을 무시했다.
- DHH와 Zach의 벤치마크는 폐쇄 루프 방식이었지만, 실제 부하는 동시 사용자들이 응답 대기 없이 행동할 때 발생한다. 동일한 이벤트 수를 비교하면 Rust는 6~7k 중 1%, Elixir는 ~1.7k 중 100%를 배달했다.
- Elixir 커뮤니티는 근본 원인을 이해하지 않고 Elixir가 동시성에서 우월하다고 결론 내렸지만, Elixir는 저수준 제어 부족, 높은 메모리 사용, 느린 속도라는 대가가 있다.
- 상수 배달률 테스트에서 Rust 판본은 100 POST/초에 약 14% 배달, Elixir는 약 60%였지만, Elixir는 23%의 HTTP 요청이 타임아웃됐다.
- Rust의 메시지 손실 원인은 broadcast 채널 용량이 256으로 제한되어 있었는데, 용량을 16384로 늘리면 14%에서 90%로 개선되지만 최악의 지연시간이 11초에서 130초 이상으로 증가한다.
- 높은 용량 설정 시 Elixir 판본은 100 req/초 테스트에서 1.8GB 메모리를 사용했다. 일부 메시지 손실이 나음과 OOM 살해 중 어느 것이 나은지는 트레이드오프 판단이다.
- 결론: 어떤 언어든 신중하게 사고해야 하며, 단일 지표에 기반해 성급한 결론을 내리면 안 되고, 시스템의 실패 모드와 트레이드오프를 이해해야 하며, 벤치마크는 어렵다.