에이전트 시대의 코드 품질

TMT

https://addyo.substack.com/p/agentic-code-quality

오랫동안 우리는 코드 품질을 코드 리뷰로 평가해 왔습니다. 누군가 작성된 코드를 읽고 깔끔한지, 충분히 고민했는지, 빠른지, 이해하기 쉬운지, 테스트가 잘 되는지 확인하는 방식이었습니다. 하지만 에이전트에게는 이 방식이 잘 통하지 않습니다. 사람이 다 읽기에는 코드가 너무 많기 때문입니다. 그래서 품질 검사의 점점 더 많은 부분이 에이전트를 둘러싼 하니스, 환경, 운영 체계 안에서 이루어져야 합니다.

이제 소프트웨어 품질은 에이전트 주위에 어떤 제약을 세우느냐에 달려 있습니다.

Image

제약은 에이전트가 내놓은 제안에 테스트와 결정적(deterministic) 검사를 들이대는 방식으로, 시스템이 무엇을 해도 되는지를 규정합니다. 이런 제약을 세우고 유지해야, 에이전트가 매일 수십만, 수백만 건의 변경을 만들어내는 상황에서도 고품질 프로덕션 소프트웨어를 안정적으로 내놓는 루프를 만들 수 있습니다.

Image

이런 제약을 품질 게이트(quality gate)라고 부르며, 형태는 다양합니다. 전통적인 단위 테스트, 속성 기반 테스트, 인수 테스트가 여기에 포함됩니다. 코드의 변형본을 만들어 같은 테스트에 돌려 보면서 우리가 놓치고 있는 버그가 몰래 끼어들지 않는지 확인하는 뮤테이션 테스트도 있습니다. 순환 복잡도나 줄 길이처럼 코드를 읽기 좋게 유지해 주는 코드 품질 지표도 제약입니다. 제약은 시스템이 어떤 제안을 코드 변경으로 받아들여 적용할지 정하는 데에도 중요한 역할을 합니다. 변경 제안이 에이전트를 실행하는 인터프리터에서 에이전트 컨트롤러를 거쳐 프로덕션까지 나아가는 동안 충분한 검사를 거치기 때문에, 배포해도 안전하고 변경의 영향이 에이전트의 권한 범위 안에 있다고 확신할 수 있습니다.

에이전트는 무엇이든 제안할 수 있습니다. 그 제안이 배포해도 될 만큼 안전하고, 올바르고, 범위를 지키고, 쓸모 있는지는 여러분과 팀이 세운 제약이 판정합니다.

이 모델은 많은 것을 제공하지만 빠뜨리는 부분도 많고, 그 빈틈은 지금 고민해 볼 가치가 있습니다. 하나는 자율성 문제입니다. 에이전트는 의도한 바를 잘 수행하다가도, 정보가 부족하거나 하려는 일이 모호하면 실패할 수 있습니다. 이는 과제 자체에도, 하니스·환경 등 여러 구성 요소가 과제 조건을 정하는 방식에도 똑같이 적용됩니다. 사람이 좋은 코드를 내놓지 못하는 이유의 상당수는 에이전트가 겪는 문제와 겹칩니다. 스크립트가 몰아붙이는 부하를 견디지 못하는 취약한 환경, 돌릴 때마다 결과가 달라지는 빌드, 빠져 있는 권한, 부실한 테스트 같은 것들입니다. 그래서 에이전트에게 믿을 수 있는 피드백을 주고, 실패해도 피해가 작게 끝나며, 성공을 조금씩 쌓아 가기 쉬운 더 나은 환경이 필요합니다.

Image

우리가 바라는 환경은 에이전트가 실질적인 작업을 하고, 믿을 수 있는 피드백을 받고, 실패해도 큰 피해를 남기지 않는 환경입니다.

또 하나 중요한 문제는 신뢰입니다. 아무리 똑똑하고 견고한 최신 에이전트라 해도, 올바른지 확인하지 않은 채 의도를 덥석 맡길 수는 없습니다. 신뢰를 전제로 시작하되, 그 신뢰는 힘들여 얻어내야 하는 것입니다.

Image

어떤 제약은 작업이 시작되기 전에 방향을 잡아 줍니다. 어떤 제약은 에이전트가 일하는 동안 피드백을 줍니다. 또 어떤 제약은 결과물이 프로덕션 경계를 넘어도 되는지를 판정합니다.

시스템 주위에 검증 구조를 세우는 방식을 모델링하는 방법은 여러 가지입니다.

제 경험상 단위 테스트에만 기대기보다는, 더 폭넓되 의도적으로 고른 검사 묶음을 제약으로 두는 편이 좋습니다. 핵심은 검사마다 고유한 책임을 갖게 하는 것이고, 그 범위는 타입 안전성과 성능부터 후반 단계의 보안 스캔까지 걸쳐 있을 수 있습니다. ESLint 같은 린트 도구로 강제할 수 있는 아키텍처 규칙을 비롯해, 제약을 직접 정의할 수도 있습니다. 이런 도구 상당수에는 내장 훅이 있어서, 무언가 깨졌을 때 에이전트나 사람을 불러들이는 데 쓸 수 있습니다.

지금으로서는 쓸 만한 에이전트 산출물과 조잡한 결과물(slop)의 차이 대부분이 여전히 이 루프를 운영하는 팀의 역량에 달려 있습니다.

AI 덕분에 코드를 대량으로, 빠르게 만들어낼 수 있지만, 그만큼 사람이 모든 변경을 하나하나 리뷰하기는 어려워집니다. 대신 사람의 주의를 어디에 쓸지 의도적으로 정해야 합니다. 기계 속도로 움직이는 시스템에 사람의 검사를 끼워 넣으면 생산성이 떨어지는 것은 당연한 일입니다. 사람의 주의력은 희소하고 귀하므로, 우리의 판단이 꼭 필요한 가장 미묘한 문제에 먼저 배정해야 합니다. 하류의 사람은 제약을 지키는 자동 가드레일이 깨졌을 때에만 불러들여야 합니다.

앞으로 사람이 하는 '코드 리뷰'는 지금과 사뭇 다른 모습이 될 것입니다.

정확성은 중요한 축 하나일 뿐이고, 유지보수성, 성능, 보안, 효율, 이해하기 쉬움 같은 다른 축도 중요할 수 있습니다. 정확성이 여러 종류의 신호로 쪼개지듯, 나머지 품질 요소도 마찬가지입니다. 그리고 제약을 몇 개나 두었느냐보다, 그 제약이 우리가 정한 품질과 프로덕션 준비 기준을 충족할 만큼 까다로운가가 더 중요합니다.

소프트웨어 품질은 지표 하나로 잴 수 있는 것이 아닙니다. 여러분과 팀에게 중요도가 제각각인 신호들의 모음이라고 생각하세요.

배압(back-pressure)은 여러 도구로 구현할 수 있습니다. 컴파일러가 잘못된 코드를 거부하고, 테스트가 실패하고, 보안 정책이 나쁜 관행을 막고, CI가 배포를 거절하는 식입니다. 이상적으로는 모든 작업이 끝난 뒤 맨 마지막에 한 번 하는 리뷰가 아니라, 루프 전체에 걸쳐 존재해야 합니다.

제약과 배압이 있으면 에이전트의 나쁜 작업을 문제가 되기 전에 잡아낼 수 있습니다.

변경량이 도구가 소화할 수 있는 수준을 넘어서 제약을 적용할 수 없게 되면 어떻게 될까요? 결국 대기열이 쌓이고, 사람 속도로 움직이는 검증 시스템에 기대게 됩니다. 규모를 키우려면 검사를 끝까지 미루지 말고 가능한 한 많이 과정 곳곳의 검증 루프 안으로 밀어 넣어야 합니다. 자동 검사 안에서 규모를 키울 수 있으면 전체 딜리버리 시스템의 속도와 처리량을 높일 수 있습니다. 검증 루프에 여유가 바닥나면 몇 가지 중 하나를 해야 합니다. 첫째, 검증 시스템을 확장해서 들어오는 변경을 제약하고 밀어낼 수용량을 더 확보할 수 있습니다. 둘째, 에이전트가 새 변경을 만들어내는 속도를 줄여서 검증이 작업량을 따라잡게 할 수 있습니다. 셋째, 품질 기준을 낮춰서 검증이 그만큼 세게 밀어내지 않게 할 수 있습니다. 확장 관점에서는 이 모든 것을 할 준비가 되어 있어야 합니다. 동시에, 어떤 방향에서는 오히려 제약을 풀어야 더 많은 일을 해낼 수 있다는 사실도 놓치지 말아야 합니다. 에이전트 개발자 무리(swarm)나 자동화된 소프트웨어 공장을 투입해서, 변경 하나하나를 우리가 리뷰해 줄 때까지 기다리지 않고 만들어내게 하면 에이전트가 변경을 만들어내는 속도를 더 높일 수 있을지도 모릅니다.

그리고 어떤 영역에서는 다른 영역의 제약을 더 조이는 대신 에이전트에게 더 많은 자유를 주고 싶을 수도 있습니다. 가장 중요하게 여기는 곳에 더 엄격한 제약을 두면, 품질을 희생하지 않으면서 처리량을 최대로 끌어올릴 수 있습니다. 이런 결정 과정 내내 선택지는 많습니다. 가장 분명한 것은 품질의 여러 축 사이에서 저울질을 해야 한다는 점입니다. 앞서 강조했듯 보안은 매우 중요하지만, 보안을 지키는 일과 제품을 제때 내놓는 일 사이에서도 저울질을 해야 했습니다. 한쪽 끝에는 혁신 중심, 반대쪽 끝에는 품질 중심이 있는 스펙트럼이 있고, 그 위 어디에 설지는 어느 시점엔가 선택해야 합니다.

환경과 시스템에서 나오는 명확한 피드백을 에이전트나 팀에 돌려주어, 사람은 취향, 의도, 아키텍처처럼 더 주관적인 문제에 집중할 수 있게 해야 합니다. 사람이 제약의 안전 범위 안에 머물도록 도울 수 있다면, 어디서부터 잘못됐는지 찾느라 애쓸 필요가 없어집니다.

소프트웨어 품질은 정확성만을 뜻하지 않습니다. 유지보수성, 좋은 성능, 보안, 효율, 이해하기 쉬움도 모두 소프트웨어 품질입니다. 이런 기준을 충족하고 프로덕션이 계속 흘러가게 해 주는 모든 제약이 딜리버리 파이프라인에 배압을 만들어냅니다.

강한 제약을 어디에 적용하고 어디서 없애거나 완화할지는 신중하게 결정해야 합니다. 두 가지 목표 모두에 기여하는 곳에는 강한 제약을 적용하세요. 어느 한쪽에도 기여하지 못한다면 유지하지 마세요. 상황에 따라 기준을 올리거나 내릴 준비를 해 두세요. 그리고 소프트웨어 시스템 곳곳에 자리한 이런 제약이야말로 소프트웨어 품질을 강제할 수 있게 해 주는 장치임을 기억하세요.

이 두 가지 목적에 가장 잘 기여할 곳에 강한 제약을 적용하고, 어느 쪽에도 별로 기여하지 못하는 제약은 없애거나 완화하는 것을 검토해야 합니다. 필요에 따라 품질 기준을 올리거나 내릴 준비도 되어 있어야 합니다. 결국 소프트웨어 시스템 곳곳에 있는 이런 제약이 품질에 실질적인 힘을 실어 줍니다. 많은 경우 새 도구를 도입하거나 이미 있는 도구를 강화하는 것만으로 배압과 제약을 더 만들어낼 수 있습니다. 이 모든 것을 대부분의 변경 요청을 밀어내는 데 쓸 수 있습니다. 이런 장치는 파이프라인 전체에 걸쳐 세워야 합니다. 파이프라인 맨 끝에서 CI 시스템이 문제를 고치기 전에는 배포할 수 없다고 통보할 때까지 기다려서는 안 됩니다. 가능한 모든 경로를 통해, 이런 신호를 최대한 이른 시점에 활용해야 합니다. 이 시스템의 궁극적인 제약은 시스템을 만들고 운영하며 내린 결정과 행동을 스스로 책임지겠다는, 우리 자신에게 거는 제약입니다. 하지만 다른 모든 제약과 마찬가지로, 우리 자신의 판단이 얼마나 억제하고, 얼마나 배압을 걸고, 얼마나 최종 점검 역할을 하게 할지는 신중하게 저울질해야 합니다.

품질은 에이전트 주위에 우리가 세워 둔 제약 속에 있습니다. 여러분의 앱 품질을 고민할 때도 이 문제 정의를 가져다가 자신만의 제약 중심 계획을 세워 보세요.

이 글은 Pangram 4에서 100% 사람이 쓴 글로 판정받았습니다. 품질 게이트를 구축할 좋은 출발점을 찾고 있다면 Sonar가 꽤 괜찮은 해법이라는 점도 다시 알려드립니다.

Edit this page

On this Page

No Headings