"AI가 개발자를 대체할까?" 이 질문은 이제 좀 지겹다. 2년 전에도 이 질문이었고, 지금도 이 질문이다. 그 사이에 실제로 바뀐 건, AI가 개발자를 대체한 게 아니라 AI가 작성한 코드가 우리 코드베이스에 들어오기 시작했다는 거다.
나는 매일 AI가 생성한 코드를 리뷰한다. 내가 AI 도구를 써서 만든 코드도 있고, 팀원이 AI 도움을 받아 작성한 코드도 있다. 여기서 발견한 건, AI가 코드를 잘 쓰느냐 못 쓰느냐의 문제가 아니라는 거다. 진짜 문제는 다른 곳에 있었다.
처음의 감탄, 그리고 의심
AI 코딩 도구를 처음 쓴 건 2024년쯤이었다. 에디터에서 주석을 쓰면 코드가 자동으로 완성되는 경험은 솔직히 경이로웠다. "// 배열에서 중복을 제거하고 정렬하는 함수"라고 쓰면 함수가 뚝딱 나왔다. 보일러플레이트 코드를 쓸 때는 체감 속도가 두세 배는 빨라졌다.
한 달 정도 열심히 썼다. 그러다가 한 가지를 알아챘다. AI가 생성한 코드가 "그럴듯하게 틀리는" 경우가 있다는 거다.
유틸 함수를 하나 만들었다. 날짜 범위를 받아서 해당 기간의 주말을 제외한 영업일 수를 계산하는 함수. AI가 생성한 코드는 깔끔했고, 변수명도 합리적이었고, 로직도 언뜻 맞아 보였다. 하지만 테스트를 돌려보니 공휴일이 주말과 겹치는 경우를 이중으로 차감하고 있었다.
여기서 핵심은, 코드만 봤을 때는 이 버그를 발견하기 어렵다는 거다. 문법 오류가 아니다. 변수명이 이상한 것도 아니다. 로직이 자연스럽게 읽힌다. 다만, 특정 엣지 케이스에서 결과가 틀릴 뿐이다. 인간이 직접 작성했다면 이런 엣지 케이스를 떠올리면서 쓰기 때문에 함께 처리했을 가능성이 높다. AI는 패턴 매칭으로 코드를 생성하기 때문에, 명시적으로 언급되지 않은 엣지 케이스를 놓치는 경향이 있다.
테스트를 통과하는 취약한 코드
더 무서웠던 건 보안 관련 사건이었다. 유저 입력을 받아서 서버에 전송하는 폼을 만들 때, AI가 제안한 코드를 거의 그대로 사용했다. 폼 밸리데이션도 깔끔하게 들어갔고, 에러 핸들링도 있었고, 테스트도 전부 통과했다.
코드 리뷰에서 시니어가 한 줄을 지적했다. 유저 입력값을 서버에 보내기 전에 sanitize를 하지 않고 있었다. 프론트엔드에서 XSS를 100% 막는 건 서버의 몫이지만, 클라이언트 측에서도 기본적인 입력값 정제는 해야 한다. 특히 innerHTML이나 dangerouslySetInnerHTML을 사용하는 경우라면.
AI는 이 코드를 생성할 때 보안을 고려하지 않았다. 기능적으로는 완벽했다. 유저가 폼을 채우고 제출하면 데이터가 서버에 잘 전달됐다. 테스트에서도 "올바른 입력이 올바르게 전송되는가"를 검증했으니 당연히 통과했다. 악의적인 입력을 넣는 테스트는 내가 작성하지 않았고, AI도 제안하지 않았다.
Addy Osmani가 AI 코딩에 대해 쓴 글에서 "AI가 생성한 코드를 주니어 개발자의 코드처럼 리뷰해야 한다"는 취지의 이야기를 한 적이 있다. 처음에는 좀 과한 비유라고 생각했는데, 이런 경험을 직접 하고 나니 정확한 표현이었다. 주니어가 작성한 코드가 그렇듯이, AI 코드도 기능은 동작하지만 경험에서 오는 방어적 코딩이 빠져 있는 경우가 많다.
미묘한 성능 문제들
보안만이 아니다. AI가 생성한 코드에서 반복적으로 보이는 패턴 중 하나가, 기능은 맞지만 성능이 미묘하게 나쁜 코드다.
리스트 컴포넌트를 만들 때, AI가 생성한 코드에서 filter와 map을 체이닝하는 경우가 많았다. 배열을 두 번 순회하는 거다. 데이터가 10개일 때는 체감이 안 되지만, 1,000개일 때는 다르다. reduce 한 번으로 같은 결과를 낼 수 있는데, AI는 가독성이 좋은 체이닝 패턴을 선호하는 것 같았다.
렌더링 최적화도 빠지는 경우가 잦았다. AI가 생성한 React 컴포넌트에서 useMemo나 useCallback이 필요한 곳에 빠져 있거나, 반대로 불필요한 곳에 과하게 들어가 있는 경우를 여러 번 봤다. 이건 AI가 "이 컴포넌트가 얼마나 자주 리렌더링되는가"라는 런타임 맥락을 모르기 때문이다. 코드의 정적인 구조만 보고는 판단할 수 없는 영역이다.
한 번은 AI가 생성한 코드가 API를 불필요하게 두 번 호출하는 걸 발견했다. 첫 번째 호출로 데이터를 받아와서 상태에 저장하고, 다른 컴포넌트에서 같은 데이터가 필요한데 상태를 공유하는 대신 같은 API를 한 번 더 호출하고 있었다. 이것도 "동작"은 했다. 유저 입장에서 결과는 같다. 하지만 서버 비용과 응답 시간 측면에서는 확실히 나쁜 코드였다.
새로운 기술: 읽기의 비중이 달라졌다
AI 도구를 쓰기 전에는, 개발 시간의 대부분이 "코드를 쓰는 것"이었다. 생각하고, 타이핑하고, 디버깅하고. AI 이후에는, "코드를 쓰는 시간"이 줄고 "코드를 읽고 평가하는 시간"이 늘었다.
이건 근본적인 변화다. 코드를 처음부터 쓰면, 쓰는 과정에서 맥락이 머릿속에 남는다. 왜 이 변수가 여기 있는지, 왜 이 조건문이 필요한지, 이미 알고 있는 상태에서 다음 줄을 쓴다. 하지만 AI가 생성한 코드를 읽을 때는, 그 맥락을 역으로 추론해야 한다. "이 코드가 왜 이렇게 되어 있지?"를 매 줄마다 질문해야 한다.
이게 예전에 복붙 코드를 이해하는 것과 비슷하면서도 다른 점이 있다. Stack Overflow 코드는 10줄, 20줄 단위다. 하지만 AI는 파일 전체를, 때로는 여러 파일에 걸쳐서 코드를 생성한다. 읽고 평가해야 할 양이 비교할 수 없이 많다.
그래서 요즘 가장 중요해진 기술이 "빠르고 정확하게 코드를 읽는 능력"이다. 전체를 한 줄씩 꼼꼼히 읽을 시간은 없다. 위험한 패턴을 빠르게 캐치하고, 나머지는 테스트로 커버하는 전략이 필요하다. 어디에 집중해서 읽어야 하는지를 아는 것 자체가 기술이 됐다.
AI에게 맡기면 안 되는 것들
몇 달간 AI 코드를 리뷰하면서 나름의 기준이 생겼다.
AI에게 맡겨도 되는 것: 보일러플레이트, CRUD 로직, 간단한 유틸 함수, 테스트 코드의 초안, 정규표현식 같은 것들. 패턴이 명확하고, 정해진 규칙을 따르면 되는 작업. 이런 건 AI가 나보다 빠르고, 품질도 충분하다.
AI에게 맡기면 안 되는 것: 인증/인가 로직, 결제 관련 코드, 복잡한 상태 머신, 성능에 민감한 코드, 비즈니스 로직의 핵심 부분. 이런 건 도메인 맥락을 깊이 이해해야 하고, 한 줄의 실수가 큰 사고로 이어질 수 있다. AI가 초안을 잡아주더라도, 처음부터 끝까지 내가 다시 쓰는 수준으로 검토한다.
AI가 잘 하지만 확인이 필요한 것: API 호출 레이어, 폼 밸리데이션, 라우팅 설정, 에러 핸들링. 이런 건 80%는 AI가 잘 하지만, 나머지 20%에서 프로젝트 특화된 요구사항이 빠지는 경우가 있다. AI의 결과물을 시작점으로 삼되, 꼭 검증한다.
팀에서 AI 코드를 다루는 방식
우리 팀에서는 최근 AI 도구 사용에 대해 몇 가지 그라운드 룰을 정했다.
첫째, AI가 생성한 코드도 작성자에게 책임이 있다. "AI가 이렇게 써줬는데요"는 코드 리뷰에서 유효한 변명이 아니다. PR을 올린 사람이 그 코드를 이해하고 있어야 한다.
둘째, AI가 생성한 코드에는 반드시 테스트가 있어야 한다. 엣지 케이스를 포함해서. AI가 테스트를 생성해줄 수도 있지만, 테스트 케이스의 설계는 사람이 해야 한다. "어떤 상황을 테스트해야 하는가"를 결정하는 건 아직 사람의 영역이다.
셋째, 보안에 민감한 코드는 AI 생성 여부와 관계없이 시니어가 리뷰한다. 이건 원래도 그랬지만, AI 이후로 더 엄격해졌다. AI가 생성한 코드가 "그럴듯하게" 보이기 때문에 오히려 리뷰어의 주의력이 떨어질 수 있다는 걸 경험으로 알았다.
개발자의 역할이 바뀌고 있다
코드를 직접 타이핑하는 비중은 확실히 줄었다. 그 자리를 "코드를 설계하고, 생성하고, 검증하는" 활동이 채우고 있다. Addy Osmani가 언급한 "70% 문제"라는 개념이 와닿는다. AI가 일상적인 코딩의 70%를 처리할 수 있더라도, 나머지 30% — 아키텍처 결정, 도메인 이해, 엣지 케이스 파악, 보안 고려 — 가 프로덕트의 품질을 결정한다.
어쩌면 개발자의 역할이 "코드를 쓰는 사람"에서 "코드의 품질을 보장하는 사람"으로 옮겨가고 있는 건지도 모른다. 직접 쓰든, AI가 쓰든, 최종적으로 코드베이스에 들어가는 코드에 대한 판단은 인간이 해야 한다. 적어도 지금은.
이게 좋은 방향인지는 솔직히 모르겠다. 직접 코드를 쓰면서 얻는 깊은 이해가 줄어드는 건 분명하다. 주니어 개발자들이 AI에 의존해서 코드를 생성하면, "왜 이렇게 동작하는지"를 이해할 기회가 줄어들 수 있다. 이건 장기적으로 업계 전체의 기술력 하락으로 이어질 수 있다는 우려가 있다.
반면에, 반복적인 코딩에서 해방되면서 더 높은 수준의 문제에 집중할 수 있게 되는 것도 사실이다. 보일러플레이트 때문에 시간 쓰는 대신, 아키텍처를 고민하고, 유저 경험을 개선하고, 성능을 최적화하는 데 시간을 쓸 수 있다.
정답은 아마 중간 어딘가에 있을 거다. AI를 거부하는 것도, 맹신하는 것도 답이 아니다. 도구로서 잘 활용하되, 내 기술을 녹슬게 하지 않는 균형점을 각자 찾아야 한다. 그 균형점은 사람마다, 팀마다, 프로젝트마다 다를 거다.
확실한 건 하나다. AI가 코드를 쓰는 시대에, 코드를 읽고 평가하는 능력이 더 중요해졌다. 역설적이다. 쓰기가 쉬워질수록 읽기가 어려워진다. 그리고 그 어려운 읽기를 잘 하는 사람이 좋은 개발자로 평가받는 시대가 온 것 같다.
가끔 AI 없이 코드를 쓰는 날을 의도적으로 만든다. 자동완성을 끄고, 검색도 최소화하고, 머릿속에 있는 것만으로 코드를 작성해본다. 느리다. 확실히 느리다. 하지만 그 과정에서 내가 실제로 뭘 알고 뭘 모르는지가 드러난다. AI에 기대어 있으면 보이지 않던 빈틈이 보인다. 이 빈틈을 인식하는 것 자체가, AI 시대에 개발자로서 살아남는 방법이 아닐까 생각한다.
