AI 코드 생성 모범 사례: 개발자 가이드
AI 어시스턴트를 활용하여 검증된 모범 사례와 워크플로우 패턴으로 더 빠르게 더 나은 코드를 작성하세요.
지시만 하지 말고 맥락을 제공하세요
가장 흔한 실패 유형은 이미 갖고 있는 코드를 보여주지 않은 채 코드를 요청하는 것입니다. 여러분의 스택, 컨벤션, 기존 패턴을 볼 수 없는 모델은 여러분의 아키텍처와 충돌하는 범용 코드를 만들어 냅니다.
같은 작업에 대한 두 프롬프트의 차이를 생각해 보세요. 개선 전: 환불 처리 함수를 작성해줘. 이렇게 하면 그럴듯하지만 범용적인 코드가 나오고, 에러 처리와 타입은 지어낸 것들입니다. 개선 후: 우리 Express API에서 PaymentGateway 래퍼를 통해 환불을 처리하는 TypeScript 함수를 작성해줘. 아래 refundService.ts의 구조를 따르고, 실패는 우리 AppError 클래스로 발생시키고, 내가 붙여 넣은 Zod 스키마로 입력을 검증해줘. 참조한 파일을 실제로 함께 제공한 두 번째 프롬프트는 최소한의 수정만으로 코드베이스에 들어가는 코드를 만들어 냅니다.
이를 부담 없이 습관화하는 방법:
- 새 모듈을 요청할 때마다 대표적인 기존 파일 하나를 붙여 넣어, 모델이 네이밍과 구조를 따라 하게 하세요. - 프레임워크, 데이터베이스, 런타임 등 스택과 버전을 명시하세요. 기본값은 버전마다 다릅니다. - 에러 처리와 로깅 컨벤션은 매번 리뷰에서 고치지 말고 세션마다 한 번씩 미리 알려주세요. - 함수 시그니처만이 아니라 비즈니스 규칙을 설명하세요. 엣지 케이스는 비즈니스 규칙 안에 살고 있습니다.
주니어 개발자의 코드처럼 리뷰하세요
AI가 생성한 코드는 실제로 올바른 경우보다 훨씬 자주 컴파일되고 관용적으로 보입니다. 유능하지만 감독받지 않는 주니어 개발자의 풀 리퀘스트를 다루듯이 다루세요. 모든 줄을 읽고, 모든 가정을 의심하고, 신뢰하기 전에 실행해 보세요. 의도적으로 점검할 가치가 있는 반복적인 버그 유형:
- 루프, 슬라이스, 페이지네이션 경계에서의 off-by-one 오류. - null과 undefined 처리, 특히 API 응답의 선택적 필드 주변. - 비동기 코드의 경쟁 조건: await되지 않은 프라미스, 공유 가변 상태, 누락된 락. - 미묘하게 잘못된 API 사용 — 실재하는 메서드를 잘못된 인자 순서로 호출하거나, 폐기 예정 오버로드를 쓰거나, 버전 간에 바뀐 기본값을 쓰는 경우. - 설정에서 가져와야 할 값이 하드코딩된 경우.
유용한 규율 하나: 병합하기 전에 생성된 각 함수가 무엇을 하는지 한 문장으로 설명해 보세요. 설명할 수 없다면 아직 리뷰하지 않은 것입니다.
환각된 API와 존재하지 않는 패키지
모델은 메서드, 옵션, 심지어 패키지 전체를 정기적으로 지어냅니다. 환각된 이름이 위험한 이유는 바로 그럴듯하기 때문입니다. 실재하는 두 라이브러리를 섞어 놓았거나, 다른 프레임워크에는 존재하는 메서드인 경우가 많습니다. 낯선 API 위에 코드를 쌓기 전에 공식 문서에서 확인하고, 주변 코드를 작성하기 전에 임포트부터 단독으로 시험해 보세요.
여기에는 실질적인 보안 문제도 있습니다. 공격자들은 AI 모델이 흔히 환각하는 이름으로 악성 패키지를 게시해 왔습니다. 타이포스쿼팅의 변종으로, 슬롭스쿼팅이라고도 불립니다. 어시스턴트가 제안했다는 이유만으로 패키지를 설치하지 마세요. 먼저 레지스트리 페이지, 다운로드 수, 메인테이너 이력, 가능하면 소스 저장소까지 확인하세요. 널리 공유되는 AI 코딩 세션 분석들에서 지어낸 패키지 이름은 이 점검이 가끔이 아니라 고정 습관이 되어야 할 만큼 자주 등장합니다.
보안 리뷰는 선택 사항이 아닙니다
생성된 코드는 화려하지 않은 보안 작업을 자주 빠뜨립니다. AI의 도움을 받은 모든 변경에서 다음을 명시적으로 점검하세요:
- 인젝션: 데이터베이스 쿼리는 문자열 연결이 아니라 반드시 매개변수화해야 하며, 셸 명령에도 동일하게 적용됩니다. - 시크릿: 모델은 프롬프트에 있던 API 키와 연결 문자열을 소스 파일에 태연하게 하드코딩합니다. 시크릿은 환경 변수나 시크릿 매니저에 보관하고, 실제 자격 증명을 절대 프롬프트에 붙여 넣지 마세요. - 입력 검증: HTTP 핸들러, 큐 컨슈머, 파일 파서 등 모든 경계가 악의적인 입력을 받는다고 가정하고, 생성된 코드가 이를 검증하는지 확인하세요. - 인가: 생성된 엔드포인트는 인증은 확인하면서 리소스별 인가는 건너뛰는 경우가 많습니다.
모델에게 자신의 출력에서 취약점을 찾으라고 요청하는 것은 가치 있는 2차 점검이며 실제 문제를 자주 잡아내지만, 사람의 리뷰와 정적 분석 도구를 보완하는 것이지 대체하는 것이 아닙니다.
재생성 대신 반복적으로 다듬으세요
출력이 대체로 맞다면 전체를 다시 돌리고 싶은 충동을 참으세요. 재생성은 이미 올바랐던 모든 것을 버리고, 검토되지 않은 새로운 변동성을 끌어들입니다. 대신 구체적인 결함을 지목하세요: 이 함수는 그대로 두고, items 배열이 비어 있으면 빈 summary 객체를 반환하는 가드만 추가해줘. 기능은 데이터 모델, 그다음 엔드포인트, 그다음 연결 순으로 단계적으로 만들고, 각 단계를 리뷰해서 이후 단계가 검증되지 않은 출력이 아니라 검증된 코드 위에 서게 하세요.
테스트를 먼저 작성하세요
테스트 주도 개발은 AI와 유난히 잘 어울립니다. 테스트를 직접 작성하거나, 생성했다면 혹독하게 리뷰해서 실제 요구사항을 담게 한 다음, 모델에게 그것을 통과하는 코드를 구현하게 하세요. 이렇게 하면 신뢰 문제가 뒤집힙니다. 불투명한 로직을 한 줄씩 감사하는 대신, 여러분이 통제하는 명세에 대해 동작을 검증하게 되는 것입니다.
같은 세션에서 같은 모델이 코드 이후에 생성한 테스트는 조심하세요. 그런 테스트는 코드가 해야 할 일이 아니라 코드가 하는 일을 검증하는 경향이 있어서, 여러분이 잡고 싶었던 바로 그 버그를 태연하게 단언해 버립니다. 최소한 생성된 테스트에서 빠진 엣지 케이스 — 빈 입력, 경계값, 에러 경로, 동시 접근 — 를 리뷰하세요.
AI 코드 생성을 쓰지 말아야 할 때
- 학습할 공개 코드가 거의 없는 새로운 알고리즘이나 틈새 도메인 — 출력 품질이 급격히 떨어지고 환각 비율이 올라갑니다. - 암호화나 인증 흐름 같은 보안 핵심 프리미티브: 생성된 구현 대신 검증되고 감사받은 라이브러리를 사용하세요. - 여러분이 평가할 자격이 없는 코드. 출력의 옳고 그름을 판단할 수 없다면 리뷰할 수 없고, 리뷰되지 않은 AI 코드는 부채입니다. - 모든 줄의 출처와 라이선스가 문제될 수 있는 컴플라이언스 민감 코드.
아키텍처의 주인은 사람입니다
모델은 그럴듯한 국소적 해법에 최적화되어 있을 뿐, 시스템의 장기적인 모습에 책임을 지지 않습니다. 서비스 경계, 데이터 흐름, 의존성 선택, 장애 모드에 관한 결정은 그 결과를 안고 살아갈 사람이 내려야 합니다. AI는 선택지를 탐색하고, 반론을 요청해 설계를 압박 테스트하고, 여러분이 정한 구조 안에서 구현하는 데 쓰세요. 하지만 결정 자체와 그에 대한 책임은 사람에게 남겨 두세요.
이 실천법들을 함께 도입하면 AI 코드 생성은 미묘한 결함의 원천에서 진짜 생산성 배수기로 바뀝니다. 초안 작성과 보일러플레이트에서는 실질적인 속도 향상을 얻으면서, 정확성은 여전히 코드를 병합하는 사람이 보장하는 것입니다.