본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 20. 10:20

Claude Code가 코딩하기 전에 생각하도록 만들었습니다. 그다음에는 팀을 부여했습니다.

요약

Claude Code가 단순히 코드를 작성하는 것을 넘어, 시니어 엔지니어의 사고 프로세스를 따르도록 프롬프트를 설계하여 개발 품질을 높이는 방법을 다룹니다. 단일 에이전트를 넘어 여러 에이전트가 협업하는 '엔지니어링 팀' 구조로 확장하여 아키텍트 역할을 수행하는 워크플로를 제안합니다.

핵심 포인트

  • Claude Code에 시니어 엔지니어의 규율(코드베이스 읽기, 테스트 우선 작성 등)을 부여하는 방법
  • 단일 에이전트(v1)에서 다중 에이전트 팀(v2)으로 확장하여 생산성 극대화
  • 개발자의 역할이 코드 작성에서 에이전트 워크플로를 감독하는 아키텍트로 변화
  • 실패하는 테스트를 먼저 작성하여 코드의 안정성을 확보하는 프로세스 강조

얼마 전 저는 "Claude Code가 코딩하기 전에 생각하도록 만들었습니다. 여기 그 프롬프트가 있습니다."라는 제목의 글을 썼습니다. 그 전제는 많은 이들의 공감을 얻었습니다. AI 코딩 어시스턴트(AI coding assistants)의 문제는 결코 '지능'이 아니었습니다. 이 모델들은 당신이 기능을 설명하는 것보다 더 빠르게 작동하는 함수를 작성할 수 있습니다. 문제는 **프로세스 (process)**였습니다. 스스로 내버려 두면, Claude Code는 기존 코드를 읽고, 테스트를 작성하며, 배포하기 전에 자신의 작업물을 검토하는 직무 단계를 건너뛴 명석한 주니어 개발자처럼 행동합니다. 먼저 코딩하고 나중에 생각하는 식입니다.

그래서 저는 프로세스를 부여했습니다. 저는 이를 /wizard라고 불렀으며, 이는 하나의 Claude가 규율 있는 시니어 엔지니어(senior engineer)의 습관을 갖도록 강제했습니다: 한 줄의 코드를 쓰기 전에 코드베이스(codebase)를 읽고, 구현하기 전에 수락 기준(acceptance criteria)을 통해 "완료"의 정의를 내리며, 먼저 실패하는 테스트를 작성한 다음, 이를 통과하기 위한 최소한의 코드를 작성하고, 방금 작성한 것을 망가뜨리려고 시도하는 것입니다. 결과물은 동일한 작동하는 코드이지만, 새벽 2시에 "왜 이게 운영 환경(production)에서 깨졌지?"라고 후속 조치를 할 일은 없어졌습니다.

그것이 버전 1(version one)이었습니다. 한 번에 하나의 Claude, 하나의 규율, 하나의 풀 리퀘스트(pull request)였습니다.

이 포스트는 제가 Claude를 더 나은 *개발자 (developer)*로 만들려는 시도를 멈추고, 더 나은 *엔지니어링 팀 (engineering team)*으로 만들기 시작했을 때 어떤 일이 일어났는지, 그리고 그것이 제 업무에 어떤 영향을 미쳤는지에 관한 것입니다. 왜냐하면 아무도 경고해주지 않은 부분이 여기에 있기 때문입니다. v1에서 저는 코드를 작성하는 것과 라인별 리뷰(line-by-line reviews)를 하는 것을 멈췄습니다. v2에서는 다음 단계의 층위도 사라졌습니다. 저는 심도 있는 기술적 프롬프트(technical prompts)와 작업을 공급하는 GitHub 이슈(GitHub issues)를 작성하는 것을 멈췄습니다. 남은 것은 완전히 다른 고도의 작업입니다. 저는 워크플로(workflows)를 조정하고 그 안에서 실행되는 에이전트(agents)를 감독합니다. 저는 지휘합니다.

처음 오셨나요? 이 글을 이해하기 위해 v1 포스트를 반드시 읽을 필요는 없지만, 그것은 아래의 모든 것이 구축된 토대입니다. 원문은 이 글의 하단에, 그리고 이 모든 것이 담긴 오픈 소스 리포지토리(open-source repo)와 함께 링크되어 있습니다.

변화: 시니어 개발자에서 팀을 운영하는 시니어 아키텍트 (senior architect)로

혼자 일하는 절제된 시니어 개발자(senior developer)에 대해 알아야 할 점은, 그들은 여전히 혼자 일한다는 것입니다. 그들은 주의 깊게 읽고, 철저하게 테스트하며, 스스로 리뷰하고, 순차적으로 한 번에 하나의 작업만 수행하며, 매 코드 리뷰 왕복 과정마다 작업이 중단(blocking)됩니다. v1은 환상적인 개인 기여자(individual contributor)였지만, 개인 기여자에게는 한계가 있습니다. 바로 한 쌍의 손뿐이라는 점입니다.

진정한 시니어 아키텍트(senior architect)는 하루 종일 에디터 앞에 앉아 있지 않습니다. 그들은 문제를 분리 가능한 관심사(separable concerns)로 분해하고, 모두가 그에 맞춰 구축할 수 있는 계약(contract)을 작성하며, 백엔드, UI, 테스트 커버리지(test coverage)를 동시에 일하는 사람들에게 넘깁니다. 그들은 계획하고, 배분하고, 통합하며, 리뷰 파이프라인(review pipeline)이 계속 돌아가도록 유지하며, 본인이 직접 코드를 작성하는 일은 거의 없습니다. 그것이 바로 v2입니다. 멘탈 모델(mental model)이 "Claude를 시니어 개발자로 만들기"에서 **"Claude를 팀을 운영하는 시니어 아키텍트로 만들기"**로 변화했으며, 저에게는 팀을 운영하는 것에서 팀을 *지휘(conducting)*하는 것으로 변화했습니다. 구체적으로는 다음과 같습니다: 스스로는 코드를 작성하지 않는 단일 메인 스레드 **오케스트레이터(orchestrator)**가 작업을 여러 전문 **서브에이전트(subagents)**에게 분산시키며, 각 서브에이전트는 자신만의 격리된 git 워크트리(worktree)에서 병렬로 빌드하고, 자동화된 리뷰 게이트(review gate)를 통해 동시에 여러 개의 풀 리퀘스트(pull request)를 추진합니다.

처음 이것을 지켜보았을 때 저를 진심으로 놀라게 했던 정서적 보상은 다음과 같습니다: 제가 기능을 설명하고 자리를 비웠다가 돌아오면, 제가 잠든 사이에 엔지니어링 팀이 결과물을 계속 배포(shipping)하고 있었다는 점입니다.

v1에서 v2로: 무엇이 변했는가

만약 기존의 /wizard를 사용했다면, 다음 표를 통해 업그레이드된 전체 내용을 확인할 수 있습니다:

v1 (훈련된 개발자 한 명)v2 (팀을 운영하는 아키텍트)
아이디어에서 작업으로사용자가 티켓을 직접 작성함이슈 관리자 (issue-maintainer) 에이전트가 한 줄짜리 아이디어를 구조화된 이슈(issue) 또는 에픽(epic)으로 변환함
...

v1을 작동하게 만들었던 모든 요소는 밑바탕에 여전히 존재합니다. v2는 그 규율을 대체하는 것이 아닙니다. 그것을 팀 전체에 **분산(distributes)**시키고 그 팀을 병렬로 실행하는 것입니다. 사실, v1은 "직접 모드 (direct mode)"로서 토씨 하나 틀리지 않고 그대로 보존되며, 팀은 작업이 그만한 가치가 있을 정도로 충분히 복잡할 때만 가동됩니다. 한 줄짜리 수정 작업에는 팀 운영 비용(team tax)을 지불하지 않습니다. 이제 각 구성 요소를 살펴보겠습니다.

코드가 작성되기 전부터 시작됩니다: 아이디어를 이슈로 변환하는 에이전트

파이프라인의 가장 앞단은 제가 가장 오랫동안 과소평가했던 부분입니다. 예전에는 제가 직접 티켓을 작성했습니다. 샤워를 하다가 어떤 기능이 떠오르면, 그것을 실행하기 위해 지불해야 하는 대가는 모호한 문장을 제목, 수락 기준 (acceptance criteria), 라벨 (labels), 상위 에픽 (parent epic)으로의 링크가 포함된 잘 구성된 이슈로 바꾸는 것이었습니다. 이것이 하류(downstream)의 모든 과정을 조용히 저해합니다. 팀이 아무리 훌륭하더라도 허술한 티켓은 허술한 결과물을 만들어냅니다.

그래서 이 부분 또한 에이전트가 되었습니다. 이슈 관리자 (issue-maintainer) 에이전트는 한 줄짜리 아이디어("관리자가 신규 사용자를 위한 가이드 워크스루를 켤 수 있게 한다")를 가져와서 구조화된 이슈를 생성합니다. 즉, 명확한 제목, 명시적인 수락 기준 (acceptance criteria), 일관된 라벨, 그리고 에픽과 그 구성 요소들을 연결하는 상위-하위 이슈 간의 링크를 만들어냅니다. 저는 코드를 포맷팅하는 것을 그만두었던 것처럼, 티켓을 포맷팅하는 것도 그만두었습니다.

핵심은 제가 타이핑하는 시간을 10분 아껴준다는 것이 아닙니다. 핵심은 **일관성 (consistency)**입니다. 모든 이슈가 동일한 형태, 동일한 라벨 어휘, 동일한 방식으로 작성된 수락 기준 (acceptance criteria), 그리고 동일한 에픽-하위 작업 (epic-to-subtask) 구조를 갖게 되면, 나머지 시스템은 깨끗하고 균일한 단일 진실 공급원 (source of truth)을 바탕으로 작동합니다. 즉, 오케스트레이터 (orchestrator)는 어떤 이슈를 집어 들더라도 즉시 무엇이 "완료 (done)"를 의미하는지 알 수 있으며, 빌더 (builders)들은 실패하는 테스트를 작성할 수 있는 수락 기준을 상속받습니다. 일관된 이슈는 기차 전체가 달리는 레일과 같습니다. 아이디어를 이슈로 만드는 것은 에이전트 (agent)가 시작되기 전에 제가 수동으로 하는 작업이 아니라, 에이전트의 첫 번째 단계입니다.

오케스트레이터 / 워커 분리 (그리고 왜 그 경계가 git commit인가)

v2에서 가장 중요한 단일 설계 결정은 오케스트레이터 (orchestrator)와 워커 (worker) 사이의 경계, 그리고 그 경계가 정확히 어디에 위치하느냐 하는 것입니다.

**오케스트레이터 (orchestrator)**는 메인 스레드 (main thread)입니다. 즉, 당신이 실제로 대화하는 Claude입니다. 오케스트레이터는 계획을 세우고, 하위 에이전트 (subagents)를 파견하며, 파이프라인 (pipeline)을 모니터링하고, 결과를 통합합니다. 오케스트레이터는 애플리케이션 코드에 대해 에디터를 열지 않습니다. 오케스트레이터가 에디터를 여는 순간, 오케스트레이션은 중단됩니다. 이는 10개의 병렬 풀 리퀘스트 (pull requests)가 의존하고 있는 컨텍스트 (context)를 소모해 버리고, 세 명의 전문가가 동시에 처리할 수 있었던 작업을 직렬화 (serializing)해 버리는 결과를 초래합니다. **워커 (workers)**는 하위 에이전트 (subagents)입니다. 각 워커는 집중된 브리프 (brief)를 전달받아 구현을 수행하고, 영향을 받는 테스트를 실행하며, 로컬에 커밋 (commit)한 뒤, 브랜치 이름, 최종 커밋 SHA, 수정된 사항을 포함한 하나의 결과 메시지를 반환합니다.

전달 경계(handoff boundary)는 정확히 git commit입니다. 서브 에이전트가 커밋을 수행하고, 오케스트레이터는 git push 이후의 모든 것—푸시, PR 열기, 리뷰 사이클 실행—을 담당합니다. 커밋은 로컬 작업(local work) (완전히 되돌릴 수 있음)과 외부 커밋(external commitments) (CI가 작동하고, 리뷰어에게 알림이 가며, 해당 SHA에 대한 체크-런이 기록됨) 사이의 2단계 커밋 지점입니다. 이 지점에서 책임을 분리하면 세 가지 구체적인 이점을 얻을 수 있습니다. 변경 사항(diff)을 노출하기 전에 검증할 수 있습니다: 배포 시 작업 트리(worktree cut)가 형제 브랜치(sibling)가 병합되면 오래될 수 있으며, 빠른 fetch-and-rebase는 누군가를 혼란스럽게 만들기 전에 유령 삭제 변경 사항(phantom-deletion diff)을 포착합니다. 깨끗한 실패 복구(clean failure recovery)를 얻습니다: 작업 도중에 충돌하는 서브 에이전트는 아무것도 푸시하지 않았으므로, 오케스트레이터는 절반만 만들어진 PR을 정리할 필요 없이 단순히 작업 트리를 복구하기만 하면 됩니다. 그리고 단일 모니터링 소유자(single monitoring owner)를 얻습니다: 모든 진행 중인 PR의 상태를 아는 주체가 정확히 하나이므로, 해당 주체만이 PR이 준비되었다고 선언하고 서브 에이전트가 가질 수 없는 교차 영역 컨텍스트로부터 제목과 설명을 구성합니다.

앙상블: 건축가, 그리고 병렬로 작업하는 빌더들, 그리고 비평가들

여기서부터는 하나의 어시스턴트처럼 보이지 않고, 명단이 있는 팀처럼 보이기 시작합니다. 오케스트레이터가 사소하지 않은 작업을 받으면, 단순히 '빌더'를 배포하지 않습니다. 이 시점에서는 이슈 유지 관리자(issue-maintainer)가 이미 원본 아이디어를 승인 기준을 갖춘 구조화된 Github 이슈로 변환했기 때문에, 앙상블은 구축할 구체적인 무언가를 가지고 있습니다. 그 후에는 의도적인 순서로 실행됩니다:

1. 설계자 (The architect)가 가장 먼저 시작하며, 프로덕션 코드 (production code)를 작성하지 않습니다. 설계자의 역할은 서브시스템 (subsystem)을 설계하고, 불변량 (invariants)을 열거하며, 동시성 분석 (concurrency analysis)을 수행하고 (예: 이것이 동시에 두 번 실행되면 어떻게 되는가? 이 데이터에 접근하는 모든 경로에서 무엇이 계속 참이어야 하는가?), 두 가지 결과물을 생성하는 것입니다: 수락 기준 (acceptance criteria)을 인코딩한 실패하는 테스트 명세 (failing-test spec) (이슈 관리자가 이슈에 작성했던 내용을 이제 실행 가능한 형태로 만든 것), 그리고 UI와 백엔드가 교환할 모든 필드와 그 타입, 범위, 기본값을 정의한 **데이터 계약 (data contract)**입니다. 설계자는 읽기 전용 (read-only)입니다. 설계는 하지만 구축하지는 않습니다. 이 계약은 팀의 정직함을 유지하는 이음새 (seam) 역할을 합니다. 모든 구축자의 결과물은 구축자가 브리프 (brief)를 느슨하게 해석한 내용이 아니라, 설계자가 지정한 구체적인 실패 테스트를 기준으로 검증됩니다.

2. 그다음 구축자 (builders)들이 그 하나의 계약을 바탕으로 병렬로 투입됩니다. 백엔드 전문가가 서비스 (services), 모델 (models), 마이그레이션 (migrations)을 담당하고, 프론트엔드 전문가가 UI를 담당하며, QA 전문가가 커버리지 (coverage)를 작성합니다. 이들은 동시에 작업을 수행합니다. 프론트엔드는 백엔드를 기다리지 않는데, 왜냐하면 이미 받게 될 데이터의 정확한 형태를 알고 있기 때문입니다. 각자는 **중복되지 않는 파일 세트 (non-overlapping set of files)**를 소유하므로, 동일한 트리 내에서 충돌하는 일이 발생하지 않습니다. 진정한 단일 도메인 (single-domain) 변경은 한 명의 구축자에게 할당되지만, 분할은 예외가 아닌 _기본값 (default)_입니다.

3. 마지막으로 비평가 (critics)들이 검증하며, 결정적으로 이들은 그것을 구축하지 않았습니다. 이것은 생성자/평가자 분리 (generator/evaluator separation)이며, 매우 중요합니다. 변경 사항을 작성한 에이전트와 승인하는 에이전트는 서로 다릅니다. QA 전문가는 코드가 통과(green)된 후 다시 돌아와서, 뮤테이션 테스팅 (mutation-testing) 사고방식을 적용하여 (단순히 "작동했다"라고 단언하는 것이 아니라, 코드가 변이되었을 때 깨지게 될 구체적인 값과 정확한 횟수를 단언함) 수락 기준이 실제로 커버되었는지 확인합니다.

그리고 제가 가장 좋아하는 부분인 **도메인 사용자 렌즈 (domain-user lenses)**가 있습니다. 제품을 사용하는 각 사용자 유형에 대해, _해당 페르소나의 관점_에서 변경 사항을 읽고 어디에서 문제가 발생하는지 찾아내는 역할을 하는 적대적 비평가 (adversarial critic)가 존재합니다. 관리자(Admin), 최종 사용자(end user), 파워 유저(power user)는 각각 관리자 렌즈, 최종 사용자 렌즈, 파워 유저 렌즈가 됩니다. 각 렌즈는 두 가지 조사 (probes)를 수행합니다: 기능적 동등성 (feature parity) ("관리자에게 기능이 추가되었는데, 파워 유저에게도 유사한 기능이 제공되어야 하는가?") 및 교차 행위자 유출 (cross-actor leak) ("이 관리자 전용 기능이 최종 사용자가 공유하는 화면에 나타나게 될 것인가?"). "해당 사항 없음"이라고 말하는 렌즈는 반드시 두 가지 조사를 모두 _수행_하고 그 결과가 비어 있음을 추론해야 합니다. 이는 건너뛸 수 있는 단계가 아니라, 반드시 얻어내야 하는 결론입니다. 마지막으로 **문서 사서 (documentation librarian)**가 문서가 코드에 맞춰 실제로 업데이트되었는지 확인합니다.

이 앙상블 (ensemble)을 하나로 묶어주는 엄격한 규칙이 하나 있습니다: 에이전트들은 서로 대화하지 않습니다. 이들은 격리된 컨텍스트 (isolated contexts)에서 실행되며 정확히 하나의 결과만을 반환합니다. 설계자 (architect)가 자신의 명세 (spec)를 빌더 (builder)에게 전달할 수 없고, 빌더가 자신의 차이점 (diff)을 QA에게 전달할 수 없습니다. 모든 인계는 오케스트레이터 (orchestrator)에 의해 중재됩니다: 오케스트레이터는 에이전트 A의 출력을 읽고, 에이전트 B가 필요로 하는 부분을 추출하여 B의 브리프 (brief)에 포함시킵니다. 이것은 동료들이 협상하는 군집 (swarm)이 아닙니다. 이는 매니저가 업무를 분해하고, 격리된 전문가들을 파견하며, 그들의 단발성 (one-shot) 결과물들을 다음 체인의 고리로 엮어내는 과정입니다.

팀이 한 명의 개발자라면 놓쳤을 것을 잡아낸 순간

병렬성은 훌륭하지만, 진짜 승리는 _품질 (quality)_에 있습니다. 중립적인 예를 들어보겠습니다: 당신이 팀에게 사용자를 위한 새로운 온보딩 워크스루 (onboarding walkthrough)를 활성화하는 관리자 기능을 추가하라고 요청합니다. 유능한 단 한 명의 개발자라면, 설령 규율이 잡힌 개발자라 할지라도 정확히 그것만을 구축하여 배포하고, 그것은 정상 작동할 것입니다. 수락 기준 (acceptance criteria)도 충족됩니다.

하지만 최종 사용자 관점(end-user lens), 즉 일반 사용자처럼 생각하는 것만이 유일한 임무인 비판자의 관점에서 교차 액터 누출 조사(cross-actor leak probe)를 실행했을 때, 아무도 묻지 않았던 질문을 던졌습니다. 이 새로운 동작은 실제로 무엇에 결합되어 있는가? 그것은 체크박스나 토글과 같이 맥락이 없는 기본 요소(primitive)인, 공유된 저수준 UI 컴포넌트(low-level UI component)에 결합되어 있었으며, 이는 일반 사용자가 보는 화면을 포함하여 많은 화면에서 재사용되는 것이었습니다. 그리고 그것이 바로 함정입니다. 권한이 있는 표면(privileged surface)은 역할별로 분리함으로써 보안을 강화할 수 있습니다. 하지만 기본 요소(primitive)는 보안을 강화할 수 없습니다. 체크박스는 단지 입력과 출력일 뿐이며, 이것이 관리자 콘솔에 있는지 아니면 최종 사용자 설정 페이지에 있는지 알지 못합니다. "이 액터가 이 기능을 트리거할 수 있는가"를 결정해야 하는 요소는 컴포넌트가 아니라, 그보다 한 단계 위인 컨트롤러(controller) 및 서비스 레이어(service layer)에 존재합니다. 관리자 동작이 특정 결합을 보호하는 중간 계층 게이트(middle-tier gate) 없이 공유된 기본 요소에 직접 연결되어 있었기 때문에, 최종 사용자 화면에 렌더링된 동일한 기본 요소가 그 연결을 조용히 상속받게 되었습니다. 이 관리자 기능과 아무런 관련이 없는 일반 사용자라 할지라도 이를 작동시킬 수 있었을 것입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0