지난 1년 동안 저는 Claude Code와 Codex를 사용하여 제품을 구축했습니다. 이 에이전트들은 코드를 작성하고 기능을 작동시키는 데 능숙했습니다. 하지만 그 기능들이 제품의 방향과 상황에 맞는지 결정하는 것은 여전히 제 책임이었습니다.
개발 속도가 빨라지면서 새로운 질문들이 생겨났습니다. 에이전트가 기능이 작동한다고 보고할 때, 얼마나 신뢰해야 할까요? 성장하는 코드베이스의 모든 줄을 현실적으로 읽을 수 없을 때, 무엇에 초점을 맞춰 검토해야 할까요?
1년 후 제가 내린 결론은 사람이 제품의 구조와 디자인 의도를 소유하고(own), 에이전트가 그 방향 안에서 구현하는 것입니다.
1. 최신 모델들이 의도 파악에 훨씬 뛰어나다
이전 모델들을 사용할 때는 제가 요청하지 않은 작업들이 자주 보였습니다. 한 기능에 대한 수정만 요청했는데도 에이전트가 다른 무언가를 변경한 것을 발견하는 경우가 있었습니다.
제 경험상 Astra 6와 Opus 5.5는 초기 모델들보다 요청의 맥락과 의도를 더 잘 이해했습니다. Luna나 Haiku 같은 더 빠른 모델, 그리고 Gemini를 사용하면서 저는 작업을 명시하고 그 경계(boundaries)를 명확히 설명하는 것이 더 신뢰할 수 있다는 것을 알게 되었습니다.
이것은 저의 개인적인 경험이며 일반적인 순위는 아닙니다. 성능은 모델 버전, 작업, 제공되는 맥락에 따라 달라집니다. 모델이 개선되더라도 무엇이 바뀌어야 하는지, 왜 바뀌어야 하는지, 그리고 범위가 어디서 끝나는지를 명확히 하는 것이 여전히 유용합니다.
2. 작동하는 기능이 반드시 의도된 기능은 아니다
요청을 이해하고 그것을 제품에 맞게 구현하는 것은 다른 어려움입니다. 에이전트는 기능을 작동시키고 테스트를 통과시키는 데 능숙하지만, 비즈니스 목표, 서비스의 현재 규모, 또는 미래 성장을 충분히 고려하지 않고 솔루션을 구현할 수 있습니다.
에이전트가 개발 및 코드 검토가 완료되었다고 보고한 후에도, 저는 데이터 흐름(data flow), 메모리 사용량(memory use), 잠재적인 데이터베이스 트랜잭션 충돌(potential database transaction conflicts), 그리고 아키텍처를 검사함으로써 문제를 발견했습니다. 이 문제들은 네 가지 범주로 분류되는 경향이 있었습니다:
- 중복 코드 및 불필요한 구현: 에이전트가 기존 인터페이스를 통해 문제를 더 간단하게 해결할 수 있었음에도 불구하고, 기능을 작동시키기 위해 별도의 구현을 추가합니다.
- 비용 및 성능 간과: 에이전트가 이미 메모리에 있는 데이터를 재사용하는 대신, 후속 실행에서 해당 데이터를 다시 로드합니다. 이는 비용과 지연 시간(latency)을 증가시킬 수 있으며, 결국에는 메모리 부족(out-of-memory) 오류로 이어질 수 있습니다.
- 코드와 문서의 불일치: 에이전트가 오래된 문서나 결함 있는 기존 코드를 신뢰하여, 원래 의도와 다른 무언가를 구축합니다.
- 유용한 검증을 제공하지 않는 테스트: 에이전트가 커버리지(coverage) 수치에만 초점을 맞추고, 기능의 실제 동작이나 중요한 실패 사례를 확인하는 데 실패하는 테스트 코드를 작성합니다.
테스트를 통과하고 에이전트의 완료 보고서를 받는 것은 유용한 신호입니다. 하지만 이것만으로는 설계가 적절하거나 올바른 문제가 해결되었음을 입증하지 못합니다. 여전히 누군가가 제품을 사용하고 중요한 데이터 흐름과 변경 사항의 영향을 검토해야 합니다.
3. 제품에 대한 소유권 유지하기 (Keep ownership of the product)
AI 코딩 에이전트가 개발 속도를 높임에 따라, 생성된 모든 라인을 검토하는 것이 점점 더 어려워집니다. 사이드 프로젝트라 할지라도 변경 사항을 따라잡는 데 상당한 시간이 걸릴 만큼 충분한 커밋(commit) 기록이 쌓일 수 있습니다.
이것이 판단을 포기한다는 의미는 아닙니다. 제 경험상, 에이전트는 명확한 전체 구조와 방향을 제시받았을 때 세부 사항을 잘 구현합니다. 우리의 역할은 코드의 양을 넘어 제품의 구조와 기능이 의도된 방향으로 진화하고 있는지를 질문하는 것입니다.
유용한 접근 방식은 코드 구조와 기능 동작을 다이어그램과 일반 언어로 표현한 다음, 이를 검토의 기반으로 사용하는 것이라고 생각합니다.
- 아키텍처 검토(Architecture review): 코드에서 파생된 다이어그램을 사용하여 전체 구조를 점검합니다. 서비스 및 도메인 경계가 적절한지 확인하고, 중복되거나 과도하게 추상화된 부분이 있는지 살펴봅니다.
- 기능 설계 검토(Feature design review): 새로운 기능의 흐름과 순서, 서비스 간 의존성, 그리고 도메인 경계를 문서로 작성합니다. 코드에 깊이 들어가기 전에, 해당 기능이 어떻게 작동해야 하는지, 그리고 왜 그렇게 설계되었는지 먼저 검토합니다.
다이어그램과 문서는 코드 검토를 대체하지 않습니다. 이들은 더 큰 맥락을 이해하고 좀 더 주의 깊게 살펴봐야 할 코드를 찾는 출발점을 제공할 뿐입니다. 또한 구현된 내용과도 대조하여 확인해야 합니다.
4. 제품을 이해하고 설계하는 실용적인 방법
Specify는 코드베이스로부터 제품의 아키텍처를 시각화하고, 개별 기능에 대한 개발 노트와 흐름 다이어그램을 생성하는 데 도움을 줄 수 있습니다. 이러한 뷰(view) 덕분에 코드를 한 줄씩 따라가기 전에 데이터가 어떻게 이동하고 처리되는지, 그리고 기능들이 어떻게 연결되는지를 더 쉽게 파악할 수 있습니다.
새로운 기능을 위해 저는 다음 순서를 사용합니다:
- 현재 구조 이해하기: 기존 아키텍처와 관련 기능을 검토하여 재사용 가능한 서비스 및 데이터를 식별합니다.
- 기능 설계하기: 기능이 속하는 도메인을 파악하고, 기존 서비스 및 데이터를 어떻게 사용할지 명시하는 PRD(Product Requirements Document)를 작성합니다.
- 구현 요청하기: 코딩 에이전트에게 검토된 방향과 제약 조건을 제공한 후, 해당 기능을 구현하도록 요청합니다.
- 결과 검토하기: 기능을 사용해보고, 데이터 흐름 및 변경된 구조를 설계 의도와 비교하며 중요한 코드와 테스트 케이스를 점검합니다.
- 의사 결정 기록하기: 향후 작업을 위해 설계 의도와 주요 결정을 개발 노트에 보관합니다.
에이전트가 기능을 구축하는 속도를 높임에 따라, 무엇을 만들지 그리고 제품이 어떻게 진화해야 할지를 결정하는 것이 더욱 중요해지고 있습니다. 현재 구조를 이해하고 디자인을 주도적으로 소유하는 것은 에이전트의 구현 속도를 제품 방향성에 맞춰 활용할 수 있게 만듭니다.
AI 코딩 에이전트가 작성한 코드에서 어떤 문제점들을 발견하셨나요? 작은 예시라도 환영합니다—댓글에 여러분의 경험을 공유해 주세요.