
AI가 작성한 코드로 인해 실제로 망가진 5가지 사례. 반년 운영을 통해 알게 된 NG 사례와 해결 방법
요약
AI를 활용한 코딩 과정에서 발생하기 쉬운 5가지 안티 패턴과 그 해결 방법을 제시합니다. 유지보수성을 해치는 잘못된 주석, 과도한 추상화, 거대 함수, 예외 무시, 테스트 부재의 위험성을 경고합니다.
핵심 포인트
- 코드의 내용을 반복하는 주석 대신 '왜(Why)'를 설명하는 주석을 남길 것
- 성급한 공통화보다는 중복을 허용하며 필요할 때 추상화할 것
- 함수는 책임에 따라 작게 나누어 유지보수성을 확보할 것
- 에러를 무시하는 try/catch 대신 명확한 로그와 반환을 사용할 것
- AI의 구현을 맹신하지 말고 반드시 테스트 코드를 작성할 것
먼저 목록부터. AI에게 8할을 쓰게 하고 반년 동안 운영해 보면서, 실제로 망가진(腐った) 작성 방식 5가지를 NG 사례와 해결 방법으로 나열합니다. 모두 "AI가 쓰기 쉬운" 방식이며, 그대로 두면 나중에 유지보수(Maintenance)를 할 수 없게 되는 것들입니다.
- 코드를 말로 바꿔 쓰기만 하는 주석을 남발함
- 너무 빠른 공통화·추상화 (Abstraction)
- 거대한 하나의 함수 상태로 방치함
- 에러를 무시하는 try/catch
- 테스트 없이 AI의 구현을 신뢰함
위에서부터 순서대로 나쁜 예, 좋은 예, 이유를 작성하겠습니다.
AI는 부탁하면 얼마든지 주석을 작성합니다. 하지만 그 대부분은 코드를 일본어로 바꿔 쓴 것에 불과합니다.
// ❌ NG: 코드를 읽으면 알 수 있는 내용을 주석으로 반복함
// 사용자 ID를 취득한다
$user_id = get_current_user_id();
...
// ✅ OK: '왜' 그렇게 하는지만 남김
// 관리자라도 「자신의 게시물만」 나오게 하는 사양이라 author로 필터링함
$posts = get_posts(['author' => get_current_user_id()]);
이유: 바꿔 쓰기식 주석은 구현을 변경할 때마다 낡은 정보가 되어 코드와 어긋나게 됩니다. 반년 뒤에는 도움을 주기는커녕 거짓 지도가 됩니다. 남긴다면 「왜(Why)」만 남기세요. 무엇을 하고 있는지는 코드가 말해줍니다.
AI는 "공통화해 두었습니다"를 선호합니다. 단 두 곳이 비슷할 뿐인데도 추상적인 기저 클래스(Base Class)나 범용 함수를 만들고 싶어 합니다.
// ❌ NG: 아직 2곳뿐인데, 범용화하여 분기로 흡수
function render_box($type, $data) {
if ($type === 'notice') { /* ... */ }
...
// ✅ OK: 중복을 허용하고, 우선은 솔직하게 각각 작성함
function render_notice($data) { /* ... */ }
function render_error($data) { /* ... */ }
...
이유: 너무 빠른 추상화는 예상하지 못한 케이스가 왔을 때 맞지 않게 되고, 그렇다고 다시 떼어내는 것도 어려워집니다. 중복을 하나 허용하는 편이 변경하기에 가볍습니다. 공통화는 「3번째」부터 생각하는 정도가 딱 적당했습니다.
AI는 하나의 함수에 처리를 크게 몰아넣어 작성합니다. 동작하기 때문에 그대로 두기 쉽습니다.
// ❌ NG: 취득·검증·정형·저장·통지를 하나의 함수에 전부
function handle_submit($request) {
// 입력값 추출
...
// ✅ OK: 책임에 따라 작게 나눔
function handle_submit($request) {
$data = validate_input($request);
...
이유: 큰 덩어리는 어디를 바꾸면 무엇이 망가질지 읽을 수 없어서, 반년 뒤에 건드리는 것이 무서워집니다. 작게 나눈 함수만이 나중에 두려움 없이 고칠 수 있었습니다. 이름이 붙는 만큼 읽을 때의 단서도 됩니다.
AI는 우선 동작시키기 위해 예외(Exception)를 통째로 삼켜버리는 코드를 쓰기 쉽습니다.
// ❌ NG: 삼켜버리고, 아무 일도 없었던 것처럼 만듦
try {
$result = $client->request($payload);
...
// ✅ OK: 삼키지 않고, 기록하여 호출 측에 반환함
try {
$result = $client->request($payload);
...
이유: 삼켜버린 예외는 운영 환경에서 "왜인지 모르겠지만 동작하지 않는데, 에러도 뜨지 않는" 상황을 만듭니다. 원인을 볼 수 없는 버그는 가장 많은 시간을 잡아먹습니다. 실패는 지우지 말고, 보이는 형태로 남기세요.
AI의 출력은 동작하는 것처럼 보여도 사양(Specification)대로라고 단정할 수 없습니다. 테스트가 없으면 다시 작성할 때마다 동작이 조금씩 어긋납니다.
// ❌ NG: 동작하는 것처럼 보이므로, 테스트를 쓰지 않고 그대로 채택
$result = filter_comment($comment); // 아마 맞겠지, 하며 진행
// ✅ OK: 사양을 테스트로 고정한 뒤에 맡김
public function test_links_over_three_are_spam() {
$comment = ['comment_content' => 'http://a http://b http://c http://d'];
...
왜일까요. 구현은 AI에게 맡기더라도, 사양(Specification)과 테스트는 인간이 쥐고 있어야 합니다. 무너지지 않는 축이 하나 있으면, AI에게 몇 번을 다시 쓰게 하더라도 그 축을 기준으로 돌아올 수 있습니다. 반대로 사양까지 모호하게 맡겨버린 부분은, 반년 뒤에 "무엇이 옳은지 스스로도 모르겠다"는 상태가 되어 있었습니다.
- 주석은 "왜(Why)"만 작성한다. 코드의 말을 바꾸는 것은 삭제한다
- 공통화는 3번째부터 한다. 중복을 하나 허용하는 편이 더 가볍다
- 거대 함수는 책임에 따라 나눈다. 이름이 단서가 된다
- 에러는 묵인하지 않는다. 기록하고, 보이는 형태로 반환한다
- 사양과 테스트는 인간이 쥐고, 구현만 AI에게 맡긴다
모두 작성 직후에는 동작하기 때문에 알아차리지 못합니다. 부패하는 것은 반년 뒤입니다. "AI가 쓰기 쉬운 형태"를 알고, 생성된 직후에 수정해 두면 나중의 자신이 도움을 받습니다. 도움이 되었다면 저장해 두었다가, AI에게 코드를 작성하게 할 때 다시 확인해 보세요.
평소에는 raplsworks.com에서 WordPress 플러그인 개발이나 Claude Code 주변의 이야기를 쓰고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기