본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 09. 08:44

작가가 엔지니어일 필요는 없다: 하네스(Harness)가 품질을 유지하는 방법 (시리즈 5부)

요약

airCloset의 AI 플랫폼 'cortex'가 비엔지니어도 프로덕션 저장소에 직접 PR을 생성할 수 있도록 지원하는 하네스(Harness) 시스템의 사례를 다룹니다. 지식 그래프, 자동 리뷰, 자가 치유 메커니즘을 통해 코드 품질을 유지하며 실제 기능 구현까지 확장하는 과정을 설명합니다.

핵심 포인트

  • 비엔지니어가 직접 프로덕션 코드 PR을 생성할 수 있는 환경 구축
  • 지식 그래프, 자동 리뷰, 자가 치유를 결합한 AI 하네스 프레임워크
  • 단순 수정을 넘어 전체 스택의 기능을 구현하는 수준의 자동화
  • AI 기반의 코드 품질 유지 및 운영 자동화 전략

안녕하세요, airCloset의 CTO인 Ryan입니다.

면책 조항 (Disclaimer): 이 글에서 언급되는 "cortex"는 airCloset에서 자체적으로 구축한 AI 플랫폼의 내부 코드네임입니다. 이는 Snowflake Cortex 또는 Palo Alto Networks Cortex와 같은 기존 상용 서비스와는 무관합니다.

1부 (시리즈 소개)에서 저는 cortex의 하네스(harness)가 비엔지니어(비즈니스 측면의 매니저, PMO 등)가 프로덕션 저장소(production repository)에 PR(Pull Request)을 생성할 수 있을 정도로 성숙해진 과정에 대해 작성했습니다. 여기서 하네스란 프로덕션 환경 내 AI를 위한 런타임 기반(runtime foundation)을 의미하며, 1부에서 4부까지 다루었던 지식 그래프(knowledge graph), 자동 리뷰(Auto Review), 자가 치유(Self-Healing), 그리고 재발 방지(Recurrence Prevention)의 결합체입니다.

5부는 그 다음 단계인 해당 하네스가 이제 실제로 코드를 작성하는 주체의 계층에 도달했음을 다룹니다.

"그래도 결국 엔지니어가 나중에 확인하겠죠?" -- 많은 독자분이 이 질문을 품고 이 글에 도달할 것이라 예상합니다. 그래서 이 포스트는 다른 무엇보다도 하나의 구체적인 사례를 먼저 제시하며 시작합니다.

5부에서 다루는 내용:

  1. 실제로 어떤 종류의 PR이 배포되고 있는가 -- 최근 사례 두 가지를 상세히 설명
  2. 무엇이 작동하고 무엇이 작동하지 않는가 -- 기존 스택 위에 기능을 추가하는 것과 새로운 인프라를 구축하는 것 사이의 경계
  3. 왜 이것이 비엔지니어에게도 유효한가 -- 1~4부에서 다룬 네 가지 메커니즘이 어떻게 이를 뒷받침하는지
  4. 다음 단계 -- toC 서비스로의 확장 -- 소비자 대상 규모 확장을 위한 이동 방향

더 깊이 있는 toC 구현 이야기는 별도의 포스트에서 다룰 예정이며, 여기서는 프레임워크와 방향성을 제시합니다.

시리즈

#주제주요 장면기사
1시리즈 소개: cortex 하네스관리자 없이 PR 병합 / 아무도 알아채기 전에 장애 해결ai-harness-intro
...

하나의 장면으로 시작하기

하나의 장면으로 시작하기

+1,742 라인 / 41개 파일 규모의 PR(Pull Request)이 내부 대시보드 웹 앱에 도착합니다. 제목은 "PL dashboard ver.2"입니다. 이 변경 사항은 여러 사업부의 매니저와 팀 리더들에게 프로젝트 가시성을 제공하며, 각자가 자신의 부서나 팀에 해당하는 범위만 볼 수 있도록 제한합니다. 이 작업은 공유 타입(shared types) 패키지에 단일 진실 공급원(SSoT, Single Source of Truth)을 추가하고, INNER JOINLEFT JOIN을 포함하는 SQL이 적용된 API 서버의 새로운 라우트(route), 웹 앱의 새로운 페이지와 뷰 상태(view-state), 그리고 개인 설정(personal-settings) 인터페이스를 추가합니다. 즉, 실제 기능을 구현할 때 기대할 수 있는 전체 스택(stack)이 포함되어 있습니다.

핵심은 이것이 단순한 오타 수정이나 문자열 교체가 아니라는 점입니다. 엔티티(Entities), 리포지토리(repositories), API 라우트(routes), 화면(screens), 필터(filters), 개인 설정(personal settings) 등, 기능을 구현할 때 통상적으로 건드리는 모든 계층이 수정되었습니다. 숙련된 엔지니어 기준으로 규모 면에서 며칠 분량의 작업입니다.

리뷰-수정(review-fix) 사이클은 다음과 같이 진행되었습니다:

  1. PR 오픈 (+1,742 / 41개 파일)
  2. 자동 리뷰 1차 (auto-review pass 1): 주요 결함 발견 (권한 범위(permission-scope) 누락 — 다른 부서의 데이터가 있어서는 안 될 뷰에 노출되는 문제) 및 몇 가지 사소한(Minor) 항목들
  3. 작성자 봇 푸시 (author bot push): 권한 범위 누락 문제를 해결하고 사소한 항목들을 처리
  4. 자동 리뷰 2차 (auto-review pass 2): 사소한(Nit) 항목들이 남아 있으며, 린트(lint) 오류(no-empty-function)가 포착됨
  5. 작성자 봇 푸시 (author bot push): 린트 오류 해결
  6. 자동 리뷰 3차 (auto-review pass 3): 여전히 몇몇 사소한(Nit) 사항들에 대해 코멘트(COMMENTED)가 달려 있으며, 아직 승인(APPROVE)되지 않음
  7. 작성자 봇 푸시 (iteration 2): 로딩 스켈레톤(loading skeleton)을 강화하고, 불필요한 JSDoc 수정을 되돌림(revert)
  8. 자동 리뷰 4차 (auto-review pass 4): 승인(APPROVED) → CI 통과 + 승인(APPROVE) 조건 모두 충족 → 자동 병합(auto-merge) → 운영 환경(production) 반영

PR 오픈부터 병합까지: 4회의 리뷰-수정(review-fix) 라운드, 3회의 작성자-봇(author-bot) 푸시, 인간 리뷰어 개입 0회. 리뷰는 자동 리뷰 봇(auto-review bot)이 수행하고, 수정은 작성자 봇(author bot, PR 작성자가 자신의 머신에서 실행하는 자동 리뷰 응답 에이전트)이 수행하며, 최종 승인(APPROVE)은 AI가 제출하고, CI가 통과(green)되는 즉시 자동 병합(auto-merge) 스크립트가 이를 가져갑니다. 운영 환경(production)에는 56/56 공유 타입 체크(SSoT), 2,284/2,284 API 테스트, 1,113/1,113 웹 스펙(web specs), 그리고 0개의 린트(lint) 에러 상태로 반영됩니다. (cortex는 일반적인 체크를 위한 oxlint@graph-* 규칙을 위한 커스텀 eslint 플러그인으로 린트 작업을 분할하여 수행합니다.)

두 번째 리뷰 패스(review pass)는 주목할 만한 가치가 있습니다. "스코프 폴스루(Scope fall-through)"는 다소 기술적인 발견입니다. 즉, 권한 필터의 허점으로 인해 본인의 부서가 아닌 다른 부서의 데이터가 뷰(view)에 유출될 수 있는 문제였습니다. 이것은 내부 대시보드이므로 외부 유출 사고는 아니지만, "자신과 관련된 것만 보기"는 이러한 대시보드의 핵심 목적입니다. 이를 놓치면 단순히 정보가 새나가는 위험뿐만 아니라, 사용자가 애초에 필터링할 필요가 없는 노이즈에 파묻히게 됩니다. 이는 실수로 병합하기 쉽고 운영 환경에서 인지하기에는 고통스러운 종류의 문제입니다. 자동 리뷰(auto-review)가 첫 번째 패스에서 이를 잡아내고 작성자 측에서 수정하도록 되돌려 보냈다는 사실이 이 전체 흐름을 비엔지니어(non-engineer)에게도 실행 가능하게 만듭니다. 이러한 루프가 없다면, 비엔지니어가 제출한 이 정도 규모의 PR은 위험한 도박이 되었을 것입니다.

그리고: 이 PR의 작성자는 엔지니어가 아닙니다. 비즈니스 측 팀원이 Claude Code에 기능 설명을 전달하고, 관련 기존 코드를 가져오기 위해 지식 그래프(knowledge graph, 2부에서 다룸)에 의존했으며, 그 결과 1,742줄 이상의 PR이 생성되었습니다. 위에서 언급한 4회의 리뷰-수정 라운드는 그 이후에 일어난 일입니다.

이러한 설정은 이 포스트의 핵심 주장과 직접적으로 맞닿아 있습니다: 비즈니스 요구사항(business requirements)을 가장 잘 아는 사람이, 이를 정리하여 엔지니어에게 전달하는 대신 Claude Code를 통해 직접 프로덕션(production)까지 실행한다는 것입니다.

"작성한다(write)"라는 표현에 대해 빠르게 명확히 짚고 넘어가겠습니다. 이 글에서 제가 "작성한다"라고 말할 때, 그것은 에디터에서 한 줄씩 타이핑하는 것을 의미하지 않습니다. 제가 의미하는 바는 비즈니스 요구사항을 Claude Code에 전달하고, 도메인 지식(domain knowledge)을 바탕으로 결과물인 diff(차이점)와 AI 리뷰 코멘트를 판단하며, 프로덕션 머지(production merge)까지 완수하는 것 — 즉, 전체 과정(arc)을 의미합니다. 실제 diff의 대부분은 Claude Code가 작성하며, 리뷰 피드백은 작성자 봇(author bot)이 처리합니다. 인간이 하는 일은 세 가지입니다: 원하는 것을 말로 표현하고, 진행 과정에서 판단(예: "이게 적절한가, 아니면 벗어났는가")을 내리며, 머지할 준비가 되었을 때 승인하는 것입니다. 이 중 어느 것도 기술적인 의미에서의 구현(implementation) 작업이 아닙니다. 그것이 여기서 말하는 "작성한다"의 의미입니다.

물론 여전히 학습 곡선(learning curve)은 존재합니다. Claude Code에 어떤 프롬프트(prompt)를 줄 것인지, 컨텍스트(context)를 위해 어디를 가리킬 것인지와 같은 것들 말입니다. 하지만 그 중 어느 것도 프로그래밍을 배우는 것은 아닙니다. 당신에게 필요한 것은 구문(syntax)이나 프레임워크(framework) 지식이 아니라, 원하는 것을 명확하게 설명할 수 있는 능력입니다.

하네스(harness)가 품질을 보장하므로, +1,742줄 / 41개 파일에 달하는 규모에서도 이 방식은 작동합니다.

범위 외(Out of scope): 이 포스트는 비엔지니어가 프로덕션 저장소(production repo)에 PR을 여는 대신 샌드박스(sandbox) 환경에 자유롭게 앱을 배포하는 경로는 다루지 않습니다. 그것은 다른 메커니즘이며, 이전 포스트에서 다루었습니다: Bridging "I Want to Build" and "I Want to Publish Safely" for Non-Engineers with a Custom Sandbox MCP. 이 포스트는 구체적으로 프로덕션 저장소에 PR을 여는 것 — 전통적으로 엔지니어 전용이었던 정문(front door)에 대해 다룹니다.

변경이 필요할 때, 직접 할 수 있습니다

이전 섹션의 요점은 이것입니다:

변경이 필요할 때, 엔지니어에게 알릴 필요 없이 직접 변경할 수 있습니다.

이것이 지켜질 때, 다음과 같은 요청들이:

  • "대시보드에 새로운 지표(metric)를 추가하고 싶어요"
  • "집계 필터(aggregation filter)가 실제 비즈니스 운영 방식과 일치하지 않아요"
  • "프로덕션 앱에 작은 비즈니스 지원 기능을 내장하고 싶어요"

엔지니어가 현재 진행 중인 작업 뒤에 대기열(queue)로 쌓이는 상황이 중단됩니다. 해결책은 필요가 발생하는 즉시 반영됩니다.

과거의 흐름을 생각해 보십시오. 비즈니스 측의 누군가가 변경이 필요한 작은 사항을 발견합니다. 그들은 요구사항을 작성합니다. 엔지니어를 위해 티켓을 생성하거나 Slack 스레드를 엽니다. 엔지니어는 다른 작업을 수행 중이므로 해당 요청은 대기열에 머뭅니다. 마침내 엔지니어가 그 작업을 처리할 때쯤이면, 해석이 비즈니스가 실제로 의도했던 바와 어긋나게 되고, 의견을 주고받는 과정(back-and-forth)과 검토 단계(review pass)를 거친 후에야 비로소 배포됩니다. 아주 작은 변경이라도 실제 시간(wall-clock time) 기준으로 며칠에서 일주일이 걸립니다.

이것이 바로 **비즈니스 이해와 코드 사이의 번역 계층 (translation layer)**이 초래하는 비용이며, 엔지니어가 바쁠수록 상황은 악화됩니다. 비즈니스의 개선 주기(improvement cycle)가 결국 엔지니어링의 백로그(backlog) 속도에 맞춰지게 되는 것입니다.

요구사항을 알고 있는 사람이 직접 변경 사항을 작성하면, 그 번역 계층과 대기열이 모두 사라집니다.

Business request to production -- the translation layer and queue go away, taking the cycle from days to hours

이것이 작동한 최근의 두 가지 사례를 소개합니다.

최근 배포된 엔지니어가 아닌 사람들의 두 가지 PR (Pull Request)

PR종류 (Kind)크기 (Size)변경 사항
#1573심층 버그 수정 (Deep bug fix)+348 -177 / 7개 파일대시보드의 실적(actuals) 수치가 타겟(target)을 부당하게 초과함. 근본 원인: "어떤 팀을 집계할 것인가"에 대한 정의가 타겟 측과 실적 측 사이에서 비대칭적이었음. 수정 사항은 공유된 "포함할 팀" 목록을 별도의 파일로 분리하고 양쪽 모두가 이를 참조하도록 함. 테스트도 추가됨.
#1557기존 스택 기반 기능 구축 (Feature build on top of existing stack)+1,742 -227 / 41개 파일도입부 장면에 등장한 PL 대시보드 v2. 엔티티(Entities), 리포지토리(repositories), API, UI가 모두 수정되었으나, 웹 앱 자체(스택)는 이미 구축되어 있었으며, 이 기능은 그 위에 올라가는 형태임.

형태는 다르지만, 두 사례 모두 머지(merge)까지 완료된 엔지니어가 아닌 사람들의 PR (Pull Request)입니다.

#1573 -- 심층적인 근본 원인 수정

이 건은 비즈니스 측의 "수치가 이상해 보인다"라는 의견에서 시작되었으며, PR은 데이터 무결성(data-integrity) 문제까지 파고들었습니다. 표면적인 증상은 다음과 같습니다: "대시보드의 실적 수치가 월간 타겟을 초과하며, 팀원들이 실제와 다르다는 것을 알고 있음에도 달성률이 101%로 표시됨." 게으른 해결책이라면 보정 계수(fudge factor)를 넣거나 디스플레이 상에서 값을 제한(clamp)하는 것이었을 것입니다. 하지만 실제로는 그렇게 하지 않았습니다.

작성자는 집계 쿼리(aggregation queries)를 파고들어 실제 원인을 찾아냈습니다: 실적 측과 타겟 측이 서로 다른 테이블을 읽고 있었으며, "어떤 팀을 포함할 것인가"에 대한 정의가 양측 간에 대칭적이지 않았던 것입니다. 타겟 값을 보유하지 않는 팀(디자이너, PMO 등)이 타겟 측에는 나타나지 않았지만 실적 측에서는 집계되고 있었고, 이로 인해 분자가 분모에 비해 부풀려졌습니다.

이 수정은 미봉책이 아닌 구조적인 해결책입니다. 단일 파일이 "이 집계의 범위에 포함되는 팀"을 공유 목록으로 정의하며, 양측 모두 이를 참조합니다. 타겟 측과 실적 측 정의 간의 향후 불일치(drift)가 발생하지 않도록 공유된 상수(constant)를 통해 고정되었습니다.

"어떤 데이터가 집계(aggregation)에서 제외되는가"와 "타겟(target) 측과 실적(actuals) 측이 정말로 대칭적인가"를 다루는 문제는 엔지니어들도 놓치기 쉬운 부분입니다. 비엔지니어가 구조적 수준까지 파고들어 그 지점에서 문제를 해결하는 것이 이번 PR(Pull Request)에서 눈에 띄는 점입니다.

#1557 -- 기존 스택(stack) 위에 구축된 대규모 기능 구현

이것이 서론에서 설명했던 바로 그 PR입니다. +1,742 라인 / 엔티티(entity), 리포지토리(repository), API, 그리고 UI를 아우르는 41개의 파일 -- 이는 사람들이 보통 "수정(modification)"이라고 말할 때 의미하는 범위를 훨씬 넘어선 규모의 변화입니다.

비엔지니어가 이 정도 규모의 변경 사항을 배포할 수 있는 이유는 웹 앱 자체(스택)가 이미 구축되어 있기 때문입니다. 아무도 새로운 앱을 세우지 않으며, 새로운 Cloud Run 서비스를 정의할 필요도 없고, 새로운 의존성 패키지(dependency packages)나 새로운 디렉토리 구조도 필요하지 않습니다. 이 변경 사항은 기존에 이미 존재하는 구조 내에 라우트(route), 페이지, 그리고 리포지토리 항목을 추가할 뿐입니다. 이미 구축된 것 위에 올라타는 방식입니다.

이것이 바로 "기존 스택 위에(on top of an existing stack)"라는 범위입니다. 이것이 경계선이며, 다음 섹션에서 이를 자세히 설명합니다.

용어에 관한 참고 사항: 이 글에서 말하는 "수정(modification)"은 "기존 로직에 대한 작은 조정"보다 더 넓은 의미를 갖습니다. 여기에는 기존 스택 위에 새로운 엔티티, 새로운 엔드포인트(endpoints), 그리고 새로운 페이지를 추가하는 것이 포함됩니다. 제가 긋고 있는 선은 **스택 위에 구축하는 것(building on top of a stack)**과 스택 자체를 처음부터 세우는 것(standing the stack up in the first place) 사이의 차이입니다.

무엇이 작동하고, 무엇이 작동하지 않는가

원칙: 스택을 세우는 것은 어렵지만, 그 위에 구축하는 것은 어렵지 않다

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0