AI 지원 프로그래밍에서 코드 읽기, 구현 이해, 의도 부채, 그리고 개발자가 져야 할 책임에 관한 고찰.
그 질문은 좀 더 무해한 “코드를 읽나요?”라는 질문과 상당히 다르다. _아직도_라는 말에는 진보에 관한 어떤 이론이 슬그머니 들어 있다. 코드 읽기는 전화번호를 외우거나 종이 지도를 펼치는 일처럼 사라져 가는 것이며, 질문하는 사람은 혹시라도 당신이 여전히 낡은 방식에 매달리는 몽매주의자 중 하나가 아닌지 알고 싶어 하는 듯하다.
나는 AI를 광범위하게 사용하고, AI가 만들어 내는 것을 읽는다. 적어도 내가 커밋하고 배포하는 코드에 대해 어느 정도 책임을 져야 한다고 기대받는 직장에서는, 이것이 내가 소프트웨어를 개발하고 싶은 방식에 관한 의도적인 선택이다. 다른 사람들은 때로는 상당한 신중함을 갖고 다른 선택을 한다. 그러나 우리는 이제 어느 쪽의 길이 동료들에게 무엇을 요구하는지 반드시 합의하지 않은 채 코드베이스를 공유하기 시작했다.
어느 선택이 우세해질지는 알기 매우 어렵다. _아직도_라는 말은 이 문제가 이미 해결되었다고 전제하며, 실제로 요즘에는 작동하는 애플리케이션을 만드는 일이 꽤 더 쉬워졌다. 그러나 요구사항, 개발자, 도구의 변화 속에서 그것을 유지하는 데 무엇이 드는지 알아내는 데는 훨씬 더 긴 시간이 걸린다. 우리는 지금 팀이 일하는 방식에 관한 약속을 하고 있으며, 그 결과는 나중에야 느껴지고 이해될 것이다. 어느 사고방식이든 자신의 승리를 선언하는 자신감은 다소 성급해 보인다.
내가 알기로, 요즘 AI를 사용하는 데는 널리 퍼진 두 가지 접근법이 있다.
_가속기_는 자신의 이해를 코드로 옮기는 일을 AI의 도움으로 수행한다. 이들은 의도에서 코드로의 번역 뒤에 있는 추론을 설명하고, 변경의 결과를 예측하며, 그에 따라 만들어진 모델과 구현을 유지할 수 있을 만큼 구현에 대한 이해를 간직하려 한다. 생성된 코드를 읽는 일은 그 약속의 일부다.
가속기에게 언어 모델과 하니스는 대략 텍스트 편집기와 그 플러그인과 같은 범주에 속한다. 이제 더 빨리 코딩할 수 있게 된 것이다. 이들은 구현을 설명하고 변경할 수 있는 능력을 계속 유지하는 데 투자한다. 큰 변경은 검토하기가 느리고, 모델을 잘못 구현하려는 생성된 차이는 다시 작성하며, 팀의 읽기가 생성 속도를 따라가지 못할 때마다 인지 부채1여백 주석 storey 1 Storey, M.-A. 기술 부채에서 인지 및 의도 부채로: AI 시대의 소프트웨어 건강성 재고. arXiv 2026; 2쪽 ↩가 쌓이고, 이 모든 것은 지키기 매우 어려운 규율을 요구한다.
_바이브코더_는 구현과 그 지속적인 수정을 AI에 위임하는 것을 목표로 한다. 이들의 관심은 원하는 동작을 명세하고, 맥락과 도메인 지식을 제공하며, 결과가 만족스러운지 판단할 방법을 마련하는 쪽으로 옮겨 간다. 모든 구현 세부 사항을 이해하는 것은 더는 이들의 작업이 의도하는 산출물이 아니다.
바이브코더는 언어 모델이 구현을 추상화해 주기를 기대하며, 이를 컴파일러와 프레임워크와 같은 범주에 둔다. 더는 기술적 세부 사항을 이해할 필요가 없어야 한다는 것이다. 이들은 코드를 명세하고, 재생성하고, 평가하는 능력을 계속 유지하는 데 투자한다. 요구사항이 다시 작성되거나 잊히고, 세션 사이에서 맥락이 표류하며, 에이전트가 “멍청한 구역”에 들어가지 않도록3여백 주석 horthy 3 Horthy, D. 바이브는 허용되지 않는다: 복잡한 코드베이스에서 어려운 문제 해결하기. YouTube 2025; 5:55 ↩ 에이전트에게 보여 줄 내용을 선별하는 데 엔지니어링 시간이 들면서 의도 부채2여백 주석 storey2 2 Storey 2026; 3쪽 ↩가 축적될 수 있고, 이 모든 것은 Anthropic 또는 Open AI가 통제하는 모델의 품질에 따라 성패가 갈린다.
이 구분은 모델이 얼마나 많은 코드를 작성하는가가 아니라, 개발자가 산출물과 맺는 관계에 관한 것이다.4여백 주석 willison 4 Willison, S. AI 지원 프로그래밍이 모두 바이브 코딩은 아니다(하지만 바이브 코딩은 멋지다). 2025 ↩ 가속기는 기능의 거의 모든 줄을 생성하면서도 무엇을 만들었는지 이해하고, 그 뒤의 추론에 책임을 질 수 있다. 바이브코더는 명세와 인수 기준을 다듬는 데 상당한 시간을 쓰면서도, 그 결과로 나온 구현은 의도적으로 일회용으로 취급할 수 있다. 가속기라는 것은 모델에 묻기 전에 답을 알고 있어야 한다는 뜻이 아니다. 아직 이해하지 못한 문제를 탐색하기 위해 생성된 코드를 사용할 수 있다. 다만 코드가 주 브랜치에 들어가기 전에 그 이해를 얻으려는 의도가 있어야 한다.5여백 주석 abstain 5 프로그래밍에 AI를 전혀 받아들이지 않는 세 번째 집단도 있다. 내가 접한 반대는 대체로 법적 문제(보통 저작권 관련) 또는 윤리적 문제였고, 진지한 논의가 필요하지만 이 분석의 범위 밖이다. 내가 접하지 못한 것은 실용적인 엔지니어링 이유로, 즉 생성된 코드가 소프트웨어를 더 나쁘게 만들고 결국 절약하는 것보다 더 많은 비용을 초래한다고 믿어서 AI를 피하는 상업용 소프트웨어 조직이다. 그런 곳에서 일한다면, 편하게 연락해 달라. 정말로 듣고 싶다. ↩
내 개인적 선호는 프로그래밍이 무엇을 위한 일인지에 대한 생각에서 나온다. 나는 이전에 프로그래밍이 본질적으로 순수 응용철학이라고 썼다. 당시에는 Peter Naur의 에세이를 읽지 못했는데,6여백 주석 naur 6 Naur, P. 이론 구축으로서의 프로그래밍. Microprocessing and Microprogramming 1985 ↩ 그 에세이는 LLM의 등장으로 다시 주목받게 되었고, 35년 먼저 비슷한 요지를 말하고 있었다.
이는 본질적으로 같은 주장이다. 훨씬 더 똑똑한 누군가가 더 잘 표현했을 뿐이다. 코드는 프로그래밍의 진짜 산출물이 아니다. 오히려 우리는 코드를 자산으로 오해하지만, 대개 그것은 실제로 부채다. 진짜 산출물, 즉 자산은 그 뒤의 모델 또는 이론이다. 이론이란 사람이 무언가를 단지 할 수 있게 하는 것을 넘어, 그것을 설명하고, 그것에 관한 질문에 답하고, 미래를 예측하는 데 사용하고, 상황이 바뀌면 적응할 수 있게 하는 종류의 지식이다. 그것을 가진 프로그래머는 세 가지를 할 수 있다.
“프로그램의 이론을 가진 프로그래머는 그 해결책이 자신이 처리하는 데 도움을 주는 세상의 일들과 어떻게 관련되는지 설명할 수 있다. (…) 프로그램의 이론을 가진 프로그래머는 프로그램의 각 부분이 왜 현재 모습인지를 설명할 수 있다. (…) 프로그램의 이론을 가진 프로그래머는 세상의 일을 새로운 방식으로 뒷받침하도록 프로그램을 수정하라는 어떤 요구에도 건설적으로 대응할 수 있다.”
다시 말해 소스 코드는 프로그래밍 활동의 산출물 한 종류일 뿐이지만, 더 눈에 잘 보인다는 이유로 그것을 만들어 내며 얻은 이해보다 더 가치 있는 것으로 취급된다. 마치 전기는 보이지 않는다는 이유만으로 석탄 발전소 냉각탑에서 나오는 증기를 전기가 아니라 주된 산출물로 취급하는 것과 같다.
소프트웨어 엔지니어의 일 중 일부는 지금까지 암묵적으로만 이해되어 온 비즈니스의 부분들에 이름을 붙이고 구조화하는 것이다. 이는 코드 밖에서도 이점이 있다. 우리가 모델링하는 일을 하는 사람들이 자신이 무엇을 하는지 이해하고, 자신의 일의 측면들을 새로운 관점에서 보도록 도울 수 있다.
프로그래밍은 현실의 모래알을 분류하는 한 가지 방식이다.7여백 주석 pirsig 7 Pirsig, R. 선과 모터사이클 관리술. Vintage 2004; 72쪽 ↩ 우리는 한 사물을 다른 사물과 구별하고, 그 구별에 이름을 붙이며, 그 분류가 어디에서 유용했고 어디에서 잘못되었는지 발견하게 해 주는 동작을 가진 시스템을 만든다.
사물에 이름 붙이기를 그 즉각적인 외양에 따라 하면, 우연적일 수 있는 제품 이해 방식에 우리를 가둔다. 본질적 속성에 따라 이름을 붙이는 방식은 더 유연하지만, 발견하고 구조화하는 데 훨씬 더 많은 노력이 든다. 그리고 실행 중인 소프트웨어는 그 분류의 결과만 시험할 수 있다. 모델이 도메인에 맞는지 판단하려면 여전히 모델링되는 사람들과 프로세스에 접촉해야 한다. 통과한 테스트 스위트는 프로그램이 당신이 말한 대로 동작한다는 것만 증명할 뿐, 당신이 말한 것이 현실과 일치한다는 것은 증명하지 않는다.
프로그래머가 도메인을 이해하는 방식은 구현을 진행하면서 바뀐다. 요구사항을 논의하거나 화이트보드에 그릴 수도 있지만, 개념 분석은 코드와 처음 맞닥뜨리는 순간 살아남지 못할 수 있다. 모든 경우를 고려해야 할 때는 문제에 대한 이해가 완전히 바뀌어 처음으로 돌아가야 할 수도 있다.
그러므로 구현은 명세를 실행 가능한 코드로 단순히 번역한 것이 아니라, 명세가 수정되는 장소 중 하나다. 바이브코더는 구현을 다루지 않고 소프트웨어를 명세하고 실행함으로써 이론을 구축할 수 있다는 데 베팅하는 듯하다. 나는 그것이 확실하지 않다.
가속기 또는 바이브코더 접근법을 선택하는 일에는 서로 다른 약속이 수반된다. 같은 사람도 서로 다른 프로젝트에서, 심지어 같은 프로젝트 안의 하위 모듈에서 다르게 선택할 수 있다.
예를 들어 나는 기반 구현에는 실제로 관심이 없고 화면에 무언가를 보고 싶을 뿐인, 일회용 또는 탐색적 프로젝트에서는 바이브 코딩 쪽으로 기울 수 있다. 어려운 점은 구현에 대한 이해를 유지하지 않게 되면서도 그것을 올바르게 위임하는 방법을 의식적으로 생각하지 않을 수 있다는 것이다. 차이를 읽는 대신 훑어보기 시작하고, 특정 구현 선택의 근거를 떠올리거나 심지어 만들어 내는 데 많은 시간이 필요해지며, 결국 실제로 무엇을 만들었는지 알아내는 유일한 실용적 방법은 모델에게 묻는 것이 된다. 그리고 모델이 말하는 것이 맞는지 검증할 방법은 없다.
이것이 내가 두 접근법을 어떤 종류의 연속선으로 생각하지 않는 이유다. 한 모듈에서는 가속기이고 다른 모듈에서는 바이브코더일 수 있지만, 어느 쪽에서도 중간은 아니다. 표류하는 가속기는 두 접근법 사이 어딘가에 이르는 것이 아니다. 그는 사라진 이론을 보완하기 위해 의도적인 바이브코더라면 구축했을 명세와 평가의 하니스 없이, 기본값으로 바이브코더가 된다.
내 상업적 작업에서 생성된 코드의 모든 줄을 읽는 것은 내가 표류하지 않도록 하는 좋은 방법이다. 그것이 이해를 보장하지는 않지만, 이해와 구현이 어긋나는 지점을 발견할 기회를 반복해서 제공한다.
그리고 그 둘은 어긋난다. 에이전트는 여전히 멍청한 선택을 하고, 텍스트 산출물로 표현할 수 없는 시간 같은 인간적 차원을 종종 존중하지 않기 때문이다. 테스트를 추가한 에이전트는 그저 터미널 출력을 본다. 그 에이전트에게는 이제 테스트 실행 시간이 세 배로 길어졌다는 사실이 별로 중요하지 않다. 하지만 사람에게는 속도가 중요하다. 마찬가지로 오염된 맥락 창을 가진 에이전트가 “멍청한 구역”으로 표류하면 다른 구성 요소 안에 React 구성 요소를 선언하거나 훅 규칙을 위반하는 것처럼 명백한 국소적 실수를 하기 시작한다.
나는 이것이 가속기 선언문처럼 들리기를 바라지 않는다. 바이브코더가 옳고 AI가 코드를 보는 일을 시대에 뒤떨어진 것으로 만들 가능성에는 완전히 열려 있다. 다만 나는 아직 그 결론을 뒷받침할 만큼 설득력 있는 증거를 보지 못했다.
하지만 내가 확신하는 것은 한 가지 명백히 해로운 관행이다. 사전에 기대와 경계를 정하고 지키지 않은 채 서로 다른 접근법을 선호하는 사람들을 같은 팀에 넣는 일이다.
가속기는 저자가 유지할 의도가 전혀 없었거나 애초에 갖고 있지 않았던 이해를 재구성하는 작업을 물려받을 수 있다. 바이브코더는 우연적인 구현 선택을 설명하라는 요구를 받을 수 있다. 그가 상당한 시간을 들여 개발 프로세스를 다듬은 것은 바로 그 선택들을 의도적으로 일회용으로 만들기 위해서였는데도 말이다. 어느 쪽이든 말하지 않은 유지보수 기대를 강요하여 다른 쪽의 일을 더 어렵게 만들 수 있다.
일반적인 서신에서 필터링하지 않은 AI 산출물을 누군가에게 보내는 것은 무례하다. 그러나 이것이 코드, 의도, 그리고 운영 환경의 문제에 대한 책임과 관련되기 시작하면 예의는 엔지니어링 문제가 된다. 변경을 병합하기 전에 동료들은 그 변경이 어떻게 유지될 예정인지 알아야 한다. 개발자의 구현 이해를 통해서인지, 명세와 확립된 코드 생성 및 엄격한 테스트 프로세스를 통해서인지, 아니면 어느 부분이 어느 것인지 분명한 한 두 방식의 조합을 통해서인지 말이다.
이 모든 것이 가속기의 입장을 편안하게 만들지는 않는다.
사용하지 않는 기술은 퇴화하며, AI가 생성한 코드를 직접 타이핑하는 대신 단지 검토하는 것만으로도 상황이 요구할 때 이를 대신하고 수동 코딩으로 되돌아갈 수 있을 만큼 충분한지는 지켜봐야 한다. 주요 AI 연구소가 파산하거나 가격을 올리는 것처럼 자주 추측되던 일부 상황은 더는 걱정거리가 아닌 듯하다(필요하다면 어떻게든 계속할 수 있을 만큼 품질이 높은 공개 가중치 모델을 제공하는 곳이 많다). 그러나 우리가 예측하지 못하는 자동화의 위험이 있을 수도 있다.8여백 주석 bainbridge 8 Bainbridge, L. 자동화의 아이러니. Automatica 1983 (!!) ↩ 그리고 바이브 코딩되었거나 심지어 가속되어 만들어진 코드베이스를 물려받는 사람은 그것을 유지하기가 감당할 수 없을 만큼 어렵다고 느낄지도 모른다.
인간이 여전히 책임진다고 선언하는 일은 쉽다. 인간이 그 책임을 행사할 능력을 계속 갖도록 작업을 구성하는 일은 훨씬 더 어렵고 매우 다차원적인 의사결정을 요구한다. 가속기 접근법은 번아웃으로 가는 지름길일 수도 있다.
모든 것을 검토하려면 한 번에 얼마나 많은 낯선 작업을 할 수 있는지에 제약이 따른다. AI와 코딩할 때도 여전히 요구사항을 모델링하고 구현이 표류하지 않도록 해야 한다. 그렇지 않으면 산출물을 스스로 검토하는 일은 최악의 종류의 일이 된다. 즉, “매우 지루하지만 매우 큰 책임이 따르며, 그럼에도 책임을 처리하는 데 필요한 자질을 습득하거나 유지할 기회는 없는” 일이다.9여백 주석 bainbridge2 9 Bainbridge 1983; §1.2 ↩
이는 성공을 위해 선의 이상의 것을 요구하는 힘든 실천을 의식적으로 선택하는 일이다. 소프트웨어 개발이 언젠가 완전히 자동화된다면, 필요할 때 대신할 수 있는 사람이 곁에 있도록 프로그래머에게 기술을 유지하기 위한 수동 코딩 작업을 수행시키는 일이 소프트웨어 회사에 필요한 비용이 될 수 있다.10여백 주석 bainbridge3 10 Bainbridge 1983; §2.3 ↩
AI 혁명이 코드 검토에 대해 드러낸 듯한 사실은, 우리가 코드 자체의 품질을 신경 쓴 적은 결코 없으며 구현의 품질에 표현된 제품에 대한 이해를 신경 썼다는 것이다. 코드 품질은 Claude Code 이전 시대에는 그 이해를 가늠하는 유용한 대리 지표였지만, 이제 언어 모델은 그 이해를 설득력 있게 가장할 수 있다. 코드베이스에 생성된 코드가 존재한다는 것은 이해와 구현을 별도로 검토하는 일이 더 중요해졌음을 뜻한다.
검토자는 요구사항, 의도적인 구현 결정, 물려받은 관례, 근거가 기록되지 않은 선택을 구별해야 한다. 그 구별은 코드가 변화하는 동안에도 코드와 연결된 채 남아야 한다.
요점은 특정 코드 조각이 생성되었는지 키보드로 입력되었는지가 아니다. 사람도 설명하기 어려운 우연적인 선택을 하지만, 아주 많은 그런 선택을 하면서도 작동하는 소프트웨어를 만들기는 훨씬 더 어렵다. 에이전트는 늘 그렇게 하지만, 그렇다고 에이전트를 전면적으로 배제할 이유는 아니다. 명시적인 결정을 충실하게 구현하는 일은 여전히 충분히 가능하다.
다음 이야기를 생각해 보자. 비즈니스 요구사항은 사용자가 비밀번호 재설정 링크를 요청할 수 있고 그 링크가 만료되어야 한다는 것이다. 개발자는 특정 만료 기간을 선택한다. 에이전트는 그것을 표현하고 확인하는 방법을 선택한다. 결과 코드는 여러 곳에서 그 결정을 구현하지만, 의도는 사라진다. 나중에 독자가 expiryTime = 6h라는 값을 보면 소프트웨어가 무엇을 하는지는 알 수 있지만, 6시간은 여러 곳에서 왔을 수 있다. 명시적인 비즈니스 요구사항, 기존 관례, 숙고한 절충, 또는 아무도 이의를 제기하지 않은 추측 말이다. 값을 바꿔야 하는지 결정하려면 독자는 무엇이 그 값을 정당화했는지와 그 상황이 여전히 성립하는지를 알아야 한다. 결정의 결과는 코드에 있지만, 코드만으로는 그것을 충분히 재고할 수 있을 만큼 그 역사를 보존하지 못한다. 이것이 의도 부채이며, 코드의 모든 줄을 읽는다고 해서 그것이 상환되지는 않는다.
에이전트가 여기서 도움을 줄 수 있는 유망한 한 방법은 요약 능력을 활용하여 검토자가 그러한 관계를 추적하고 어느 선택에 설명이 없는지 보게 하는 것이다. 코드를 직접 검토한다면 Crit 같은 도구를 사용하여 구현이 의도에서 벗어나지 않았는지 확인할 수 있다. 또는 CodeRabbit의 Change Stack, 혹은 나 자신의 intent-stack 기술을 사용하여 맥락을 모으고 검토자를 위한 보조 자료를 생성할 수 있다.
자동화에 관해서는, 위임이 커질수록 생성된 코드베이스가 성장하는 가운데 지속적인 목표, 제약, 검증 기준, 관련 맥락을 보존하기가 점점 더 어려워진다. 동시에 구현을 수행하는 에이전트가 관련 맥락 조각을 우연히 발견하지 못했거나 일회용이어야 했던 정보에 권위를 부여했다는 이유만으로 모순된 결정을 내릴 수 있으므로, 코드 줄 수가 늘어날수록 그러한 보존은 점점 더 중요해진다. 그 기록은 세션이 끝나고, 에이전트가 바뀌며, 구현이 재생성될 때에도 계속 사용할 수 있어야 한다.
“소프트웨어 공장”과 “그래프 엔지니어링”을 구축하는 여러 실험은, 요약의 점점 더 프랙탈한 구조로 의도를 목록화하여 그 위임을 의도적으로 만들려는 시도처럼 보인다. 그렇게 하면 트리, 그래프 또는 에이전트 무리가 자신과 관련 없는 것으로 서로의 맥락 창을 오염시키지 않고 서로 다른 일반성 수준에서 소통할 수 있다. 나는 이 접근법과 그다지 잘 맞지는 않지만, 합리적인 출발점은 두 가지 규칙으로 운영되는 Strong DM의 소프트웨어 공장에 관한 설명을 검토하는 것일 수 있다. 사람은 코드를 작성하지 않고, 사람은 코드를 검토하지 않는다. 대신 코드베이스 밖에 보관된 시나리오에 대해 에이전트의 작업을 검증한다.11여백 주석 wsff 11 반대되는 견해는 Horthy, D. 소프트웨어 공장이 실패하는 이유를 보라↩
그렇다면 AI 지원 프로그래밍에는 적어도 두 종류의 진보가 있다. 하나는 개발자가 구현을 이해하고 상호작용하도록 돕고, 다른 하나는 그 상호작용의 필요 자체를 없애려 한다. 후자가 더 많은 주목을 받는 듯하지만, 이들은 서로 다른 길이고 서로 다른 도구와 접근법을 요구한다. 둘 다 개선될 수 있지만, 그렇다고 가속기의 목표가 바이브코더가 되는 것이라는 결론이 나오지는 않는다. 코드 읽기를 그만두는 일은 그 자체로 진보가 아니다.
하지만 동료가 아직도 코드를 읽는지 묻기 전에, 당신이 아직도 그에게 당신의 코드를 유지보수해 주기를 기대하는지 생각해 보는 편이 좋겠다.