한때 머지는 결승선이었습니다. 풀 리퀘스트를 열고, 누군가 리뷰하고, 그것이 들어가면 변경은 끝난 것이었습니다. 코딩 에이전트는 그 선을 조용히 옮겨버렸습니다. 에이전트가 Linear 이슈를 맡아 코드를 작성하고, 당신이 회의 중일 때 머지 리퀘스트를 여는 순간, 머지는 더 이상 작업의 끝이 아닙니다 — 머지가 건드리는 모든 것의 시작입니다.
머지는 더 이상 결승선이 아니다
머지는 결코 단순한 머지가 아닙니다. 모든 변경은 그 주변 시스템에 기대고 있습니다. 이제는 닫혀야 할 이슈, 오늘 아침부터 사실과 조금 다른 내용을 설명하는 문서, 어제보다 조금 더 붉어진 CI, 아무도 쓰지 않은 릴리스 노트, 사실은 몇 시간 전에 이미 배포된 수정을 여전히 기다리고 있는 고객 지원 대화까지.
한 명의 엔지니어가 일주일에 몇 건의 변경을 배포하던 시절에는 이런 후속 작업이 틈새에 자연스럽게 끼워 넣어졌습니다. 풀 리퀘스트를 연 김에 이슈를 닫았고, 방금 코드를 건드렸으니 문서도 기억이 났습니다. 하지만 에이전트 — 혹은 여러 에이전트로 이루어진 함대 — 가 하루에 수많은 변경을 배포하게 되면 그 틈새는 넘쳐흐릅니다. 더 이상 병목은 코드가 아닙니다. 코드 이후에 있는 모든 것이 병목입니다.
유지보수 방식은 바뀌지 않았다
개발은 빨라졌습니다. 유지보수는 그렇지 않았습니다. 프로젝트의 일관성을 유지하기 위해 우리가 쓰는 도구는 여전히 대부분 수동이며, 여전히 누군가 적절한 순간에 그것을 사용해야 한다는 것을 기억하는 데 의존합니다.
- 머지 리퀘스트는 들어갔지만, 그것이 해결한 Linear 이슈는 여전히 열려 있습니다.
- 문서는 여전히 이전 동작을 설명하고 있고, 어느 페이지인지 아무도 확실히 모릅니다.
- CI는 일주일째 간헐적으로 실패하고 있고, 모두가 그것을 무시하는 법을 배웠습니다.
- 석 달 전 만든 feature flag는 담당자도, 제거 예정일도 없습니다.
- 고객 지원팀은 화요일에 이미 수정된 버그에 대해 우회 방법으로 티켓에 답변합니다.
- 누군가 이번 릴리스에 무엇이 나갔는지 물으면, 정직한 답은 "git log를 좀 볼게요"입니다.
이 중 어느 것도 새로운 문제가 아니며, 사실 에이전트만의 문제도 아닙니다. 이는 소프트웨어 프로젝트의 평범한 엔트로피입니다. 에이전트는 그저 속도를 높여서, 예전에 이를 흡수하던 비공식 시스템이 더 이상 감당하지 못하게 만들 뿐입니다.
프롬프트로 지시하는 정리는 확장되지 않는다
명백한 해결책은 에이전트에게 정리도 맡기는 것이고, 실제로 그렇게 할 수 있습니다. 머지 리퀘스트에서 @taskgoblin을 멘션하고 문서를 업데이트하고, 이슈를 닫고, 릴리스 노트를 작성하라고 지시하면 됩니다. 효과가 있습니다. 하지만 이는 전체 루프에서 가장 희소한 자원, 즉 매번 적절한 순간에 요청하는 것을 기억하는 사람에게 의존합니다.
유지보수는 일회성 작업이 아니라 루프입니다. "문서가 최신인지 확인하기"는 한 번 하고 끝나는 일이 아닙니다. "머지된 이슈가 반드시 닫히도록 하기"도 한 번 하고 끝나는 일이 아닙니다. 사람이 루프를 돌려야 할 때를 알아차리기를 기다리는 모든 것은 일관성 없이 실행됩니다 — 사람이 알아차리는 것 자체가 일관적이지 않기 때문이며, 특히 에이전트의 존재 이유가 애초에 이 모든 것을 머릿속에 담아두지 않아도 되게 하는 것이었다는 점을 생각하면 더욱 그렇습니다. 프롬프트로 지시하는 정리는 작업을 에이전트에게 옮기지만, 그 작업의 스케줄링은 정확히 원래 있던 곳, 즉 당신에게 그대로 남겨둡니다.
우리가 Loops를 만든 이유
일반적인 에이전트 실행은 이벤트로 촉발됩니다 — 이슈 할당, 멘션, 새로운 풀 리퀘스트. Loop는 시간으로 촉발됩니다. 에이전트에게 상시 지시사항과 주기 — 평일 아침마다, 매주 월요일, 매월 1일 — 를 부여하면, 다른 어떤 실행과도 동일한 도구와 접근 권한을 가진 샌드박스 안에서 스스로 실행됩니다.
지시사항이 곧 작업 전체이며, 좋은 지시사항은 바람이 아니라 직무 기술서처럼 읽힙니다. 무엇을 볼지, 어느 저장소인지, 무엇을 할지, 무엇을 하지 말지, 그리고 — 무인으로 실행해도 안전하게 만드는 부분 — 할 일이 없을 때 무엇을 할지, 그것은 바로 아무것도 하지 않는 것입니다.
매주 평일 오전 9시,
group/repo에서 지난 하루 동안 머지된 머지 리퀘스트를 확인하고, 그것들이 해결한 Linear 이슈 중 여전히 열려 있는 것이 있으면 닫으세요. 없다면 아무것도 하지 마세요.
이것이 담당자가 있는 유지보수 루프입니다. 당신이 기억하기를 기다리지 않습니다. 예약된 실행도 완전한 에이전트 실행이기 때문에 끝까지 갈 수 있습니다. 오래된 문서를 표시만 하는 것이 아니라 그것을 고치는 머지 리퀘스트를 엽니다. 머지된 이슈가 다시 열린 상태로 표류한 것을 알아차리기만 하는 것이 아니라 닫습니다 — 그런 다음 당신이 실제로 볼 곳에 보고합니다. Linear 이슈의 댓글로, 당신이 지정한 Slack 채널의 메시지로, 더 나은 곳이 없다면 이메일로.
그리고 일반 실행이 이미 하는 모든 것을 재사용하기 때문에 까다로운 부분들도 처리되어 있습니다. 놓친 시간은 소급 실행되지 않고 건너뛰어지므로, 한 시간 동안 다운되었던 스케줄러가 깨어나서 백 건의 밀린 실행을 한꺼번에 쏟아내지 않습니다. 각 실행에는 자체 예산과 가드레일이 있습니다. 우리는 바로 이런 루프를 위한 시작 템플릿 세트를 제공합니다 — 이슈와 머지를 동기화 상태로 유지하기, 너무 오래 빨간불인 CI 감시하기, 담당자를 잃은 feature flag 추적하기, 무언가 배포될 때마다 릴리스 노트 작성하기 — 대부분의 팀에서 유용한 루프는 결국 비슷하기 때문입니다. 당신은 저장소와 채널만 채우면 됩니다. 가드레일은 이미 작성되어 있습니다.
엔지니어의 역할은 한 단계 올라간다
이 모든 것 아래에는 한 가지 우려가 있습니다. 유지보수를 자동화한다는 것이 판단력까지 자동화하는 것을 의미하지 않느냐는 것입니다. 그렇지 않습니다. 오히려 판단력을 한 단계 끌어올립니다. 루프가 스스로 실행되면, 당신은 이슈 닫는 것을 기억하는 사람에서 벗어나 어떤 루프가 존재해야 하는지, 그 가드레일은 무엇인지, 각각에 대해 "완료"란 무엇을 의미하는지를 결정하는 사람이 됩니다. 당신은 심부름을 하는 대신 상시 지시사항을 검토합니다.
어쨌든 그것이 이 일의 더 시니어한 버전입니다. 에이전트는 코드를 작성하는 비용을 낮췄습니다. 남은 일은 시스템에 대해 무엇이 참이어야 하는지를 결정하고, 그것이 계속 참으로 유지되도록 하는 것입니다. Loops는 그 모든 것을 머릿속에 담아두지 않고도 참으로 유지하는 방법입니다 — 에이전트가 일을 만들고, 상시 루프가 그것을 유지합니다.