기능이 출시된 지 6개월 후에 리포지토리를 열어봐도 많은 것을 재구성할 수 있다. 아키텍처를 추적하고, 스키마를 살펴보고, 테스트를 읽고, 정확히 어떤 줄이 바뀌었는지 확인할 수 있다.
하지만 대개 재구성할 수 없는 것은, 왜 그 줄들이 필요해졌는지를 만든 대화다.
코드는 어떤 고객이 형식이 잘못된 export를 보내기 때문에 검증 규칙이 존재한다는 사실을 말해주지 않는다. 이상한 재시도 정책이 다운스트림 시스템에서 중복 거래를 막기 위한 것이라는 점도 설명하지 않는다. 더 깔끔한 인터페이스가 접근성 테스트 이후 거부되었다는 사실도, 서비스 경계가 엔지니어링 선호가 아니라 계약상 제약을 반영한 것이라는 점도 보여주지 않는다.
Git은 코드의 변경 이력을 보존하는 데 탁월하다. 하지만 의도는 팀이 그것을 의식적으로 문서화하고 구현과 연결해 둘 때에만 보존된다.
이 간극은 늘 소프트웨어 엔지니어링의 일부였다. AI 코딩 도구는 그것을 더 눈에 띄게 만든다. 시스템은 리포지토리의 모든 파일을 읽고, 모든 심볼을 따라가며, 기술적으로는 그럴듯한 패치를 생성할 수 있지만 여전히 잘못된 문제를 풀 수 있다.
문제는 코드가 오해를 부른다는 데 있지 않다. 코드는 더 좁은 질문에 답하고 있을 뿐이다.
엔지니어링의 진실을 이루는 다섯 개의 층위
의미 있는 소프트웨어 변경 대부분은 서로 다른 다섯 가지 증거 층위에 의존한다.
- 의도 — 사용자, 고객, 또는 비즈니스가 원하는 결과는 무엇인가? 이는 명세서, 티켓, 지원 대화, 또는 회의 노트에 있을 수 있다.
- 제약 조건 — 무엇이 깨지면 안 되는가? 호환성 약속, 보안 경계, 규제, 계약, 예산, 마감일은 종종 리포지토리 밖에 있다.
- 구현 — 오늘날 시스템은 어떻게 동작하는가? 코드, 테스트, 스키마, 의존성, 배포 설정이 이 층위를 제공한다.
- 런타임 증거 — 실제 시스템에서는 무슨 일이 일어나고 있는가? 로그, 트레이스, 메트릭, 프로덕션 데이터, 사고 보고서는 코드상으로는 타당해 보이는 가정을 뒤집을 수 있다.
- 의사결정 이력 — 현재 접근 방식은 왜 선택되었는가? Pull request, 설계 논의, 기각된 대안, 이전 사고에 그 답이 담겨 있다.
리포지토리는 세 번째 층위에서 가장 강하다. 다른 층위의 일부도 담고 있지만, 그것들을 완전하게 대표하기에는 거의 언제나 부족하다.
이것이 중요한 이유는 소프트웨어 실패가 종종 층위와 층위의 경계에서 나타나기 때문이다. 구현은 오래된 명세와 일치한다. 수정은 티켓은 충족하지만 운영상 제약을 위반한다. 테스트가 통과하는 이유는 그것이 어제의 가정을 인코딩하고 있기 때문이다. 코드는 내부적으로 일관되지만 프로덕션 데이터는 아무도 문서화하지 않은 패턴을 따른다.
로컬에서는 올바른 패치라도 여전히 잘못된 변경일 수 있다.
저장소만으로는 답할 수 없는 것
문서를 수정한 뒤 업데이트된 문장을 검색했는데 결과에는 이전 버전만 보이는 사용자를 생각해 봅시다. “검색이 즉시 업데이트되게 해달라”는 요청은 분명해 보입니다. 저장소는 어디서부터 살펴볼지에 대한 몇 가지 출발점을 보여주지만, 그 자체만으로 올바른 해결책을 정의할 수는 없습니다.
| 질문 | 가능성이 높은 출처 |
|---|---|
| 어떤 버전의 문서가 기준인가? | 원본 문서와 개정 이력 |
| 이전 텍스트는 어디에 남아 있는가? | 동기화 로그, 추출 결과, 검색 인덱스 또는 캐시 |
| 이 제품에서 “즉시”는 무엇을 의미하는가? | 제품 약속 또는 서비스 목표 |
| 문서 내용이 바뀌면서 권한도 함께 변경되었는가? | 원본 권한과 감사 이력 |
| 오래된 결과는 특정 사용자, 소스 또는 지역에만 한정되는가? | 요청 추적과 프로덕션 메트릭 |
검색 코드는 결과가 어떻게 반환되는지는 설명해 줄 수 있습니다. 하지만 실제 결함이 동기화 지연인지, 오래된 추출 결과인지, 캐시 무효화 문제인지, 권한 전파 문제인지, 아니면 제품이 애초에 정의하지 않았던 기대치인지까지는 알려주지 못합니다.
이 구분은 시스템이 성숙할수록 더 중요해집니다. 낡아 보이는 필드가 사실은 레거시 클라이언트를 계속 지원하고 있을 수 있습니다. 중복처럼 보이는 서비스가 서로 다른 권한 요구사항을 가진 데이터를 분리하고 있을 수도 있습니다. 과도해 보이는 검사 하나가 현재 팀은 보지 못했던 프로덕션 장애의 유일한 코드 수준 흔적일 수도 있습니다.
복잡성을 제거하는 일은 가치가 있습니다. 하지만 복잡성으로 위장한 역사를 지우는 일은 대가가 큽니다.
더 많은 맥락이 있어도 여전히 틀린 답이 나올 수 있다
가장 뻔한 해결책은 AI에 더 많은 자료를 주는 것입니다. 저장소 전체, 모든 티켓, 모든 문서, 모든 메시지, 모든 로그를 말입니다.
그렇게 해서 생기는 것은 이해가 아니라 접근성입니다.
출처는 오래되었을 수도 있고, 서로 모순될 수도 있으며, 추측에 기반할 수도 있고, 서로 다른 독자를 대상으로 쓰였을 수도 있습니다. 브레인스토밍 내용이 승인된 명세보다 우선해서는 안 됩니다. 6개월 전 요구사항이 어제 내려진 제품 결정을 조용히 덮어써서도 안 됩니다. 프로덕션 로그는 그것을 만들어낸 릴리스, 환경, 코드 경로와 연결되어야 합니다. 고객 요청은 범위를 확인하지 않은 채 보편적 요구사항으로 취급되어서는 안 됩니다.
따라서 진지한 맥락 시스템에는 단순한 검색 이상이 필요합니다. 다음을 추론할 수 있어야 합니다.
- 권위: 어떤 출처가 요구사항을 정의할 수 있는가?
- 최신성: 어떤 정보가 현재 유효하며, 무엇이 대체되었는가?
- 출처: 각 주장, 제약, 결론은 어디에서 나왔는가?
- 관계: 어떤 이슈, 릴리스, 고객, 데이터셋, 코드 경로가 서로 연결되는가?
- 권한: 이 작업에 어떤 출처를 사용할 수 있으며, 어떤 출처를 이 사람에게 보여줄 수 있는가?
맥락은 토큰의 더미가 아닙니다. 시간, 권위, 경계를 가진 그래프입니다.
더 많은 맥락은 더 많은 근거를 만들어야지, 근거 없는 더 큰 확신을 만들어서는 안 됩니다.
실제 작업 단위는 변경이다
에디터와 코딩 도구는 파일을 중심으로 구성됩니다. 우리가 수정하는 대상이 파일이기 때문입니다. 하지만 엔지니어링 팀은 변경을 중심으로 조직됩니다.
변경은 이유에서 시작됩니다. 그것은 요구사항이 되고, 코드와 데이터를 건드리며, 리뷰를 거쳐, 프로덕션에 도달하고, 새로운 근거를 만들어냅니다. 이 단계들이 서로 분리된 채로 남아 있으면, 앞으로의 모든 작업은 또 한 번의 고고학으로 시작하게 됩니다.
실제 소프트웨어를 다루는 AI 시스템이라면 이 생애주기를 따라야 합니다.
구현 전에, 요청이 무엇인지, 관련 제약은 무엇인지, 서로 충돌하는 출처는 없는지를 식별해야 합니다. 지금 하려는 일이 결함 수정인지, 기대 동작의 변경인지, 새로운 계약의 도입인지도 알아야 합니다.
구현 중에는, 의미 있는 각 선택을 근거와 연결해야 합니다. 왜 이 모듈인가? 왜 이 마이그레이션 전략인가? 왜 이 분기를 유지하는가? 그 설명은 코드를 만들어낸 채팅이 끝난 뒤에도 남아 있어야 합니다.
구현이 끝난 뒤에는 검증 결과, 검토 결정, 그리고 새롭게 드러난 제약 사항을 변경 사항에 함께 남겨야 합니다. 그렇지 않으면 다음 사람—혹은 다음 AI 세션—이 그것들을 다시 찾아내야 합니다.
이것이 저장소를 편집할 수 있는 도구와 엔지니어링 작업에 참여할 수 있는 시스템의 차이입니다.
AI는 재구성 비용을 줄여야지, 판단을 없애서는 안 됩니다
더 나은 컨텍스트는 때때로 자율적인 소프트웨어 개발로 가는 길처럼 제시됩니다. 하지만 당장의 가치는 그보다 덜 극적이고 더 유용합니다. 즉, 변경을 하기 전에 현실을 다시 구성해 파악하는 데 드는 비용을 줄여주는 것입니다.
AI는 원래 요구사항을 관련 코드 옆에 가져다 놓을 수 있습니다. 이례적인 보호 장치가 왜 생겼는지 설명해 주는 인시던트를 드러낼 수 있습니다. 실패한 지표를 그것을 바꾼 릴리스와 연결할 수 있습니다. 구현이 시작되기 전에 두 개의 권위 있는 출처가 서로 충돌한다는 점을 보여줄 수도 있습니다.
이런 역량이 엔지니어링 판단을 없애는 것은 아닙니다. 오히려 판단이 더 충분한 정보를 바탕으로 이루어지게 합니다.
어떤 트레이드오프를 받아들일 수 있는지, 요구사항이 완전한지, 릴리스가 어느 정도의 위험을 감수할 수 있는지는 여전히 사람이 결정해야 합니다. 시스템은 근거를 보이게 하고 추론 과정을 검토할 수 있게 해야 합니다. 매끈한 패치 뒤에 불확실성을 숨겨서는 안 됩니다.
기준은 “코드를 생성할 수 있는가?”가 아닙니다.
기준은 “왜 지금 이것이 올바른 변경인지 설명할 수 있는가?”입니다.
저장소 인식에서 작업 인식으로
코딩 어시스턴트가 처음 유용해진 것은 개발자 앞에 있는 파일을 이해하면서부터였습니다. 저장소 인식은 그다음의 큰 진전이었습니다. 관련 코드를 찾고, 심볼을 따라가고, 프로젝트 전반에 걸쳐 변경을 적용할 수 있게 된 것입니다.
다음 단계는 저장소를 둘러싼 작업을 인식하는 것입니다.
이는 코드를 그것을 요청한 명세, 그것을 명확히 한 대화, 그것에 이의를 제기한 프로덕션 근거, 그리고 이후에도 기억되어야 할 결정과 연결한다는 뜻입니다. 동시에 관련이 없거나, 오래되었거나, 사용자의 권한 밖에 있는 컨텍스트는 제외해야 한다는 뜻이기도 합니다.
Dvina를 만들면서, 이것은 우리가 계속해서 되돌아오는 아이디어 중 하나입니다. 작업은 하나의 파일, 애플리케이션, 혹은 대화 안에서만 일어나지 않습니다. 의미는 그들 사이의 연결 속에, 그리고 그 연결이 시간에 따라 어떻게 변하는지에 담겨 있습니다.
저장소는 여전히 핵심입니다. 시스템 동작에 대한 실행 가능한 진실의 원천이기 때문입니다. 다만 그것이 제품 의도, 운영 현실, 또는 조직의 기억까지 포함한 완전한 진실의 원천은 아닙니다.
전체 맥락은 무엇이 만들어지는지를 바꿉니다
코드만 있을 때 자연스럽게 나오는 질문은 다음과 같습니다:
어떤 변경이 이 시스템에 맞는가?
더 넓은 컨텍스트가 있으면 질문은 이렇게 바뀝니다:
어떤 변경이 이 시스템, 이 요구사항, 이 이력, 그리고 지금 이 시점에 맞는가?
두 번째 질문은 제약이 회귀로 이어지기 전에 포착합니다. 리뷰어에게 구현의 근거를 제공합니다. 새로운 팀원이 시스템이 왜 지금과 같은 모습인지 이해하는 데도 도움이 됩니다. 그리고 AI에 현실적인 역할을 부여합니다. 에디터 안의 신탁이 아니라, 작업 전반에 걸쳐 근거를 모아 제시할 수 있는 참여자로서 말입니다.
당신의 리포지토리가 이야기의 전부였던 적은 없습니다.
기회는 그 나머지까지 읽어낼 수 있는 시스템을 만들고, 그 근거를 보여주게 하는 데 있습니다.

