대형 LLM이 나왔을 때 처음 시험해 본 일은 개발 중이던 프로젝트의 리팩토링이었다. 바로 코드를 고치게 하지는 않았다. 먼저 시스템마다 어울리는 디자인 패턴을 검토하게 했다.
클린 아키텍처를 적용하려고 현재 구조를 다시 점검하는 과정에서, 내가 미처 생각하지 못했거나 그냥 넘겼던 구조적 결함이 하나둘 드러났다. 그 결함을 고치고 나온 결과물은 내가 쓴 코드보다 구조가 좋았다.
지금 돌아보면 가치는 코드를 생성한 단계보다 그 앞 단계에서 나왔다. AI는 작성자이기 전에 내 코드의 리뷰어였다. 그리고 그 판단이 맞다고 확인할 수 있었던 건, 원래 코드를 누구보다 잘 아는 사람이 나였기 때문이다.
그 경험 이후로 나는 코드를 읽지 않게 됐다. 이상한 일이다. 내가 깊이 알던 코드에서 얻은 신뢰를, 지금은 읽지도 않는 코드에 그대로 적용하고 있으니까.
무엇을 믿고, 무엇을 믿지 않기로 했나
코드를 읽지 않는다고 검증을 그만둔 것은 아니다. 믿는 대상과 믿지 않는 대상을 나눴을 뿐이다.
예전에도 리뷰는 빨랐다. 다만 그때는 근거가 있었다. 내가 코드 작성에 직접 참여했기 때문에 변경점만 봐도 맥락을 알 수 있었다. 지금은 그 근거가 없다. 그래서 신뢰의 자리를 다시 정해야 했다.
- 코드 수준의 정합성은 AI를 믿기로 했다. 함수가 제대로 동작하는지, 읽기 좋게 짜여 있는지는 이제 내가 보는 것보다 나을 때가 많다. 증명한 것은 아니고, 내 시간을 어디에 쓸지 정한 선택이다.
- 아키텍처와 구현 방향은 믿지 않는다. 책임이 어디에 놓여야 하는지, 모듈이 무엇을 불러도 되는지는 프로젝트의 맥락과 의도를 알아야 판단할 수 있다.
리팩토링 때 AI가 짚은 것이 바로 구조적 결함이었으니, 아키텍처를 믿지 않는다는 말은 이상하게 들릴 수 있다. 구분은 이렇다. 그때 AI는 결함을 제안했고, 맞는지 판정한 것은 나였다. 제안은 지금도 받는다. 넘기지 않는 것은 판정과, 판정의 기준을 정하는 일이다.
국방 연구개발에서 익숙한 V&V 구분을 빌리면 이렇게 정리된다. 명세대로 만들었는지 확인하는 일(verification)은 기계에 넘기고, 맞는 것을 만들고 있는지 판단하는 일(validation)은 사람이 쥔다.
검증을 한 층 위로 올리기
코드를 보지 않는 대신, 코드가 정해 둔 설계를 따르는지를 확인하기로 했다. 그래서 BATON이라는 도구를 만들고 있다.
BATON은 다이어그램과 정리된 정의 문서를 기준으로 놓고, 구현이 그 기준대로 가고 있는지를 판정한다. 판정은 두 가지 방식을 함께 쓴다.
- 구조 추출: 코드에서 모듈 의존성과 인터페이스를 뽑아 설계와 기계적으로 비교한다. 결과가 매번 같다.
- LLM 판정: 문서와 코드를 함께 읽혀 의도대로 구현됐는지를 묻는다. 구조로는 안 보이는 책임과 흐름을 볼 수 있다. 대신 같은 입력에도 결과가 달라질 수 있다.
이렇게 하면 내가 직접 보는 대상이 변경된 코드 전체에서 몇 장의 문서로 바뀐다. 볼 양은 줄고, 내가 아니면 내릴 수 없는 판단에 시간이 간다.
돌이켜 보면 리팩토링 때와 같은 원리다. 그때도 클린 아키텍처라는 명시된 기준이 있었기에 결함이 드러났다.
품질은 명시된 기준에서 나온다.
예상하지 못한 효과: 문서가 살아났다
내 작업에 먼저 적용해 검증을 산출물 기준으로 바꾸자, 산출물이 즉각적으로 최신화되기 시작했다. 처음에 기대한 효과는 아니었다.
설계가 끝나고 개발이 진행되면 산출물은 낡기 마련이다. 우리 팀도 그랬다. 코드는 바뀌는데 다이어그램은 설계 시점에 멈춰 있고, 단계 말이 되면 몰아서 맞추는 일이 반복됐다. “문서를 갱신하자”는 규칙과 의지로는 잘 풀리지 않았다.
지금은 문서가 검증의 정답지다. 문서가 현실과 다르면 검증이 실패한다. 그러니 구현 방향이 바뀌면 문서부터 고치게 된다. 고치지 않으면 다음 작업이 나아가지 않기 때문이다.
규칙이 아니라 구조가 동기를 만든 경우다. 개발 프로세스 표준화를 하면서 가장 크게 배운 점이기도 하다. 사람을 닦달하는 규칙보다, 지키지 않으면 일이 진행되지 않는 구조가 더 오래 간다.
코드를 못 읽는 사람도 검증에 들어왔다
아직 팀 전체에 적용하기 전이다. 다만 이 방향을 설명했을 때 반응은 긍정적이었고, 특히 비개발자들이 반겼다.
이유를 생각해 보면 이렇다. 검증의 기준이 코드에 있을 때는 코드를 읽는 사람만 검증에 참여할 수 있었다. 기준이 문서로 올라오자, 기획자나 과제 관리 담당자도 “설계대로 가고 있는가”를 같은 기준으로 볼 수 있게 됐다.
국방 과제에서는 이 점이 더 크게 다가온다. 요구를 제기하는 쪽과 평가하는 쪽은 대개 코드를 보지 않는다. 그들과 개발팀이 같은 문서를 보며 이야기할 수 있다면, 검증은 개발팀만의 일이 아니게 된다.
설명을 들었을 때의 반응과 실제로 써 본 뒤의 반응은 다를 수 있다. 그 이야기는 적용 후에 다시 쓰려고 한다.
아직 답하지 못한 질문들
이 방식이 답이라고 말하려는 것은 아니다. BATON은 아직 개발 중이고, LLM 판정은 계속 튜닝하고 있다. 검증의 자리를 옮기고 나니 새로운 질문이 생겼다.
- 설계와 일치한다고 맞는 것은 아니다. 구조가 다이어그램과 같아도 동작은 틀릴 수 있다. 동시성, 예외 처리, 실시간 제약처럼 다이어그램에 잘 드러나지 않는 영역은 누가 보나.
- 문서가 정답이 되면, 문서가 검증 대상이 된다. 문서가 틀리면 도구는 틀린 것을 맞다고 확인해 준다.
- 검증 도구는 누가 검증하나. LLM이 만들고, LLM이 판정하고, LLM이 그 판정을 점검하면 고리가 안에서 닫힌다. 판정 결과가 매번 같지도 않다. 바깥에 기준점이 하나는 있어야 한다.
지금의 잠정 결론은 이렇다. 사람의 자리는 코드를 읽는 곳에서 기준을 세우는 곳으로 옮겨 간다. 설계 문서를 쓰고, 무엇이 정답인지 정하고, 그 정답으로 도구를 검증하는 일이다.
국방 연구개발은 원래 검증이 병목이었던 분야다. 시험평가, 형상통제, 산출물 체계가 두껍게 쌓인 것도 그 때문이라고 본다. 무겁다고만 여겨졌던 그 문화가, AI가 코드를 쓰는 시대에는 짐이 아니라 자산이 될 수도 있다고 생각한다.
다음 글에서는 위 질문들을 하나씩 더 파고들고, 팀에 적용한 뒤의 이야기를 쓰려고 한다.