AI 코딩이 시니어와 주니어 개발자 사이의 격차를 벌리는 이유
요약
AI 코딩 도구가 개발자의 역량에 따라 상반된 결과를 초래함을 분석합니다. AI는 국소적인 코드 생성 능력은 뛰어나지만, 시스템 전체의 아키텍처를 설계하고 검증하는 능력은 부족하여 숙련도에 따른 격차를 심화시킵니다.
핵심 포인트
- AI는 기존의 역량을 강화할 뿐, 설계 능력을 대체하지 못함
- 주니어는 일관성 없는 코드베이스를 만들 위험이 높음
- 시니어는 아키텍처 설계에 집중하며 생산성을 극대화함
- AI는 국소적 최적화에는 강하나 시스템 전체 이해도는 낮음
같은 주에 두 가지 사건이 일어났습니다.
한 창업자가 저에게 저장소(repository) 하나를 보내왔습니다. AI의 도움을 받아 3개월 만에 구축된 3만 줄 규모의 코드였습니다. 컴파일도 잘 되었고, 테스트도 통과(green) 상태였습니다. 데모에서는 완성도 높아 보였습니다. 하지만 실제 운영 환경(production)에서는 5개의 별도 인증 흐름(authentication flows)이 존재했고, 비즈니스 로직이 아닌 반환 타입(return types)만을 검증하는 테스트 스위트(test suite)가 있었으며, 데이터베이스 스키마(database schema)는 ORM과 세 가지 방식으로 충돌하고 있었습니다. 저는 이 시리즈의 이전 글에서 이러한 패턴에 대해 자세히 기술했습니다. 요약하자면, 코드는 국소적으로는 일관성이 있었으나 전체적으로는 일관성이 없었습니다. 설계자(architect) 역할을 수행한 사람이 아무도 없었기 때문입니다.
이틀 후, 제가 존경하는 한 시니어 개발자가 메시지를 보내왔습니다. 그는 6개월 전에 자신의 워크플로우(workflow)에 AI 코딩 도구를 통합했습니다. 그는 아키텍처 수준의 작업을 제외한 모든 부분에서 산출물(output)이 대략 두 배로 늘어났다고 말했습니다. 그는 더 빠르게 제품을 출시(shipping)하고 있었고, 지루한 상용구 코드(boilerplate)에서 오타를 덜 내며, 자신이 흥미를 느끼는 업무에 더 많은 시간을 할애하고 있었습니다.
동일한 기술. 정반대의 결과.
그 격차는 우연이 아닙니다.
바람에는 방향이 없다
불과 바람에 관한 오래된 관찰 결과가 있습니다. 바람은 불을 만드는 것이 아니며, 어느 한 편을 선택하지도 않습니다. 바람은 이미 타고 있는 것이 무엇이든 그것을 강화할 뿐입니다. 작은 불꽃은 꺼뜨리고, 큰 불은 훨씬 더 거대한 것이 될 때까지 부채질합니다.
AI 지원 코딩(AI-assisted coding)도 같은 방식으로 작동합니다.
도구에는 선호도가 없습니다. 도구는 당신의 데이터베이스 마이그레이션(database migration)이 실행하기에 안전한지, 혹은 인증 경계(authentication boundary)가 올바른 위치에 있는지 알지 못합니다. 도구는 학습 데이터(training data)의 패턴을 기반으로 그럴싸해 보이는 출력물(output)을 생성하며, 그 출력물이 정확한지 여부와 상관없이 일관된 자신감을 가지고 이를 수행합니다. 도구는 강력합니다. 문제는 이것입니다: 어느 방향으로 강력한가?
그것은 당신이 채팅창을 열기 전에 이미 무엇이 있었느냐에 전적으로 달려 있습니다.
이것은 대중적인 서사와 모순되기 때문에 편안한 관찰은 아닙니다. 대중적인 서사는 AI가 소프트웨어 개발을 민주화한다고 말합니다. 즉, 경험이 적은 개발자들에게 이전에는 수년간의 연습이 필요했던 패턴과 역량에 대한 접근 권한을 부여한다는 것입니다. 이는 표면적인 수준에서는 사실이지만, 중요한 수준에서는 오해의 소지가 있습니다. 그럴싸해 보이는 코드 조각을 생성하는 것과, 그 코드가 존재해야 하는지, 주변 시스템과 부합하는지, 그리고 데모에서는 절대 테스트하지 않는 조건에서도 견뎌낼 수 있는지를 아는 것 사이에는 실질적인 차이가 있습니다.
AI는 첫 번째 종류의 지식에 대한 격차를 줄입니다. 하지만 두 번째 종류의 지식에 대한 격차는 벌립니다.
설계자(Architect)가 과정에 개입하지 않을 때 발생하는 일
저는 이전 글에서 설명한 코드베이스를 만들어내는 사람들이 부주의하거나 무지하다고 생각하지 않습니다. 그들은 모델에게 무언가를 만드는 데 도움을 달라고 요청했고, 모델은 도움을 주었습니다. 문제는 구조적인 것입니다. 모델은 시스템 전체에 대한 지속적인 이해를 가지고 있지 않습니다. 각 응답은 국소적으로(locally) 최적화됩니다. 모델은 현재의 문제를 해결하지만, 그 해결책이 두 파일 떨어진 곳에서 새로운 문제를 만드는지, 혹은 3주 전 다른 프롬프트를 통해 거의 동일한 해결책이 이미 존재했는지 여부는 고려하지 않습니다.
시니어 개발자는 주니어보다 머릿속에 더 많은 것을 담고 있다는 점으로 자신을 차별화하지 않습니다. 분산 시스템(Distributed systems)은 이미 오래전에 단 한 사람의 인지 능력을 넘어섰습니다. 훌륭한 엔지니어링이 정신적 기억력을 극대화하는 것이라는 생각은 실제 시스템과 접촉하면 살아남지 못할 낭만적인 환상에 불과합니다. 대신 시니어가 하는 일은 기억에 대한 의존성을 불필요하게 만드는 프로세스를 구축하는 것입니다: 아키텍처 결정 기록(Architecture Decision Records), 코드 내의 명시적인 불변량(invariants), 계약 테스트(contract tests), 아키텍처 제약 조건을 인코딩하는 CI 게이트(CI gates), 코드로서의 스키마(schema-as-code), 장애 모드에 대한 런북(runbooks) 등이 그것입니다. 시스템은 한 개인의 영웅적인 기억력이 아니라, 누구나 읽을 수 있도록 축적된 구조를 통해 명확해집니다.
이 점을 명확히 말할 가치가 있는 이유는, 이것이 그림 속에서 AI를 바라보는 당신의 사고방식을 바꾸기 때문입니다. AI는 코딩 속도(velocity)를 가속화합니다. 시니어의 역할은 다른 종류의 가속에도 시스템을 회복 탄력적(resilient)으로 만드는 것과 동일한 공식적인 프로세스(formal processes)를 통해, AI의 도움을 받은 속도로 인해 시스템이 스스로를 해치지 않도록 보호하는 것입니다.
이것은 특정 프레임워크(framework)나 프로그래밍 언어를 안다고 해서 얻을 수 있는 기술이 아닙니다. 이는 수많은 시스템을 경험하고, 그것들이 실패하는 과정을 지켜보며, 왜 그런지 정확하게 설명하기도 전에 무언가 잘못되었다는 것을 느끼는 감각 — 이를 취향(taste)이라 부르든, 판단력(judgment)이라 부르든 — 을 개발함으로써 얻어지는 것입니다. 이 판단력은 프로세스(process)를 대체하는 것이 아닙니다. 오히려 어떤 프로세스가 존재해야 하는지, 불변량(invariants)이 어디에 있는지, 그리고 시스템의 어느 부분이 명시적인 보호를 받아야 하는지를 알려주는 역할을 합니다.
그 판단력이 바로 주니어 개발자에게는 아직 없는 것입니다. 그들이 능력이 없어서가 아니라, 그것을 기르기 위해서는 시간과 실패가 필요하기 때문입니다. 지름길은 없습니다. 그리고 그러한 판단력이 없는 개발자에게 대량의 자신감 넘치는 코드를 생성하는 AI 어시스턴트(AI assistant)를 제공하면, 코드를 평가할 판단력 없이 작성된 코드에서 발생하는 모든 문제와 함께, 더 많은 코드가 더 빠르게 쏟아져 나오는 결과를 얻게 됩니다.
주니어가 AI를 사용할 때 겪는 근본적인 문제는 나쁜 제안을 수용한다는 것이 아닙니다. 나쁜 제안과 좋은 제안을 구분하지 못하는 경우가 많다는 점입니다. 모델이 인증(authentication)에 접근하는 다섯 가지 서로 다른 방법을 제안할 때, 주니어가 하나를 선택하는 기준은 "이 중 어떤 것이 아키텍처적으로 견고한가(architecturally sound)"가 아니라, "이 중 어떤 것이 가장 익숙해 보이는가, 혹은 가장 최근에 논의되었는가, 아니면 가장 자신 있게 설명되었는가"가 됩니다. 모델의 어조는 좋은 제안과 나쁜 제안 사이에서 변하지 않습니다. 모델은 정답을 말할 때나, 나중에 되돌리기에 고통스러울 패턴으로 당신을 인도할 때나 똑같이 확신에 찬 목소리로 말합니다.
시니어가 루프 안에 있을 때 발생하는 일
slug="fractional-cto"
text="정규직 채용 없이 루프(loop) 안에 시니어 엔지니어를 배치해야 할까요? Fractional CTO(부분적 CTO) 업무가 바로 이것입니다. AI 보조를 통한 속도(velocity)가 아키텍처의 혼돈(architectural chaos)을 초래하지 않도록 유지하는 기술적 리더십입니다."
/>
앞서 언급한 시니어 개발자는 일상적인 업무에서 산출물을 대략 두 배로 늘렸습니다. 저는 이 수치를 믿습니다. 왜냐하면 제가 직접 경험하는 것과 일치하기 때문입니다. 하지만 그 메커니즘은 주의 깊게 살펴볼 가치가 있습니다. 대부분의 사람들이 가정하는 것과는 다르기 때문입니다.
AI가 코드를 작성하고 시니어가 이를 검토하는 것이 아닙니다. 아니, 정확히 말하자면 그것은 표면적인 설명일 뿐, 가장 중요한 부분을 빠뜨리고 있습니다. 시니어는 수락하는 것보다 훨씬 더 많은 것을 거절합니다. 병합(merge)되는 제안 하나당, 버려지거나, 재작성을 요청받거나, 반영되기 전에 수정되는 제안이 여러 개 존재합니다. 이러한 필터링(filtering) 작업은 눈에 보이지 않습니다. 사람들은 AI가 어떻게 개발 속도를 가속화했는지에 대해 이야기하지만, 얼마나 자주 AI에게 '아니오'라고 말했는지, 혹은 신뢰할 수 있는 결과물을 얻기 위해 얼마나 많은 반복(iteration)이 필요했는지에 대해서는 거의 이야기하지 않습니다.
또한 시니어는 시스템의 어떤 부분을 절대 위임하지 않을지 정확히 알고 있습니다. 저에게는 강력한 감독 없이 모델이 결정하도록 내버려 두지 않을 항목들의 짧은 목록이 있습니다:
데이터베이스 스키마(Database schema) 변경. 모델이 마이그레이션(migration)을 생성할 수 없기 때문이 아닙니다. 모델은 빠르고 정확한 구문(syntax)으로 생성할 수 있습니다. 하지만 겉보기에 올바른 마이그레이션이라도 실행 후에야 나타나는 결과를 초래할 수 있으며, 모델은 실제 운영 데이터 분포(production data distribution)에 대한 지식 없이는 그러한 결과를 예측할 수 없습니다. 저는 AI의 도움을 받아 마이그레이션을 생성하지만, 어디에서든 실행하기 전에 모든 줄을 두 번씩 읽습니다.
보안 경계 (Security boundaries). 인증 (authentication)은 어디에서 이루어지는가? 누가 무엇을 볼 수 있도록 허용되는가? 인증되지 않은 요청은 무엇에 접근하는가? 이것들은 전체 시스템을 이해하는 사람이 의도적으로 내려야 하는 아키텍처 결정 (architectural decisions)이며, 감사를 위해 기록되어야 합니다. 모델은 당신이 요청하면 인증 체크 (auth check) 코드를 작성할 것입니다. 하지만 그 체크가 올바른 위치에, 올바른 계층 (layer)에서, 올바른 이유로 수행되는지 여부는 모델이 갖지 못한 판단력을 필요로 합니다.
돈과 관련된 모든 것. 결제 흐름 (payment flow), 과금 로직 (billing logic), 인보이스 계산 (invoice calculation). 모델은 저보다 더 빠르게 Stripe 연동 코드를 작성할 수 있습니다. 하지만 저는 여전히 모든 줄을 읽고, 모든 엣지 케이스 (edge case)를 테스트하며, 실패를 어떻게 처리할지 결정하는 주체가 될 것입니다.
운영 및 런타임 정확성 (Operational and runtime correctness) — 이 부분은 다른 항목들보다 덜 명확할 수 있습니다. AI는 이상적인 조건에서 작동하는 코드를 생성합니다. AI가 신뢰성 있게 처리하지 못하는 것은 압박 상황에서의 동작입니다: 레이스 컨디션 (race conditions), 웹훅 (webhooks) 및 큐 (queues)에서의 멱등성 (idempotency) 및 재시도 폭풍 (retry storms), 데드락 (deadlocks), 외부 API가 파이프라인 중간에 중단될 때의 실패 의미론 (failure semantics). 모델은 깨끗한 환경에서 테스트를 통과하는 코드를 생성합니다; 운영 정확성은 깨끗하지 않은 환경에서 무엇이 발생하는가에 관한 것입니다. 부하 상황에서 실패하는, 그럴싸해 보이는 코드는 눈에 띄기 전에 운영 환경 (production)에 뿌리를 내리게 되며, 이것이 바로 가장 비용이 많이 드는 종류의 오류를 만드는 이유입니다.
이러한 영역 외에도 저는 AI를 광범위하게 사용합니다. 스키마 (schema) 변경이 아닌 작업들을 위한 마이그레이션 (Migrations), 확립된 패턴을 따르는 CRUD 엔드포인트 (endpoints), 타입 정의 (Type definitions) 및 인터페이스 (interfaces), 그리고 제가 이미 글로 명시한 동작에 대한 테스트 케이스 (Test cases) 등이 그 예입니다. 여기서 '이미 명시했다'는 수식어가 중요한데, AI가 방금 자신이 작성한 코드에 대해 테스트를 작성하는 것은 완전히 다른 문제이며, 이는 또 다른 종류의 실패를 야기합니다. 이 내용은 이전 글에서 자세히 다루었습니다. 정규 표현식 (Regular expressions), 기존 서비스와 유사해야 하는 신규 서비스를 위한 보일러플레이트 (Boilerplate) 등도 포함됩니다. 이러한 영역들은 정답이 비교적 잘 정의되어 있고 주요 비용이 타이핑에 불과하기 때문에, AI가 진정으로 산출물을 배가시키는 곳입니다.
이것이 실무에서 의미하는 바는 다음과 같습니다. 저는 근본적으로 기계적인 부분에서는 훨씬 빨라지지만, 판단 (judgment)이 필요한 부분에서는 속도가 비슷합니다. 즉, 기계적인 작업 대비 판단 작업의 비율이 변하며, 제 시간 중 판단 작업이 차지하는 비중이 더 커집니다. 저는 이것이 흥미가 줄어드는 것이 아니라 오히려 더 흥미롭다고 느낍니다.
구체적인 예시
간단한 사례를 들어보겠습니다. 데이터베이스 쿼리 (database query)를 위한 프롬프팅 (prompting)입니다.
코드베이스에 익숙하지 않은 주니어 개발자는 다음과 같이 작성할 수 있습니다:
사용자의 모든 주문을 가져오는 쿼리를 작성해줘
모델은 쿼리를 반환합니다. 아마도 올바른 쿼리일 것입니다. 주니어는 이를 코드베이스에 추가합니다.
같은 코드베이스에서 작업하는 시니어 개발자는 다음과 같이 작성할 수 있습니다:
schema/orders.ts에 있는 기존 Drizzle ORM 스키마를 사용하여,
특정 사용자의 모든 열린 주문(open orders)을 가져와야 해. 주문은 소프트 삭제(soft-deleted, deleted_at 컬럼) 처리되어 있으며,
멀티 테넌시(multi-tenancy)를 위해 tenant_id로 필터링해야 하고, 고객의...
모델은 실제 코드베이스에 부합하는 쿼리를 반환합니다. 시니어는 이를 읽고, 두 가지 정도를 수정한 뒤 머지 (merge)합니다.
두 개발자 모두 AI를 사용했습니다. 차이는 도구에 있는 것이 아닙니다. 질문에 있습니다. 시니어의 질문에는 주니어가 포함해야 한다는 사실조차 몰랐던 아키텍처적 맥락 (architectural context)이 인코딩되어 있습니다. 즉, 소프트 딜리트 패턴 (soft-delete pattern), 멀티 테넌시 제약 조건 (multi-tenancy constraint), 기존 코드의 위치, 기존 명명 규칙 (naming conventions) 등이 그것입니다. 그러한 맥락은 시스템을 이해하는 데서 나옵니다. AI는 이를 제공할 수 없습니다. 당신이 직접 가져와야 합니다.
AI 이전의 소프트웨어 개발에서의 병목 현상 (bottleneck)은 구현 속도, 즉 누가 가장 빠르게 코드를 작성할 수 있느냐였습니다. AI 시대의 병목 현상은 명세의 정밀도 (specification precision)입니다. 시니어가 가져오는 진정한 이점은 손으로 코드를 빠르게 작성하는 능력이 아니라, 의도를 공식화하는 능력입니다. 즉, 코드 한 줄이 작성되기 전에 제약 조건을 명시하고, 불변성 (invariants)을 기술하며, 인터페이스를 설계하고, 실패 의미론 (failure semantics)을 정의하는 능력입니다. AI는 명세 (specification)를 바탕으로 코드를 작성합니다. 따라서 이제 코드의 품질은 AI가 받은 명세의 품질에 따른 함수가 됩니다. 이것은 타자 속도를 높이는 것과는 다른 기술이며, 이를 개발하는 데는 똑같이 수년의 시간이 걸립니다.
이것이 바로 AI가 당신이 이미 가진 것을 증폭시킨다고 말할 때의 의미입니다. 시니어는 프롬프트 (prompt)가 실제 이해를 반영하고 있기 때문에 첫 번째 프롬프트에서 유용한 응답을 얻습니다. 반면 주니어는 다시 작성해야 하는 응답을 받거나, 더 나쁜 경우에는 운영 장애 (production incident)를 일으키기 전까지는 그것이 틀렸다는 사실조차 인지하지 못하는 응답을 받게 됩니다.
평등한 접근이라는 환상
AI의 민주화에 관한 이야기 중에는 진정으로 해로운 버전이 하나 있다고 생각합니다. 그것이 정직하지 않아서가 아니라, 창업자와 채용 담당자들에게 잘못된 멘탈 모델 (mental model)을 심어주기 때문입니다.
그 이야기는 다음과 같습니다. AI는 누구나 프로덕션급 (production-grade) 소프트웨어를 작성할 수 있게 만듭니다. 더 저렴한 개발자를 고용하고 그들에게 AI 도구를 제공하십시오. 그러면 더 낮은 비용으로 동일한 결과물을 얻을 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기