AI가 코드를 생성하는 실제 장면과의 첫 만남
작년에 저는 레거시 Spring Boot 마이크로서비스를 인수하면서 내부 사용자 인증 모듈을 OAuth 2.1로 이전해야 했습니다. 팀은 단 세 명뿐이었고, 제한 기간은 3주였다. 자연스럽게 AI 프로그래밍 도구(커서 + GPT-4)를 사용해 속도를 높이는 것도 생각했습니다. 처음에는 순조롭게 시작되었습니다: AI는 새로운 인증 필터, 토큰 저장 계층, 구성 클래스를 생성해 약 800줄의 코드를 작성했으며, 경로, 예외 처리, 일부 테스트를 포함했습니다.
하지만 통합 테스트 중에 문제가 발생했습니다: AI가 SecurityFilterChain 구성을 생성했고, 두 개의 @Order 주석이 충돌하여 일부 API 엔드포인트가 인증을 우회했습니다. 더 숨겨진 것은 JwtAuthenticationConverter에 있는 널 포인터인데, AI는 누락된 claims 필드를 처리하지 않습니다. 이 다섯 가지 문제를 해결하는 데 손으로 쓰는 것보다 더 오래 걸렸는데, 먼저 자신의 "사고방식"을AI이해해야 했기 때문입니다—습관적으로 Optional을 사용하지만 일관되지는 않습니다.
이 장면을 보고 깨달았다: AI 코딩에서 가장 큰 함정은 코드를 쓸 수 없다는 것이 아니라, 그 코드를 직접 신뢰할 수 있다고 잘못 믿는다는 점이다.
4 판단 방식을 진정으로 바꿔놓는 결론들
**첫째, 코드 검토는 건너뛸 수 없지만, 검토 주제가 변경되었습니다. ** 이전에 동료 코드를 검토했으며, 논리와 스타일에 중점을 두었습니다. 이제 AI 코드를 복습하며, 경계 조건, 예외 경로, 기존 시스템과의 암시적 결합에 초점을 맞추세요. AI는 "올바르게 보이는" 코드를 생성하는 데 매우 뛰어나지만, null, 아웃 오브 바운드, 타임아웃 같은 코너를 자주 놓칩니다. 나중에는 AI 코드를 병합하기 전에 세 가지 유형의 질문을 구체적으로 확인했습니다: 1) 모든 입력 및 출력 매개변수에 대한 영 가정이 아닌 가정; 2) 모든 분기 조건에 대한 기본 동작; 3) 모든 비동기 연산의 타임아웃 및 재시도.
**둘째, 마이그레이션 작업은 완전히 다시 작성하지 않고 단계별로 교체해야 합니다. ** OAuth 마이그레이션 중 제가 저지른 가장 큰 실수는 AI가 전체 모듈에 대해 한 번에 교체 코드를 생성하게 한 것이었습니다. 더 나은 방법은 다음과 같습니다: 먼저 AI가 신규 및 구 인증 모두에 호환되는 '프록시 필터'를 생성하여 점차 트래픽을 줄이고; 각 단계는 롤백 포인트로 이전 코드를 유지합니다. 이 교훈을 배우는 데 이틀 동안 초과 근무를 했습니다.
**셋째, 프롬프트 구조는 출력 품질에 직접적인 영향을 미칩니다. ** 단순히 "OAuth 2.1 구성 생성"을 쓰는 것이 아닙니다. 나중에 세 부분으로 나누는 프롬프트를 수정했습니다: 1) 문제 맥락(프레임워크 버전, 기존 구조, 제약 조건)을 명확히 하기; 2) 특정 출력 형식(클래스 이름, 메서드 서명, 주석 스타일); 3) 피해야 할 함정(예: 폐기된 API를 사용하지 않거나 새로운 의존성을 도입하는 것). 효과가 크게 향상되어 오류율이 최소 40% 감소했습니다.
**넷째, AI는 "1에서 0.9까지"보다는 "0에서 1까지"에 더 적합합니다. ** 프로토타입, 비계, 데모 코드가 AI의 강점입니다; 하지만 기존 시스템에 미세한 수정을 해야 할 때, AI는 기존 논리를 쉽게 깨뜨릴 수 있습니다. 이제 사용 시나리오를 분리합니다: 새로운 기능 프로토타입은 AI를 사용하고, 기존 수정은 수동으로 유지됩니다.

함정이 밟고 길을 바로잡았다
가장 큰 함정: **AI에서 생성된 코드에 대해 독립적인 테스트 계층이 설정되지 않았습니다. ** 저는 AI에게 직접 코드를 생성하게 하고, 기존 테스트 스위트에서 실행하게 합니다. 하지만 AI에서 생성되는 코드는 종종 기존 테스트에서 다루지 않는 특수 모의 데이터나 구성을 필요로 합니다. 결과적으로 테스트는 통과했지만 통합은 실패했습니다. 해결책은 ai-generated/ 디렉터리를 생성하고, 먼저 그 디렉터리에 모든 AI 코드를 배치한 뒤, 독립적인 단위 테스트와 통합 계약 테스트를 작성한 뒤, 통과 후 메인 코드베이스에 병합하는 것입니다.
또 다른 함정: **과도한 신뢰 AI "설명". ** 제가 "왜 이런 걸 하냐?"고 물으면, AI는 합리적으로 들리는 이유를 제시하지만, 때로는 환상일 뿐입니다. AI가 @Transactional 전파 행동을 설명할 때, 그 추론은 오래된 Spring 5 동작에 기반하며, 프로젝트는 Spring 6의 Jakarta 네임스페이스를 사용합니다. 이제 공식 문서를 확인하거나 AI가 동시에 인용해야 합니다.

비슷한 작업을 하고 있다면, 가장 가치 있는 단계는 먼저 복사하는 것입니다
**"AI 코드 접근 체크리스트"**를 설정하고, AI에서 코드를 받을 때마다 다음 항목을 수동으로 확인하세요:
- 모든 외부 입력(매개변수, 환경 변수, 설정 파일)의 기본값이 합리적인가?
- 모든 예외 경로가 삼켜지나요(빈 캐치 블록이나 로그가 복구되지 않는가)?
- 모든 비동기 통화에 타임아웃 설정이 있나요(특히 네트워크 요청에 대해)?
- 생성된 코드가 프로젝트에 없는 새로운 의존성을 도입하나요(가져오기 및 빌드 파일 확인)?
- 코드 스타일이 팀의 기존 표준(들여쓰기, 명명, 주석 패턴)을 준수하는가?
모니터 옆에 모든 팀원의 명단을 게시했습니다. 2주 사용 후 온라인 실패율이 약 35% 감소했습니다.
언제 계속 투자하고 언제 방향을 바꿀지
지속적인 투자 조건: **접근 목록을 통과한 후 AI가 생성한 코드를 볼 때, 수정 양은 손글씨 부수의 30% 미만입니다. ** 만약 당신의 시나리오가 새로운 모듈을 만들고, 샘플 코드를 작성하고, 테스트 케이스를 작성하고, SQL이나 스크립트를 생성하는 것이라면—이것들은 AI의 안락한 영역이며, 계속 사용할 수 있습니다.
경로 변경 신호: **AI 코드를 작성 시간보다 두 배 이상 수정하거나, 세 가지 새로운 버그를 유발하는 버그 하나를 수정하세요. ** 예를 들어, OAuth 마이그레이션 과정에서 AI 구성을 디버깅하는 데 4시간을 썼지만 결국 포기하고 1.5시간 동안 스스로 다시 작성했습니다. 이 시나리오는 현재 작업이 AI의 능력 경계를 초과했음을 나타낸다—종종 레거시 시스템, 복잡한 맥락 의존성, 또는 비표준 구성을 포함한다.
명확히 멈춰야 할 두 가지 상황이 더 있습니다: 1) AI(복잡한 람다 사슬 또는 추상적 브리지 패턴)에서 생성되는 코드 로직을 이해할 수 없다; 2) AI에서 생성되는 코드에는 완전히 테스트할 수 없는 외부 의존성이 포함되어 있습니다(예: 모킹 없이 직접 서드파티 API를 호출하는 경우). 지금은 수작업으로 실행하는 것이 더 안전합니다.

아직 댓글이 없습니다