AI가 작성한 코드는 '작동'한다. 하지만 '수정'할 수 있는가? — 병목 지점은 '쓰기'에서 '읽고 수정하기'로 이동했다
요약
AI가 생성한 코드는 작동하지만, 시간이 지나 수정하기 어렵다는 문제점을 지적합니다. 개발의 병목 지점이 코드 작성(쓰기)에서 읽고 이해하며 안전하게 변경하는 작업으로 이동했으며, 이는 기술 부채와 관련됩니다.
핵심 포인트
- 개발 생산성의 병목은 '쓰기'에서 '읽고 수정하기'로 이동했다.
- AI는 작동하는 코드는 만들지만, 장기적인 유지보수성을 고려하지 않는다.
- 코드의 가치는 작성 순간이 아닌, 변경되어 지속되는 기간의 총합으로 결정된다.
- 앞으로는 코드에 명명(naming), 책임 분리 등 '읽고 수정할 수 있는 형태'를 부여하는 능력이 중요하다.
AI에게 코드를 작성하게 하면, 대체로 작동합니다. 테스트를 작성하게 하면, 대체로 통과합니다. 그렇다면 그 코드는 반년 후, 다른 담당자가 안전하게 변경할 수 있을까요?
이 질문에 즉답할 수 없다면, 보고 있는 것은 '생산성이 높아졌다'는 착각일 수 있습니다. 생산성이 높아진 것이 아니라, 비용이 뒤로 미뤄졌을 뿐인 경우가 있습니다. 게다가 까다로운 점은, 병목 지점 자체가 '쓰기(書く)'에서 '읽고 수정하기(読む・直す)'로 이동하고 있다는 것입니다. 작성 속도가 아무리 빨라져도, 그 부분은 빠르게 되지 않습니다.
소프트웨어의 가치는 작성하는 순간이 아니라, 변경되어 계속되는 기간의 총합으로 결정됩니다. 어느 시점에서 올바르게 작동하는 코드라도, 사양 변경(仕様変更), 버그 수정, 기능 추가가 있을 때마다 안전하게 손댈 수 없다면, 그때마다 비용이 발생합니다. 이를 통속적으로 '기술적 부채(技術的負債)'라고 부릅니다. 부채라는 비유가 좋은 이유는, 빌린 순간은 이득을 보는 것처럼 보이지만, 상환(나중의 수정) 타이밍에 이자가 붙은 청구가 온다는 시간차가 있기 때문입니다.
AI가 코드를 작성할 경우, 이 시간차가 더욱 노골적으로 드러납니다. AI는 '주어진 입력에 대해 올바른 출력을 반환하는' 것에는 강합니다. 하지만 '이 코드는 반년 후의 나 자신이나 타인에게 읽기 쉬운가', '변경 영향 범위 추적이 용이한가'는 AI에게 최적화 대상이 되는 경우가 많지 않습니다. 발주 측에서 이를 명시적으로 요구하지 않는 한, AI는 "작동함"을 충족하는 시점에서 멈춥니다.
예를 들어 다음과 같은 처리를 부탁했다고 가정해 봅시다. '주문 목록에서 취소되지 않은 주문의 총 금액을 계산해 주세요.' AI는 이렇게 반환할 수 있습니다.
def calc(orders):
total = 0
for o in orders:
...
이는 요구 사항대로 작동합니다. 테스트 케이스를 2~3개 던져도 통과합니다. 하지만, 반년 후에 이 함수를 변경하는 입장에서 읽어보면 여러 곳에서 걸립니다.
먼저 명명 규칙입니다. calc
무엇을 계산하는지 함수 이름만으로는 알 수 없습니다. 호출한 쪽을 읽어야 의도를 추적할 수 있습니다. 다음은 책임의 혼재입니다. '취소 제외'라는 비즈니스 규칙과 '총 금액 산출'이라는 계산 로직이 같은 루프 안에 묻혀 있습니다. 장래에 '환불된 주문도 제외하고 싶다'는 요구 사항이 왔을 때, 이 if 조건을 수정해야 할지, 다른 함수로 분리해야 할지에 대한 판단 자료가 코드 어디에도 남아있지 않습니다.
게다가 `o.get(
과거에는 개발 시간의 대부분이 '쓰는' 작업에 할애되었다. 따라서 쓰는 속도가 생산성의 병목 지점이었다. AI가 구현을 저렴하고 빠르게 공급할 수 있게 된 지금, 병목은 '그 코드를 읽고, 의도를 이해하며, 안전하게 변경하는' 작업으로 이동했다. 코드 리뷰에 필요한 시간, 사양 변경 시 영향 범위를 조사하는 시간, 테스트가 사양을 나타내는지 확인하는 시간—이러한 것들은 쓰는 속도가 빨라져도 단축되지 않는다. 오히려 AI가 생성하는 코드의 양 자체가 늘어나면, 읽고 리뷰하고 수정해야 할 대상이 증가하여 이 공정의 부하가 높아진다.
여기서 비자명적인 전환이 일어난다. AI가 구현을 저렴하게 공급하는 시대에 상대적으로 가치가 높아지는 것은 '쓰는 능력'이 아니다. AI의 출력물에 대해 명명(naming), 책임 분리, 테스트, 경계(인터페이스나 전제 조건)를 부여하여 '읽고 수정할 수 있는 형태'로 다듬을 판단력이다. 앞선 예시에서 말하자면, calc
을 calculate_active_order_total
과 같은 의도가 읽히는 이름으로 바꾸고, 취소 판정을 별도의 함수로 분리하며, '수량 미지정은 1건으로 간주한다'라는 암묵적인 전제를 주석이나 테스트 케이스로 명문화하는—이러한 작은 수고가 AI에게 위임하기 어렵고 사람에게 남는 일이다.
AI가 만든 코드를 그대로 병합할지 말지를 '작동했는지 여부'만으로 판단하는 것은 이제 너무 거칠다. 대신 물어봐야 할 것은, '이 코드가 지금의 나 외에 다른 사람이 반년 후에 안전하게 변경할 수 있는 상태인가?'이다. 이 기준은 특별한 것이 아니다. 리뷰에서 한 번쯤 들어봤던 질문을 AI 시대에 의식적으로 적용하는 것일 뿐이다. 구체적으로 다음 4가지를 본다.
- 함수명이나 클래스명이 처리 절차가 아닌 의도를 나타내는가?
- 하나의 함수나 클래스가 여러 책임을 (판정 로직과 계산, 조회와 가공 등) 지니고 있지는 않은가?
- 경계값(Edge Case)이 테스트로 언어화되어 남아 있는가? (0건, null, 극단적인 값 등 입력 측면에서 기인하는 경우)
- 암묵적 전제(예외의 무시, 기본값 보완, 부작용 유무 등 구현 측면의 판단에 기인하는 것)가 코드 외부에 그대로 방치되어 있지 않은가?
여기에 걸리는 것이 있다면, 동작 확인이 통과했더라도 그 자리에서 수정한다. 이름을 바꾸거나, 책임을 분리하거나, 놓쳤던 케이스를 테스트로 작성해 넣는다—이러한 작은 수고는 종종 몇 분이면 끝나지만, 하지 않으면 반년 후에 몇 배의 시간으로 되돌려 받게 된다. AI에게 맡길 범위가 넓어질수록, 이 수용 기준을 스스로 가지고 있는지가 팀의 유지보수 비용을 결정한다.
'쓰는 능력'은 AI가 대체하기 쉽다. '읽고 수정할 형태로 다듬는 판단력'은 현재로서는 사람에게 남아있다. 어느 쪽에 시간을 투자할지는 더 이상 선택의 여지가 있는 질문이 아니다.
설계나 가독성에 관한 정석적인 서적이 실제로 얼마나 많이 읽히고 추천되는지는 데이터로 확인할 수 있다. 관심 있는 분들은 아래를 살펴보시기 바란다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기