제가 자리를 비운 동안 AI는 좋아졌지만, 우리는 둔해졌을까요? 개발자의 솔직한 감사: AI가 실제로 대체한 것 vs. 단지 게으르게 만든 것
요약
개발자는 AI 코딩 어시스턴트의 발전이 개발 생산성을 높였음을 인정하며, 보일러플레이트 코드 생성이나 문서화 등 반복적인 작업은 '승리'라고 평가합니다. 그러나 문제는 이해(understanding)를 제안(suggestion)으로 대체하는 경향이며, 이로 인해 근본적인 엔지니어링 능력과 디버깅 능력이 잠식되고 있다는 점을 지적합니다.
핵심 포인트
- AI는 보일러플레이트 및 스캐폴딩 코드를 자동화하여 시간을 절약한다.
- 문서화나 API 조회 등 인지적 비용이 높았던 작업에서 큰 효율성을 얻었다.
- 진짜 문제는 이해를 제안으로 대체하며 근본적인 엔지니어링 능력을 약화시키는 것이다.
- 디버깅 과정이 단순 검색-붙여넣기로 변질되고 타입 안전성이 우회되는 경향이 나타난다.
Originally published on tamiz.pro.
2년 전만 해도 Copilot의 제안이 담긴 코드는 리팩토링 없이는 코드 리뷰를 통과할 수 없었습니다. 오늘날 저의 PR 중 절반은 제가 거의 수정하지 않은 AI가 생성한 코드로 배포됩니다. 도구 자체는 정말로 좋아졌습니다. 아무도 솔직하게 묻지 않는 질문은, 제가 근본적인 엔지니어링 능력에서 나빠졌는지—그리고 특히 주니어 동료들이 모든 질문에 답해주는 어시스턴트 때문에 조용히 능력을 상실하고 있는지입니다.
이것은 AI 반대론자로서의 비난이 아닙니다. 이것은 무엇이 바뀌었는지, 무엇이 진정으로 대체되었는지, 그리고 무엇이 조용히 잠식되었는지에 대한 개발자의 기술적 감사(technical audit)입니다. 이 두 범주 간의 구분이 전체 논점입니다.
AI가 실제로 대체한 것 (그리고 우리가 받아들여야 할 것)
AI 코딩 어시스턴트가 진정으로 자동화한, 측정 가능하고 실제적인 업무 카테고리가 있습니다. 이것들은 손실이 아닙니다. 승리입니다.
보일러플레이트 및 스캐폴딩(Boilerplate and scaffolding). 명세서로부터 React 컴포넌트를 생성하거나, CRUD 엔드포인트를 작성하거나, Dockerfile을 만들거나, 테스트 픽스처를 설정하는 것—이것들은 본래 지적으로 흥미로운 작업이 아니었습니다. 이것들은 아키텍처 결정이나 디버깅에 사용될 수 있었던 시간과 주의력을 소모했습니다. AI는 이제 이것들을 잘 처리합니다. 보일러플레이트 템플릿에 20분을 소비하는 주니어 개발자는 대신 그 시간을 시스템의 데이터 흐름을 이해하는 데 쓸 수 있습니다.
문서화 및 API 조회(Documentation and API lookups). AI가 있기 전에는 코드를 작성하는 시간보다 TypeScript 타입 정의를 읽는 시간이 더 많았습니다. 라이브러리 문서를 열어 적절한 오버로드를 검색하고, 기억했던 함수 시그니처가 두 버전 전의 것임을 발견하곤 했습니다. 이제 AI 어시스턴트는 이러한 질문들에 맥락(context) 속에서, 극적으로 향상된 정확도로 답합니다. 이것은 인지적 비용 없이 순수한 시간 절약입니다.
정규 표현식(Regex), 날짜 파싱(date parsing), 및 문자열 조작(string manipulation). 예전에는 개발자들이 텍스트를 다루기 위해 시간과 노력을 들여야 했던 작업들입니다. AI는 처음 시도만으로 작동하는 정규 표현식 패턴, 날짜 형식 지정 유틸리티, 그리고 문자열 변환을 작성합니다. 이것은 단순한 대체가 아닙니다. 과제가 어려워서가 아니라, 제대로 처리하기 위한 인지적 오버헤드(cognitive overhead)가 그 가치에 비해 지나쳤기 때문에 발생한 진정한 대체입니다.
단순 사례에 대한 테스트 생성. 순수 함수(pure functions)를 위한 단위 테스트(unit tests), 스냅샷 테스트(snapshot tests), 그리고 통합 테스트(integration test)의 골격 작업이 이제 신뢰성 있게 생성됩니다. 생성된 테스트가 항상 의미 있는 것은 아니지만, 이를 작성하는 구조적인 작업은 완료되었습니다.
만약 당신의 일상 업무가 이 범주들로 지배된다면, AI는 당신을 더 생산적으로 만들었습니다. 이것은 명확합니다. 저는 이에 반대하는 것이 아닙니다.
AI가 게으르게 만든 것 (그리고 이것이 진짜 문제)
우려되는 추세는 대체(replacement) 자체가 아닙니다. 이해(understanding)를 제안(suggestion)으로 대체하는 것입니다. 제가 직접 경험한 업무와 팀의 주니어 개발자들의 업무에서 관찰한 바를 구체적으로 말씀드리겠습니다.
디버깅이 검색-붙여넣기(search-and-paste)가 되었습니다. 오류가 발생했을 때, 더 이상
타입 안전성이 우회되고 있다. TypeScript는 유효하지 않은 상태를 표현할 수 없도록 존재한다. 코드를 처음부터 직접 작성할 때는 타입 시스템과 상호작용하게 된다—"이 함수가 실제로 무엇을 받아들이는지?"라고 묻는다. AI가 생성한 코드를 붙여넣을 때는 그 과정(상호작용)을 건너뛴다. 코드는 컴파일된다. 하지만 타입은 잘못되었다. 오류는 운영 환경에서 세 단계 아래에 나타난다. 나는 AI가 타입 오류를 없애기 위해 any 캐스트를 생성했고, 개발자가 왜 이 캐스트가 필요한지 의문을 제기하지 않은 채 병합한 PR들을 검토해 본 적이 있다.
아키텍처 결정이 자동 완성 기능에 아웃소싱되고 있다. 이것이 내가 가장 걱정하는 부분이다. 주니어 개발자가 "이 모듈을 어떻게 구조화해야 할까요?"라고 물었고 AI가 패턴을 반환하면, 그들은 그것이 시스템에 맞는지 평가하지 않고 그대로 채택한다. AI는 팀의 컨벤션(conventions), 배포 제약 조건(deployment constraints), 성능 요구 사항 등의 맥락을 알지 못한다. AI는 교과서적인 답변을 주지만, 운영 환경은 교과서가 아니기 때문에 그 답변들은 현장에서 실패한다. 나는 상태 관리 선택, 데이터베이스 스키마 설계, API 계약 결정 등에서 이런 사례를 목격했다. AI의 제안은 고립된 상황에서는 합리적이었다. 하지만 시스템 전체로서는 잘못되었다.
고군분투하는 과정이 생략되고 있으며, 그 고군분투가 곧 학습이었다. 이것이 내 주장의 철학적인 핵심이지만, 나는 이를 엔지니어링 관점에서 근거를 찾을 것이다. 함수를 처음부터 작성하다가 실패하면, 왜 실패했는지 배운다. 언어의 의미론(semantics), 라이브러리의 동작 방식, 시스템의 제약 조건을 학습한다. 프롬프트로부터 코드를 생성했고 그것이 작동하면, 아무것도 배우지 못한다. 기능은 작동하지만, 이해도는 없다. 6개월 후에 그 기능에 다른 제약 조건 하에서 수정이 필요할 때, 정신적 모델(mental model)을 구축한 적이 없기 때문에 수정할 수 없다. 할 수 있는 것은 다시 생성하고 새로운 프롬프트가 호환되는 무언가를 만들어내기를 바라는 것뿐이다.
이것은 가설이 아닙니다. 저는 AI의 도움을 받아 개발한 지 18개월 된 팀원이 있습니다. 그가 작성한 코드 결과물은 양이 많고 대체로 기능적입니다. 하지만 제가 그의 코드에 있는 명백하지 않은 설계 결정의 근거를 설명해 달라고 요청하면, 그는 할 수 없습니다. 그는 AI에게 그것을 자신에게 설명해 달라고 요청합니다. AI는 그럴듯한 설명을 해줍니다. 그는 고개를 끄덕일 뿐입니다. 이해하지 못합니다.
제가 관찰하는 패턴
저는 AI를 사용해서는 안 된다고 주장하는 것이 아닙니다. 저도 매일 사용합니다. 저는 우리가 스펙트럼 위에 있으며, 알아차리지 못한 채 잘못된 쪽으로 미끄러지고 있다고 주장합니다.
생산적인 패턴: 당신이 작업을 이해합니다. 코드를 작성합니다. AI에게 검토를 요청하거나 개선 사항을 제안받거나 엣지 케이스(edge case)를 잡아달라고 합니다. AI는 두 번째 눈과 같습니다. 주 저자는 여전히 당신입니다. 이 패턴은 생산성을 가속화하는 동시에 기술 개발 능력을 보존합니다.
게으른 패턴: 원하는 것을 설명합니다. AI가 코드를 생성합니다. 당신이 붙여넣습니다. 테스트합니다. 작동하면 배포합니다. AI가 주 저자입니다. 당신은 전달 메커니즘일 뿐입니다. 이 패턴은 역량을 저하시키면서 결과물을 만들어냅니다.
차이는 배포되는 코드에서는 보이지 않습니다. 시스템을 변경해야 할 때, 또는 이해를 필요로 하는 버그가 발생하여 단순한 패턴 매칭만으로는 해결할 수 없을 때, 6개월 후에야 보입니다. 첫 번째 경우에는 당신이 정신적 모델(mental model)을 가지고 있습니다. 두 번째 경우에는 그렇지 못합니다.
제가 워크플로우에서 바꾼 것들
저는 이 감사 결과를 바탕으로 의도적인 조정을 했습니다. 이것들은 규칙이 아닙니다. 실천입니다.
제가 먼저 쓰고, 그다음에 요청합니다. 사소하지 않은 모든 것—비즈니스 로직을 가진 모든 함수, 아키텍처 결정이 필요한 모든 경우, 공유 상태(shared state)를 건드리는 모든 코드—에 대해서는 제가 초기 버전을 직접 작성합니다. 그런 다음 AI에게 검토를 요청합니다. 무엇을 놓쳤는지, 어떤 엣지 케이스가 있는지, 제 접근 방식보다 더 나은 대안이 있는지 물어봅니다. 이렇게 하면 AI를 협업자(collaborator)로 사용하면서도 주 저자의 자리에 머무를 수 있습니다.
나는 '무엇(what)'보다 '왜(why)'를 묻는다. AI가 수정 방안을 제시할 때, 나의 첫 질문은 "이것을 적용해야 할까?"가 아니다. 그것은 "이 오류는 왜 발생하는지, 그리고 이 수정이 근본 원인을 어떻게 해결하는지"이다. 만약 AI의 설명이 내가 시스템에 대해 이해하는 바와 일치하지 않는다면, 나는 더 깊이 조사한다. 그 설명이 내가 알지 못했던 무언가를 밝혀낸다면, 나는 배운다. 하지만 그것이 AI가 시스템을 이해하지 못한다는 것을 보여준다면, 나는 그 제안을 무시한다.
나는 생성된 코드를 타입 안전성(type safety)과 가정(assumptions) 측면에서 감사한다. 모든 AI가 생성한 코드 블록은 any 캐스트, 암묵적 타입 강제 변환(implicit type coercion), 검증되지 않은 입력값(unvalidated inputs), 그리고 환경에 대한 숨겨진 가정을 찾는 특별한 검토 과정을 거친다. AI는 당신의 배포 대상(deployment target), 데이터 제약 조건(data constraints), 또는 팀의 컨벤션(conventions)을 알지 못한다. 그것은 맥락상 올바른 코드가 아니라, 겉보기에는 올바르게 보이는 코드에 최적화된다.
나는 주니어 개발자의 학습 곡선 보호에 힘쓴다. 우리 팀에서는 신규 입사자가 처음 3개월 동안 "스스로 먼저 작성하기(write it yourself first)"라는 관행이 있다. 그 이후부터는 AI 지원 개발이 장려되지만, 코드 리뷰 시에는 개발자에게 자신이 붙여넣은 코드를 이해하는 바를 설명하도록 명시적으로 요구한다. 만약 설명을 할 수 없다면, 그 코드는 배포되지 않는다. 이것은 우리에게 있어 협상의 여지가 없는 원칙이다.
정직한 평가
AI는 개발자를 멍청하게 만들지 않았다. AI는 개발자가 기능적인 결과물을 내놓으면서도 멍청할 수 있게 만드는 것을 가능하게 했을 뿐이다. 도구 자체는 진정으로 더 좋아졌다. 생산성 향상은 실재한다. 반복적인 작업을 대체하는 것은 순(net)긍정적이다.
하지만 기초 이해도의 침식 역시 실재하며, 이는 측정 지표로는 보이지 않는다. 이 문제는 시스템이 발전해야 할 때, 새로운 문제가 발생했을 때, 그리고 개발자가 AI의 학습 데이터에 어떤 패턴과도 일치하지 않는 버그를 만났을 때 드러난다. 그 시점에서, 스스로 코드를 작성한 적 없이 2년 동안 코드만 생성해 온 개발자는 대안(fallback)이 없다. 그들은 정신적 모델(mental model)이 없다. 그들에게는 오직 도구만이 있을 뿐이다.
가장 잘 성장할 개발자는 AI를 가장 많이 사용하는 사람이 아닙니다. 그들은 AI를 올바르게 사용하는 사람들입니다. 즉, 먼저 직접 작성하고 나중에 질문하며, 붙여넣기 전에 이해하려 노력하고, AI를 자신의 추론을 대체하는 수단이 아니라 협력자로 여기는 사람들입니다.
제가 자리를 비운 동안 AI는 발전했습니다. 저희가 둔해졌다고 생각하지는 않습니다. 하지만 우리 중 일부는 게을러지고 있다고 생각합니다. 엔지니어링에서의 게으름은 시스템이 무너질 때까지 누적되는 느리고 보이지 않는 실패 모드입니다. 모든 개발자가 던져야 할 질문은 'AI를 사용해야 하는가?'가 아닙니다. '내가 AI를 나의 이해도를 높이는 데 사용하는가, 아니면 대체하는 데 사용하는가?'입니다.
이 질문에 대한 답은 여러분의 PR(Pull Request)에서 보이지 않습니다. 그것은 디버깅하고, 아키텍처를 설계하며, 코드가 작동하는 이유를 설명할 수 있는 능력에서 나타납니다. 만약 스스로 작성한 코드에 대해 마지막 질문을 할 수 없다면, AI는 당신에게 도움을 준 것이 아닙니다. 단지 책임을 미루게 했을 뿐입니다.
개발자 워크플로우 및 엔지니어링 관행에 대한 AI의 영향 분석이 더 필요하다면, Tamiz's Insights에서 지속적인 커버리지를 확인하세요.
자주 묻는 질문
AI 코딩 도우미 사용을 완전히 중단해야 하나요?
아닙니다. 그것은 좋지 않은 선택입니다. AI 도우미는 보일러플레이트(boilerplate), 문서화, 그리고 일상적인 작업의 생산성을 실제로 향상시킵니다. 위험은 AI를 사용하는 것이 아니라, 이해도를 쌓는 것을 방해하는 방식으로 AI를 사용하는 것입니다. 생산적인 패턴은 먼저 직접 작성하고 나중에 질문하며, 생성된 모든 내용을 항상 검토하는 것입니다.
'게으른 패턴(lazy pattern)'과 '생산적인 패턴(productive pattern)'을 어떻게 구별할 수 있나요?
가장 간단한 테스트는 다음과 같습니다. AI를 참조하지 않고 자신이 작성한 코드를 다른 개발자에게 설명할 수 있습니까? 그 코드의 수정 사항을 기본 원리(first principles)부터 디버깅할 수 있습니까? 왜 특정 접근 방식을 대안보다 선택했는지 설명할 수 있습니까? 이 중 어느 질문에 대한 답이 'AI에게 물어봐야 할 것 같다'라면, 해당 작업에서 당신은 게으른 패턴에 빠져 있는 것입니다.
이것이 코딩 도우미를 넘어선 AI 도구에도 적용되나요?
네. 이러한 역동성은 AI가 생성한 문서화(documentation), AI 지원 아키텍처 설계(architecture design), 그리고 AI가 생성한 테스트 스위트(test suites)에도 동일하게 적용됩니다. 패턴은 보편적입니다. 즉, 도구가 당신이 이해를 구축하기 전에 답을 제공할 때, 당신은 학습 과정을 건너뛰게 됩니다. 해결책 또한 같습니다. 먼저 참여하고, 나중에 질문하며, 항상 감사(audit)해야 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기