가상의 1:1 면담을 떠올려 보자.

관리자: “앨리스(Alice)의 코드를 더 빨리 검토해야 해. 네가 검토를 늦추면서 신규 고객 백만 명을 데려올 엄청난 기능 Foo가 막혀 있어.”

밥(Bob): “검토하려고 하고 있어요. 하지만 1만 줄짜리 PR 다섯 개가 차례로 쌓여 있어요.”

관리자: “그러고 보니 네 기능 Bar는 왜 이렇게 오래 걸리지?”

밥: “저는 LLM을 간단한 작업에만 쓰려고 해요. 테스트나 문서 같은 것들이요—”

관리자: “LLM을 충분히 활용하지 않는군. 앨리스처럼 해야 해. 앨리스는 일을 해내고 있잖아.”

밥: “그럼 PR을 더 빨리 훑어보고, 그동안 LLM에게 Bar를 만들게 해야겠네요.”

관리자: “바로 그거야, 닷(Dot). 점심이나 배달시켜 줘!”

다시 정렬 문제가 생겼다. 경영진은 일을 빨리 끝내길 원하고, 엔지니어링 조직은 일을 제대로 하길 원한다. 이는 신기술과 구기술의 대립이 아니라 보상의 문제다. 기능을 빨리 내는 일이 유지보수성보다 우선시됐다. 버그가 생기면 Claude에게 맡겨 고치면 된다는 식이다.

LLM은 시니어 개발자에게 사실상 이길 수 없는 선택을 내놓았다. LLM을 받아들여 유지보수하기 어려운 코드를 만들어 내거나, ‘장인형’ 개발자로 남아 새 기술을 쓰는 이들에게 세 배나 뒤처지거나 둘 중 하나다. 엔지니어는 유지보수성과 품질을 계속 말할 수 있지만, 어느 순간 경영진은 코드베이스를 다루기 어렵다고 불평하지 않고 “그냥 작동하는” LLM으로 이들을 대체할지도 모른다. 존 헨리는 기계를 이겼을지 모르지만, 그 대가는 무엇이었을까.

LLM이 만드는 문제는 코드 자체보다 코드에 담긴 판단에 있다. LLM은 함수를 호출하는 함수가 다시 다른 함수를 호출하는 구조를 즐겨 만든다. 단일 책임 원칙에 비춰 어느 정도는 타당해 보일 수도 있지만, 언제 그런 구조를 적용해야 하는지 판단하는 감각은 부족하다. 함수형 프로그래밍을 막 배운 개발자가 갑자기 모든 것을 하스켈로 써야 하고 전부 순수 함수여야 한다고 여기는 것과 비슷하다.

설계 판단이 조금 어색해도 아키텍처 자체는 꽤 탄탄할 수 있다. 문제는 그런 판단이 낳은 코드를 검토하기가 악몽처럼 어렵다는 점이다. 함수 사이를 계속 오가며 참조를 찾고, 모델 버전이나 작성 시점에 따라 코드가 일관되지 않은 점까지 살펴야 한다. 코딩 규칙 파일을 길게 작성해도 모든 경우를 다룰 수는 없다. 좋은 소프트웨어를 만드는 일은 컴퓨터 ‘과학자’인 우리가 인정하고 싶어 하는 것보다 훨씬 더 많은 판단을 요구한다.

버그를 고치려 할 때 LLM 도입 전후의 코드가 함께 있는 코드베이스를 다뤄 본 사람이라면 어느 부분을 보고 있는지 알 수 있다. 어떤 부분이 엉성한 코드인지도 매우 분명해진다.

시니어 엔지니어에게 이 일은 지치는 경험이다. 좋은 코드가 어떤 모습인지, 어떻게 작동해야 하는지 안다. 다루기 즐거운 코드와 재앙 같은 코드도 안다. 그런데 코드베이스는 왜 이렇게 빨리 나빠졌을까? AI가 쓴 코드도 사람이 검토했을 텐데 말이다.

여기에는 답이 없을지도 모른다. 도구가 바뀌어야 할 수도 있고, 모델이 바뀌어야 할 수도 있으며, 아무것도 바뀔 필요가 없을 수도 있다. 개발자들이 그저 자신을 향해 날아오는 아름다운 불덩이를 바라보는 공룡일 수도 있다. 어쩌면 우리는 모두 심장이 멎을 때까지 있는 힘껏 달리며, 불덩이보다 먼저 산을 넘기를 바라는 중인지도 모른다.