에이전트 기반 리팩토링 3주: 결과의 신뢰성에 대해
요약
본 글은 coding agents를 사용한 리팩토링 과정에서 발생할 수 있는 검증 시스템의 근본적인 취약점을 다룹니다. 특히, editable-install finder와 같은 환경 설정 문제로 인해 실제 코드 변경 사항을 정확히 감지하지 못하는 사례를 발견했습니다. 효과적인 에이전트 기반 개발을 위해서는 단순히 코드를 생성하고 비교하는 것을 넘어, 로드된 구현의 출처(source)까지 추적하여 아키텍처의 무결성을 확보해야 함을 강조합니다.
핵심 포인트
- 에이전트 리팩토링 시 검증 시스템 자체의 오류가 치명적일 수 있다.
- editable-install finder 같은 환경 설정 문제를 통해 실제 코드 변경 사항이 은폐될 수 있다.
- 단순한 비교를 넘어, 로드된 모듈의 출처(source) 추적이 필수적이다.
- 에이전트 작업 시 목표 아키텍처와 인터페이스를 Git으로 정의하고 관리해야 한다.
우리는 coding agents를 사용하여 DATAMIMIC CE를 리팩토링하는 데 3주를 보냈습니다. 그리고 어느 순간, 우리의 검증 일부가 잘못된 코드를 테스트하고 있다는 것을 발견했습니다.
우리는 리팩토링이 기존 동작을 변경하지 않았는지 확인하기 위해 before/after 비교 기능을 구축했었습니다.
하지만 Python의 sys.meta_path에 등록된 editable-install finder가 최상위 패키지는 원본에서 왔음에도 불구하고 현재 checkout에서 서브모듈을 로드했습니다. 원래 구현으로 여겨졌던 부분이 부분적으로 새로운 코드를 실행하고 있었던 것입니다. 이 모듈들의 경우, 비교 기능이 우리가 밝혀내기를 바랐던 정확한 차이점들을 숨길 수 있었습니다.
우리는 영향을 받은 결과들을 VOID로 표시했습니다: 모든 931개의 XML 입력을 포괄하는 초기 파서 비교, 그리고 초기 직접 실행 및 서비스 결과를 포함하여 말입니다. 우리는 이들을 아카이브에 보관하고 설정을 수정했습니다. 방해되는 editable-install finder를 제거하고, 단순히 루트 패키지의 __file__뿐만 아니라 로드된 DATAMIMIC CE 서브모듈들의 출처를 확인하기 시작했습니다.
그것은 우리 잘못이었습니다.
우리는 coding agents가 실수를 하기 때문에 guardrails를 사용합니다. 하지만 검증 자체에 오류가 생기면 어떻게 될까요? 아키텍처 체크는 테스트 프로세스가 실제로 어떤 구현을 로드했는지 확립해주지 못합니다. 이 리팩토링의 대부분 과정에서, 코드를 생성하는 것이 무엇이 변경되어야 하는지를 결정하고 그 결과가 정확한지 확립하는 것보다 쉬웠습니다.
저는 수년 동안 DATAMIMIC을 개발해 왔습니다. 예를 들어, 우리의 DataSourceRegistry는 약 1,000줄로 성장했습니다. 런타임 컨텍스트, XML 구문, 스크립트 평가, 파일 형식, 데이터베이스 접근 등입니다. 한 곳에 너무 많은 것이 있었습니다.
우리는 Community Edition의 아키텍처를 Enterprise Edition과 일치시키고자 했고, coding agents가 리팩토링의 대부분을 담당하게 했습니다.
Agents는 제가 검토하는 것보다 더 빠르게 코드를 변경할 수 있습니다. 하지만 그들은 우리가 몇 년 전에 특정 결정을 내린 이유를 반드시 이해하지 못합니다.
각자 고유한 컨텍스트를 가진 여러 에이전트들이 별도의 세션에서 작업하면서, 작은 로컬 결정들이 아무도 동의하지 않은 상태로 아키텍처를 서서히 변경시킬 수 있습니다.
먼저 목표 아키텍처를 정의했습니다. 구성 요소, 책임, 허용되는 의존성 및 공개 인터페이스입니다. 에이전트와 제가 작업할 수 있는 버전 관리된 계약(contract)을 Git에 저장했습니다. ArchKeel은 실제 코드를 이 계약과 비교하여 확인합니다.

21 September부터 12 October 2026까지 선택된 36개의 Git 체크포인트 각각의 타일은 파이썬 파일을 나타내며, 이름 변경 식별자는 Git을 통해 추론됩니다.
저 자신이 ArchKeel을 개발했기 때문에 이것은 독립적인 평가가 아니었습니다. 저희는 이미 테스트를 진행했고 더 작은 실험들을 몇 번 실행했습니다. 저는 그 파이썬 지원 기능이 더 큰 코드베이스에 적합하다고 생각했습니다.
하지만 그렇지 않았습니다. DATAMIMIC은 우리가 보지 못했던 취약점과 엣지 케이스(edge cases)들을 노출시켰습니다. 타입 지정된 딕셔너리(Typed dictionaries), 콜백 타입(callback types), 상속된 메서드(inherited methods) 등이 문제였습니다. 그리고 결정 내리기에는 충분히 명확하지 않은 발견 사항들도 있었습니다.
때로는 문제가 DATAMIMIC에 있는지, 아키텍처 계약에 있는지, 아니면 ArchKeel에 있는지 즉시 알 수 없었습니다.
저희는 DATAMIMIC, 아키텍처 계약, 그리고 ArchKeel을 동시에 변경하고 있었습니다. 저는 ArchKeel 검증 작업이 얼마나 많은 노력이 필요할지 과소평가했습니다.
9월 25일, 로케일 오류 처리(locale error handling) 작업을 하던 에이전트가 내부 모듈에서 네 개의 임포트 구문을 도입했습니다:
from datamimic_ce.errors.factory import invalid_locale_error
임포트는 작동했습니다. 하지만 저희는 서비스가 공개 오류 인터페이스(public error interface)를 사용해야 한다고 명시적으로 결정했었습니다:
from datamimic_ce.errors import invalid_locale_error
ArchKeel은 네 개의 새로운 INTERFACES-ONLY 위반 사항을 보고했습니다. 저희는 임포트를 수정하고 검사를 다시 실행했습니다. 네 가지 위반 사항 모두 사라졌습니다. 계약이나 기준선(baseline)에는 변경이 없었습니다.
Original agent commit · Correction
커밋 후 변경 사항을 포착했습니다. 구현 에이전트는 집중 테스트(focused tests), 린트(lint) 및 타입 검사를 수행했고, 아키텍처 검사는 통합 단계에서 나중에 실행되었습니다. 이로 인해 우리의 에이전트 워크플로우에 공백이 생겼습니다. 즉, 이 검사가 에이전트가 커밋을 넘기기 전에 이루어져야 했습니다.
4개의 임포트는 큰 문제는 아닙니다. 하지만 합리적인 로컬 결정 하나가 합의된 경계를 넘어섰습니다.
규칙 자체에 대한 논의가 필요했던 경우도 있었습니다. 예를 들어, SQL 디스패치 경로(SQL dispatch path)는 우리의 광범위한 캐스트 금지(blanket cast ban)와 기존 동적 클라이언트 계약(dynamic-client contract) 간의 충돌을 노출했습니다. 우리는 호출자들을 확인하고 해당 계약을 유지하기 위해 좁은 예외를 문서화했습니다.
우리는 여전히 아키텍처에 도전해야 합니다. ArchKeel은 구현이 우리가 합의한 내용과 일치하는지 검사해야 합니다.
DATAMIMIC은 테스트 데이터 엔진입니다. 고객들은 기존 XML 모델을 가지고 있었고, 우리는 리팩토링이 그들의 동작을 조용히 변경하는 것을 원하지 않았습니다.
우리는 931개의 XML 입력을 고려해야 했습니다. 한 검토 지점에서 180개를 검토했습니다. 나머지 751개는 아직 미진행 상태였습니다.
입력들을 기존 테스트와 연결하고 결과를 기록한 다음, 증거가 누락된 곳에 집중 검사를 추가했습니다.
그리고 성공적인 실행, 예상되는 거부(expected rejections), 알려진 실패(known failures), 진단(diagnostics) 및 누락된 로컬 커버리지 사이를 구별해야 했습니다. 일부 그룹화된 부정 테스트(negative tests)가 시간 초과되었기 때문에, 우리는 이를 더 작은 검사로 분할했습니다.
결국 931개 입력 모두 증거 분류를 갖게 되었습니다. 이 중 874개는 두 개정판 모두에서 쌍을 이루는 증거(paired evidence)를 가졌으며, 여기에는 기존 오류가 동일한 12개가 포함되었습니다. 또 다른 8개는 리드백이 있는 성공적인 부모 실행으로 커버되었고, 1개는 승인된 동작 변경이었으며, 48개는 고정값(fixture) 또는 레거시 부채로 분류되었거나 모듈 수준의 CI 증거만 있었습니다. 기술 보고서에 전체 세부 내역이 보존되어 있습니다.
그것이 931개가 모두 성공적으로 재생되었다는 것을 의미하지는 않습니다. 저는 다양한 종류의 증거를 동일한 녹색 PASS로 만들고 싶지 않았습니다.
이러한 구분은 처음부터 발생했던 모듈 로딩 문제 이후 더욱 중요했습니다. 우리는 에이전트의 출력에 의문을 제기했지만, 우리 자신의 검증 설정에는 충분히 의문을 제기하지 않았습니다.
10월 12일, 저희는 리팩토링을 개발(development) 브랜치로 병합했습니다. ArchKeel 2.0.0은 관찰된 488개의 Python 파일(핵심 파일 471개, resources/ 아래 17개 포함)에서 0건의 선언된 아키텍처 위반을 보고했습니다.

승인된 개정판의 최종 CE 컴포넌트 구조.
최종 PR CI는 아키텍처 검사, 제품 테스트, 정적 분석(static analysis), 빌드 검사 및 시드 재현(seeded replay)을 포함하여 통과했습니다. 일부 브랜치 조건부 E2E(End-to-End) 및 릴리스 작업은 건너뛰어졌습니다.
여전히 아키텍처 UNKNOWN 기록이 286개 있었습니다: 상속된 메서드, 속성 바인딩(property bindings), 타입 별칭(type aliases)과 같은 해결되지 않은 사례들입니다. 이는 931개의 XML 입력과는 별개입니다.
이러한 항목들은 개별 에이전트 검토 작업(agent review tasks)을 통해 평가되었지만, 동일한 모델/제공자 생태계 내에서 이루어졌습니다. 이것은 독립적인 외부 검증(independent external verification)이 아닌 또 다른 검토 통과일 뿐입니다.
저희는 프로젝트 진행 중 승인 기준도 변경했습니다. 원래 게이트는 0개의 물질적 UNKNOWN 위치를 요구했습니다. 최종 게이트는 선언된 위반 사항이 0개이고, 나머지 알 수 없는 항목에 대한 문서화된 평가가 이루어지는 것을 받아들였습니다. 저는 해결되지 않은 분석기 사례(unresolved analyzer cases)에는 명시적인 검토가 필요하기 때문에 이 점을 받아들였습니다. 카운터를 0으로 강제하는 것은 검사기를 만족시키기 위해 유효한 Python 코드를 변경해야 함을 의미할 수 있기 때문입니다. 이러한 평가는 여전히 남아 있는 코드 의무를 기록하며, 알 수 없는 항목은 계속해서 알 수 없는 상태로 남습니다.
저희는 원래 게이트를 충족하지 못했습니다. 하지만 수정된 게이트는 충족했습니다.
코드베이스 크기 자체는 줄지 않았습니다. 핵심 Python 파일은 437개에서 471개로 늘어났고, 코드는 약 3.8% 증가했습니다. 여전히 일부 대형 모듈들은 개선이 필요합니다.
그렇다면 성공적이었을까요?
저는 책임 영역(responsibilities)과 경계(boundaries)가 더 명확해졌다고 생각합니다. 그리고 ArchKeel이 선언된 아키텍처에 반하는 의도치 않은 변경 사항을 포착한 구체적인 사례를 확보했습니다.
하지만 이것이 모든 아키텍처 결정이 올바르거나 기존의 모든 동작이 보존되었다는 것을 증명하지는 못합니다.
제가 유지하고 싶은 것은 계약(contract)과 그 결과에 대한 공유된 시각입니다. 저장된 결과물은 소스(source), 타겟(target), 분석기(analyzer)를 식별하므로, 에이전트의 요약에만 의존하기보다 검사 자체를 검토할 수 있습니다. 10월 8일에는 ArchKeel 1.0.0이 91개의 선언된 위반 사항을 보고했고, 10월 12일에는 ArchKeel 2.0.0이 0개를 보고했습니다. 이 사이에 검사기(checker)와 타겟이 변경되었기 때문에 깔끔한 전후 비교는 아닙니다. 그리고 0개라는 수치가 수용된 결론은 아니었습니다. 남아 있는 286개의 알려지지 않은 항목들은 여전히 명시적인 평가가 필요했습니다.

에이전트들이 우리를 더 빠르게 만들었을까요? 저는 모르겠습니다.
우리는 이 프로젝트에 3주를 썼지만, 그 시간의 일부는 ArchKeel 개발과 검증(verification) 수정에 사용되었습니다. 저희에게 통제 실행(control run)이나 완전한 비용 대장(cost ledger)이 없었고, 이러한 작업 흐름들을 충분히 분리하여 방어 가능한 비율을 제시할 수 없었습니다. 저는 그 효과들을 충분히 잘 분리할 수가 없어 생산성 향상을 주장하기 어렵습니다.
다음은 DATAMIMIC EE Core입니다. 저희는 공개된 ArchKeel 2.0.0으로 시작하여, 에이전트가 커밋을 넘기기 전에 아키텍처 검사를 실행하고 리팩토링 작업을 검사기 개발과 분리하여 추적할 것입니다. 우리가 배운 것들이 얼마나 전이되는지 보고 싶습니다.
저는 아키텍처에 도전하는 데 더 많은 시간을 쓰고, 검사기를 디버깅하는 데는 적은 시간을 쓰고 싶습니다.
기술 보고서(technical report)에 무효화된 결과, 남아있는 한계점 및 수용 변경 사항을 포함한 증거가 담겨 있습니다. 10월 12일부로 리팩토링은 병합되었지만, 아직 공개된 DATAMIMIC CE 릴리스의 일부는 아닙니다.
여러분의 가드레일(guardrails)은 어디서 실패했나요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기