bh2980.dev
에세이·

AI가 뱉어낸 코드의 숲에서 길을 잃지 않으려면

  • #AI

AI 모르면 간첩

요즘 AI로 개발하는 건 특별한 일이 아닙니다. 저 역시 블로그 초안부터, 코드 리뷰, 구조 점검까지 개발과 일상을 통틀어 여러 방면에서 AI를 사용하고 있습니다.

특히나 최근에 모 대란이 발생하면서 여러 가지를 시도해보고 있는데 이게 굉장히 재미있더군요. 내 아이디어가 요청 하나면 실제 제품이 되는 것을 보면, 생산자의 가치가 어디로 가느냐와는 별개로 누구나 생산 주체가 되기 쉬운 세상이 온 것은 틀림이 없습니다.

테스트는 통과하는데…

AI를 개발에 사용해보면서 느낀 점은 만드는 과정을 획기적으로 단축시켜주지만, 이를 믿고 무작정 달리다 보면 길을 잃는다는 점이었습니다. AI는 계속해서 코드를 뱉어냅니다. 나름의 논리로 그럴듯한 코드를 작성하지만, 한 번에 조망할 수 있는 범위에는 결국 컨텍스트라는 한계가 있습니다. 심지어 컨텍스트가 길어질수록 성능이 떨어지기까지 하니, AI에 의존적인 개발은 의도하든 아니든 어느 정도 기도에 의존할 수밖에 없습니다.

제가 이를 명확하게 깨달은 건 현재 개발하는 서비스를 AI만으로 한 번 개발해보려고 시도했을 때였습니다. 모든 테스트가 완벽하게 통과하는 코드가 동일한 스키마를 다른 방식으로 여러 군데서 중복 선언해서 임시로 땜빵해놓는 걸 보는 순간, AI는 더 이상 든든한 동반자가 아니라 그저 코드를 뱉어내는 뽑기 기계가 될 뿐이었습니다.

더불어 사용자의 요청 사항을 끝까지 따르는 게 아닌 중간에 타협해서 개발해버린다면… 프로젝트를 추적하는 일이 굉장히 힘들어지게 됩니다. 이런 현상이 특히 에서 심한데, 모델 자체의 지능과는 별개로 Codex는 사용자의 요청이 클 경우 이를 안전하게 개발할 수 있도록 알아서 멋대로 작게 나누려는 경향이 있습니다.

이 현상의 문제는 수많은 컨텍스트 위로 스쳐 지나간 말을 딸깍-하는 사용자가 일일이 기억하지 않는다는 점입니다. 때문에 실제로는 요청사항이 완료되지 않았는데 다음 개발을 진행하거나, 제대로 검증되지 않은 채로 개발이 진행되는 경우가 많았습니다.

이런 일이 겹치고 겹치다보면 내가 지금 어디까지 진행했고, 어떤 구조로 개발되어가고 있으며, 목표치에는 얼마나 다가갔는지 도무지 알 수 없게 됩니다. 기능이 정말 완성된 것인지도 의문이고, 결과물이라고 내놓은 내부 로직도 사실상 블랙박스가 되는 거죠.

이를 해결하기 위해 AI의 발전을 믿고 있을 수도 있지만, 안타깝게도 아직 그런 단계는 아닌 것 같습니다. 물론 근시일 내로 그런 시대가 올 것 같긴 합니다만 저는 현재를 살고 있으니까 해결 방법을 찾아야 했습니다.

기능은 개발 단위가 아니다

보통 우리는 AI에게 행동 중심의 기능을 개발해달라고 요청합니다. 예를 들어, "프로필 업데이트 기능을 추가해줘"라던가 아니면 "메모 작성 기능을 추가해줘"와 같은 기능의 개발을 프롬프트로 요청하는 거죠.

문제는 이런 기능 단위가 건드리는 범위가 추적 가능한 범위와 일치하지 않는다는 것입니다. 프로필 업데이트 기능을 구현할 때도, 단순히 UI 하나에 끝나지 않고 데이터베이스, 인증 로직, API 엔드 포인트까지 다양하게 뻗어나갑니다.

또한 각 기능 사이에는 선행 관계가 명확하지 않은 경우가 존재합니다. 쉽게 말해, A 기능이 개발되려면 B 기능이 개발되어야 하는데, B 기능의 일부 역시 A 기능이 개발되어야 개발할 수 있는 요상한 상태가 발생합니다.

즉, 우리가 AI에게 요청하는 기능은 개발 과정을 추적하기에는 너무 크고, 순서대로 정렬할 수 없습니다.

숲에서 나침반 찾기

결국 문제는 우리가 AI에게는 무엇만 말하고, 어떻게는 AI의 판단에 맡겨버린 데 있습니다. LLM은 같은 상황에서도 항상 같은 판단을 내리지 않습니다. 즉, 동일한 상황에서도 내가 원하는 방향으로 개발을 할 수도, 안 할 수도 있습니다.

하지만 코드의 개발을 맡긴 이상 이런 비결정적 리스크는 안고 갈 수밖에 없습니다. 결국 제가 생각한 해결 방법은 그보다 하위에서 계약을 고정하고, 추적 가능한 단위로 개발을 진행하여, 이해하기 쉬운 형태로 보고를 받는 것이 최선이라 생각했습니다.

제가 적용했던 구체적인 방법론은 다음과 같습니다.

  1. 계약의 고정 (SSoT 확립)

    AI가 참고할 수 있는 SSoT를 먼저 확립합니다. , , 아키텍처와 같은 문서를 md 파일로 작성하여 AI가 개발 중 바로바로 참고할 수 있도록 합니다.

    만들어진 모든 문서를 미리 참조할 경우 컨텍스트를 많이 차지할 수 있으므로, 적절한 폴더 구조를 만들어 두고 ssot-router 같은 에이전트 스킬을 개발해 적용해두면 편리합니다.

  2. 원자적 개발 단위로 분해

    기존 기능들을 세부 기능으로 구분하고 각 세부 기능별 필요한 엔티티와 함께 쭉 나열합니다. 이렇게 나열된 세부 기능을 직접 작업/흡수/재평가/후속으로 구분합니다.

    • 직접 작업: 독립적으로 바로 개발 가능한 단위
    • 흡수: 다른 작업에 포함되어 함께 구현되는 단위
    • 재평가: 선행 작업 완료 후 다시 판단해야 하는 단위
    • 후속: 현재 목표 개발 범위 밖의 단위
  3. 실제 개발 단위로의 정렬

    여기까지 오면 기능을 실제 개발 단위로 정렬할 수 있습니다. 직접 작업을 기준으로 마일스톤을 만들고, 흡수 항목은 해당 작업에 묶어 함께 구현합니다. 이렇게 하면 추적 가능하면서도 바로 개발 가능한 단위가 생깁니다.

    개발은 마일스톤 단위로 진행합니다. 마일스톤의 작업이 끝나면 재평가 항목을 다시 훑습니다. 그중 현재 범위에 포함되고 선행 조건이 충족된 항목은 직접 작업 또는 흡수로 전환합니다. 이후 작업 문서를 발행하고 마일스톤에 편입해 개발합니다. 더 이상 편입할 수 있는 재평가 항목이 없을 때까지 이를 반복합니다.

  4. 추적 가능한 기록

    앞서 말했듯 이 모든 과정은 반드시 문서로 남겨야 합니다. AI가 뱉어낸 코드를 그대로 수용하는 것이 아니라, 각 작업의 결과를 기록함으로써 프로젝트의 통제권을 유지하는 것입니다. 이때 문서는 다음과 같은 원칙을 따릅니다.

    • 가독성 우선: 서술형보다는 짧은 나열형으로 작성하여 AI와 사람이 핵심을 즉각 파악하게 합니다.
    • 미완료 작업 및 리스크 명시: 만약 기능을 완벽히 구현하지 못했다면, 남은 작업이나 잠재적 리스크를 반드시 기술합니다. 이는 다음 작업이나 마일스톤에서 AI가 참고할 중요한 컨텍스트가 됩니다.
    • 관점의 병행: 개발자의 기술적 관점뿐만 아니라, 실제 서비스가 어떻게 동작하는지 사용자 관점의 설명도 곁들입니다. 참고로 이 부분은 Claude가 Codex보다 훨씬 잘합니다.

    AI 에이전트는 작업별 완료 문서, 마일스톤별 문서, 그 외 기타 SSoT 문서를 활용하여 개발 상황을 추적합니다. 이렇게 작성된 문서들은 컨텍스트와 독립적인 로컬 파일로 저장되어 필요 시 ssot-router 스킬을 사용해 에이전트가 참조할 수 있습니다. 더불어 저 같은 경우 md 파일로 작성하여 옵시디언을 통해 사람이 같이 읽을 수 있도록 구성하니 훨씬 편했습니다.

자세히 뜯어보면 결국 이건 우리가 그동안 해왔던 개발과 다를 게 없습니다. 다만 그 자원을 이제 AI와 함께 공유한다는 것, 그 차이가 생각보다 큽니다.

마무리

AI는 빠르게 만들어줍니다. 하지만 중요한 것은 그 속도 위에서도 내가 여전히 방향을 붙잡고 있느냐는 것입니다. 저에게 마일스톤과 SSoT 문서는 길을 잃지 않기 위한 나침반이었습니다. 비록 ‘딸깍’ 한 번에 모든 것이 해결되는 마법은 아니었지만, 그 덕분에 이제는 AI의 질주가 적어도 내가 정한 방향에서 벗어나고 있지 않다는 사실을 알게 되었습니다.

지금 우리는 AI라는 거대한 숲을 지나고 있습니다. 잠깐의 ‘딸깍’만으로도 수많은 나무가 시야를 가리는 그 숲에서, 여러분은 나침반을 들고 계신가요?