숙련된 프로그래머가 운전대를 잡고 있을 때만 AI가 작성한 코드가 더 나아진다
요약
AI 코딩 도구의 품질은 사용자의 숙련도에 따라 결정되며, AI는 사용자의 역량을 증폭시키는 거울 역할을 합니다. 숙련된 개발자는 AI를 통해 반복적인 작업을 빠르게 처리하며 품질을 유지하지만, 주니어 개발자는 AI가 생성한 코드의 보안 취약점이나 누락된 요구사항을 인지하지 못해 위험을 초래할 수 있습니다.
핵심 포인트
- AI는 사용자의 숙련도를 반영하며, 숙련된 개발자는 더 나은 코드를 더 빠르게 작성하게 합니다.
- 주니어 개발자는 AI가 생성한 코드의 보안 취약점(CSRF, 타이밍 공격 등)을 식별하지 못할 위험이 큽니다.
- AI는 질문에 답하는 데 능숙하지만, 사용자가 무엇을 질문해야 하는지(누락된 요구사항)는 알려주지 못합니다.
- 시니어 개발자는 데이터 모델, 예외 케이스, 보안 경계 등을 미리 설계한 후 AI를 보일러플레이트 생성 도구로 활용합니다.
fatihsennik.com에 처음 게시되었습니다. 저는 AI 코딩 논쟁의 양측 모두를 짜증 나게 할 말을 하려고 합니다. AI가 생성한 코드는 그 자체로 좋거나 나쁘지 않습니다. 그것은 거울입니다. 그것은 사용하는 사람의 숙련도를 반영하며, 약 3배의 속도와 10배의 양으로 이를 수행합니다. AI를 사용하는 숙련된 개발자는 더 나은 코드를 더 빠르게 작성합니다. AI를 사용하는 경험이 부족한 개발자는 더 나쁜 코드를 더 빠르게 작성합니다. AI는 그 차이를 모릅니다. 그저 출력할 뿐입니다. 저는 지난 몇 달 동안 LM Studio, Ollama 등과 같은 로컬 모델을 일상적인 워크플로(Workflow)에서 사용해 왔습니다. 저는 제가 사용할 때와 고객 프로젝트의 주니어 개발자들이 사용할 때 코드 품질에 어떤 영향을 미치는지 지켜보았습니다. 그 격차는 미묘한 수준이 아닙니다.
주니어가 AI를 사용할 때 실제로 일어나는 일
주니어 개발자에게 AI 없이 사용자 인증 시스템(User authentication system)을 구축해 달라고 요청해 보십시오. 그들은 Laravel 문서를 읽고, 몇 가지 예시를 살펴보고, 실수를 저지르고, 그로부터 배울 것입니다. 결과물은 불완전하겠지만 그들은 그것을 이해할 것입니다. 코드가 깨졌을 때 디버깅(Debug)할 수도 있습니다. 이제 동일한 개발자에게 Cursor나 GitHub Copilot을 주십시오. 그들은 원하는 것을 설명합니다. AI는 30초 만에 완전한 인증 시스템을 생성합니다. 그것은 전문적으로 보입니다. 테스트는 통과합니다. 배포됩니다. 6개월 후, 그 시스템에는 아무도 코드를 완전히 읽지 않았기 때문에 아무도 알아차리지 못한 세션 고정(Session fixation) 취약점이 발견됩니다. 개발자가 요청해야 한다는 사실을 몰랐고 AI도 자발적으로 제안하지 않았기 때문에, 토큰 갱신 엔드포인트 중 하나에 CSRF 보호가 없습니다. 비밀번호 재설정 흐름에는 미묘한 타이밍 공격(Timing attack) 벡터가 존재합니다.
이 중 어느 것도 정확히 AI의 잘못은 아닙니다. AI는 주어진 프롬프트(Prompt)에 대해 그럴듯한 코드를 생성했습니다. 프롬프트에 보안 요구 사항을 언급하지 않은 이유는 그것을 작성한 사람이 그러한 요구 사항이 존재한다는 사실을 몰랐기 때문입니다. AI는 당신이 요청하는 것을 잊어버린 것이 무엇인지 말해줄 수 없습니다. 이것이 핵심적인 문제입니다. AI는 질문에 답하는 데 매우 능숙합니다. 하지만 당신이 어떤 질문을 했어야 했는지를 알려주는 데는 완전히 무용지물입니다.
시니어 개발자가 사용할 때의 모습
Laravel 기능을 구현하기 위해 AI를 사용할 때 저의 실제 워크플로우는 다음과 같습니다. 저는 이미 해당 기능에 무엇이 필요한지 알고 있습니다. 데이터 모델(Data model), 예외 케이스(Edge cases), 보안 경계(Security boundaries)에 대해 이미 고민을 마친 상태입니다. 어떤 Eloquent 메서드가 잘못 사용될 경우 주입(Injectable)될 수 있는지 알고 있으며, 어떤 미들웨어(Middleware)가 어떤 라우트(Route)에 있어야 하는지도 알고 있습니다. 실패 모드(Failure modes)가 무엇인지도 알고 있습니다.
저는 AI를 사용하여 보일러플레이트(Boilerplate), 즉 마이그레이션(Migration), 리소스 클래스(Resource class), 폼 리퀘스트 스켈레톤(Form request skeleton)과 같이 기계적이고 기본적으로 정확해야 하는 코드들을 생성하는 데 사용합니다. 저는 모든 줄을 검토합니다. 생성된 코드가 제가 동의하지 않는 가정을 하고 있을 때 이를 포착합니다. 그리고 수정합니다. AI가 누락한 유효성 검사 규칙(Validation rule)을 추가합니다. AI가 잘못된 위치에 배치한 권한 부여(Authorization) 체크를 이동시킵니다. AI는 저의 판단이 필요하지 않은 부분에서 저를 더 빠르게 만들어 주었습니다. 저의 판단은 중요한 모든 것을 처리했습니다. 이것은 주니어 개발자가 하고 있던 것과는 완전히 다른 활동입니다. 겉으로 보기에는 우리 둘 다 프롬프트(Prompt)를 입력하고 코드를 돌려받았기에 똑같아 보일 뿐입니다.
신뢰의 문제
이것을 진정으로 위험하게 만드는 것은 나쁜 코드 그 자체가 아닙니다. 나쁜 코드가 좋은 코드와 똑같이 보인다는 점입니다. 주니어가 직접 작성한 코드는 보통 특징이 있습니다. 일관성 없는 패턴, 어색한 변수 이름, 명백히 누락된 에러 핸들링(Error handling) 같은 것들 말입니다. PR(Pull Request)을 검토하는 숙련된 개발자는 작성자의 숙련도를 파악하고 그에 맞춰 검토 강도를 조절할 수 있습니다.
하지만 AI가 생성한 코드에는 그러한 특징이 전혀 없습니다. 스타일이 일관적입니다. 적절한 메서드 이름을 사용합니다. 에러 핸들링도 존재합니다. 다만 어떤 경우에는 잘못된 에러를 처리하고 있을 뿐입니다. 구조는 컨벤션(Convention)을 따릅니다. 린팅(Linting)도 통과합니다. 언뜻 보기에는 무엇을 하는지 정확히 아는 사람이 작성한 것처럼 보입니다. 그것이 함정입니다. 코드가 엄격해 보이기 때문에 코드 리뷰(Code review)가 덜 엄격해집니다. 정적 분석(Static analysis)이 일부를 잡아내긴 하지만, 바로 그 이유 때문에 저는 코드를 누가 작성했느냐에 상관없이 모든 MR(Merge Request)에 Semgrep을 실행하기 시작했습니다.
하지만 도구(tooling)가 리뷰어가 자신이 무엇을 보고 있는지 이해하는 과정을 완전히 대체할 수는 없습니다. 물론 AI는 더 좋아질 것입니다. 모델은 개선됩니다. 추론(Reasoning)은 더 날카로워질 것입니다. 컨텍스트 윈도우(Context windows)는 더 길어질 것입니다. 하지만 "코드를 더 잘 생성하는 것"과 "당신의 특정 애플리케이션의 위협 모델(threat model)에 맞는 안전하고 유지보수 가능한 프로덕션 코드를 더 잘 생성하는 것"은 같은 의미가 아닙니다. 후자는 당신의 비즈니스 로직, 배포 환경, 사용자 기반, 컴플라이언스(compliance) 요구사항, 그리고 프롬프트(prompt) 외부에 존재하는 수백 가지 다른 요소들을 이해해야 합니다. 이론적으로 올바른 인증 시스템을 생성할 수 있는 모델이라 할지라도, 당신의 특정 애플리케이션이 의료 데이터를 다루고 있기 때문에 일반적인 구현에는 포함되지 않은 특정한 보호 조치가 필요하다는 사실을 여전히 알려줄 수 없습니다. 그것은 당신이 알아야 합니다. 당신이 프롬프트에 가져와야 합니다. 그리고 무엇을 가져와야 하는지 아는 데에는 AI가 불필요하게 만들고 있다고 주장되는 바로 그 '어렵게 얻은 경험'이 정확히 필요합니다. "AI가 2년 안에 시니어 개발자를 대체할 것이다"라고 자신 있게 말하는 사람들은, 제가 관찰하기로는 대부분 프로덕션 환경에서 AI가 생성한 코드를 디버깅하는 데 많은 시간을 소비해 보지 않은 사람들입니다. 그러한 경험은 당신의 관점을 명확하게 만드는 힘이 있습니다. 제가 주니어 개발자들에게 하는 말은 이렇습니다. 사용하세요. 그것은 진정으로 유용한 도구이며, 그렇지 않은 척하는 것은 그저 전문성으로 포장된 향수(nostalgia)일 뿐입니다. 하지만 계산기처럼 사용하되, 신탁(oracle)처럼 사용하지는 마세요. 계산기는 당신이 방정식을 올바르게 설정하면 정답을 줍니다. 방정식을 잘못 설정하면 자신감 있고 정밀하며 완전히 틀린 답을 내놓습니다. 계산기는 당신의 방정식이 틀렸다는 것을 알지 못합니다. 코드를 배포하기 전에 AI가 생성한 것을 이해하세요. 단순히 "작동하는가"를 넘어, 왜 작동하는지, 그리고 입력값이 AI가 가정한 것과 다를 때 어떤 일이 발생하는지를 이해하세요. 만약 생성된 코드의 일부를 팀원에게 설명할 수 없다면, 당신의 작업은 아직 끝나지 않은 것입니다. 그리고 어쨌든 기본기를 쌓으세요. AI 도구로부터 가장 많은 것을 얻어내는 개발자는, 그 도구 없이도 유능할 사람들입니다.
지름길은 당신이 무엇을 지름길로 가고 있는지 알고 있을 때만 유용합니다. 솔직한 결론을 말씀드리자면, AI 코딩 도구는 생산성 승수 (Productivity Multipliers)입니다. 승수의 문제는 속도와 양뿐만 아니라, 당신이 이미 가지고 있는 기술과 판단력까지도 똑같이 확장시킨다는 점입니다. 숙련된 개발자에게 3배의 승수를 제공하면, 더 빠르고 훌륭한 코드를 얻을 수 있습니다. 하지만 경험이 부족한 개발자에게 동일한 승수를 제공하면, 이전과 동일한 비율의 문제들을 가진 코드를 더 빠르게 얻게 될 뿐입니다. 다만 이제는 코드가 다듬어져 보이기 때문에 그 문제들을 발견하기가 더 어려워질 뿐입니다. 여기서 변수는 기술이 아닙니다. 개발자입니다. 저는 제 워크플로 (Workflow)에서 계속 AI를 사용할 것입니다. AI가 건드리는 모든 것에 대해 계속 Semgrep을 실행할 것입니다. 프로덕션 (Production)에 반영되기 전에 모든 라인을 계속 검토할 것입니다. 그리고 이전보다 더 빠르게 배포하면서도, 무엇을 배포해야 하는지에 대한 식견은 눈에 띄게 좋아지지 않은 팀에 대해서는 계속해서 약간의 의구심을 가질 것입니다. 판단력이 결여된 속도는 진보가 아닙니다. 그것은 단지 무언가 잘못될 수 있는 표면적 (Surface area)을 넓히는 것일 뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기