
사양 주도 개발의 다음 병목 구간은 '사양 간의 연결'에 있다
요약
AI Agent 중심의 사양 주도 개발에서 개별 사양의 정확성을 넘어 사양 간의 연결을 통한 사용자 경험(UX) 확보의 중요성을 다룹니다. 유저 스토리를 기반으로 상태 전이를 계약화하는 Experience Graph와 Wave 메커니즘을 제안합니다.
핵심 포인트
- Agentic 개발의 핵심 과제는 개별 사양을 넘어선 사양 간의 연결성 확보임
- 유저 스토리를 구현의 기점으로 삼아 상태 전이를 계약(Contract)으로 정의함
- Experience Graph와 Wave 메커니즘을 통해 사양과 구현을 일관되게 연결함
- 단순 태스크 실행을 넘어 사용자 여정(User Journey) 관점의 개발 필요성 강조
코딩 Agent는 Issue를 읽고, 리포지토리(Repository)를 조사하며, 구현 계획을 세우고, 코드와 테스트를 작성하여 풀 리퀘스트(Pull Request)를 생성할 수 있게 되었다. 여러 Agent를 병행하여 구동하고, 다른 Agent에게 리뷰를 맡기는 것도 가능하다.
사양 주도 개발(Specification-driven development)을 뒷받침하는 도구와 수법도 급속도로 정비되고 있다. 모호한 요구사항을 사양으로 구체화하고, 사양으로부터 구현 계획과 태스크(Task)를 만들어 Agent에게 실행시킨다. 이러한 흐름은 이제 일부 선진적인 팀만이 시도하는 것이 아니다.
이하에서는 이와 같이 AI Agent를 중심으로 진행하는 개발을 「Agentic 개발」이라 부른다.
그럼에도 불구하고, 대규모 Web 애플리케이션을 Agent 중심으로 개발하려고 하면 또 다른 문제가 남는다.
개별 사양이 올바르더라도, 그것들을 연결한 프로덕트 경험(Product Experience)이 올바르다고는 할 수 없다.
Agent가 개별 사양을 정확하게 구현할 수 있게 될수록, 문제의 초점은 사양의 내부에서 사양과 사양 사이로 옮겨간다.
개별 사양에 비추어 올바른 API, 페이지, 권한 확인, 테스트를 조합하더라도 이용자가 목적을 달성할 수 있다고는 할 수 없다. 조작의 입구가 없거나, 이동할 곳에 대한 액세스 권한이 없거나, 처리 결과를 다음 화면에서 확인할 수 없는 경우가 있다. 처리가 부분적으로 실패하여 중간 상태가 남더라도, 이용자가 그 상태를 알 방법이나 그로부터 회복할 방법이 없는 경우도 있다.
본고에서 다루는 것은 개별 사양을 자세히 쓰는 방법이 아니다. 사양끼리를 이용자의 경험으로서 연결하는 방법이다.
우리는 디지털 아카이브 Web 애플리케이션 개발에서 다음 가설에 기반한 메커니즘을 구현하여 검증하고 있다.
구현의 기점을 태스크가 아닌 유저 스토리(User Story)에 둔다. 유저 스토리를 충족하는 일련의 상태 전이를 계약(Contract)으로 삼고, 개별 화면 사양이나 API 사양을 그 안에서 정의한다. 나아가 사양, 구현 태스크, 실제 브라우저에서의 확인, 인간에 의한 수락(Acceptance)까지 일관된 참조 관계로 연결한다.
이 가설을 우리는 Experience Graph와 Wave라는 두 가지 메커니즘으로 구체화했다. 본고에서는 기존의 사양 주도 개발이나 비동기 Agent 실행과의 차이점, 비슷한 시기에 제안된 User Journey Graph와의 관계, 실제 프로젝트에 적용하여 알게 된 점을 설명한다.
Issue에서 풀 리퀘스트까지는 이미 자동화되고 있다
비동기 코딩 Agent나 복수 Agent의 협업은 이미 주요 제품에서 제공되기 시작했다.
GitHub Copilot coding agent는 Issue나 지시로부터 비동기적으로 작업하여 초안 풀 리퀘스트를 만든다. OpenAI Codex는 여러 Agent를 병행하여 구동하며 장시간의 태스크를 관리한다. Devin도 작고 명확한 태스크의 병렬 실행을 권장하고 있다. Claude Code Agent Teams에서는 여러 세션이 공유 태스크 리스트와 메시징을 통해 협업할 수 있다.
사양 주도 개발도 마찬가지다. GitHub Spec Kit은 Spec → Plan → Tasks → Implement라는 흐름을 제공하며, 사양, 구현 계획, 태스크를 버전 관리된 산출물로 남긴다. Kiro Specs도 요구사항, 설계, 태스크라는 단계를 가지며, 태스크의 의존 관계를 해석하여 병렬 실행한다.
따라서 다음 요소들은 본고의 신규성이 아니다.
- 사양을 코드보다 먼저 정의하는 것
- 사양으로부터 구현 계획과 태스크를 만드는 것
- 여러 Agent에게 태스크를 병렬로 전달하는 것
- 다른 Agent나 다른 모델에게 리뷰를 맡기는 것
- 대화가 아닌 버전 관리된 기록으로 작업을 인계하는 것
- 구현, 검증, 인간에 의한 확인을 여러 단계로 나누는 것
이것들은 중요하며 이번 시도에서도 이용하고 있다. 하지만 중심적인 제안이 아니라, 후술할 경험 단위의 개발을 실행하기 위한 기반이다.
이번에 변경한 것은 사양을 받은 후의 공정이 아니라, 그 바로 전 단계이다. 주어진 사양을 계획과 태스크로 변환하는 것이 아니라, 먼저 실현하고 싶은 사용자 가치를 정하고, 그것을 유저 스토리와 유저 저니(User Journey)로 기술하며, 그 성립에 필요한 사양과 태스크를 결정한다.
코딩 Agent의 평가 대상도 단일 Issue에서 더 큰 기능이나 장시간의 개발로 옮겨가기 시작하고 있다. 대표적인 SWE-bench는 GitHub Issue와 리포지토리를 주고 문제를 해결하는 수정 사항을 만들게 하는 벤치마크이다. 2026년에 제안된 FeatureBench는 여러 커밋이나 풀 리퀘스트에 걸친 기능 개발을 다룬다. 해당 논문에서는 SWE-bench에서 74.4%의 해결률을 가진 모델이라도, 기능 단위에서는 11.0%밖에 성공하지 못했다고 보고하고 있다.
Issue를 해결하는 것과 기능 전체를 완성하는 것 사이에는 아직 큰 격차가 있다. 나아가 그 너머에는 여러 기능이나 페이지를 연결하여 이용자가 목적을 달성할 수 있는 프로덕트를 만드는 문제가 남아 있다.
올바른 사양을 모아도, 올바른 경험이 되지는 않는다
사양 주도 개발(Specification-driven development)은 합의된 사양을 설계, 구현 계획, 태스크, 코드로 변환하는 데 강점이 있다. 사양서에 유저 스토리(User Story)나 수락 조건(Acceptance Criteria)을 포함할 수도 있다.
하지만 사양에 적힌 기능이 어떤 사용자 가치를 실현하기 위해 필요한지, 여러 사양을 조합하여 유저 스토리가 성립하는지는 자동으로 보장되지 않는다. Agent에게 전달하는 실행 단위가 개별 기능이나 페이지가 되면, Agent는 주어진 사양을 정확하게 구현할 수는 있어도 개발 측이 정의한 사양 자체가 이용자의 목적에 적합한지까지는 평가하지 않는다.
즉, 사양 주도 개발은 사양의 모호함을 줄일 수는 있지만, 사양이 어떤 사용자 가치에서 유래하는지, 또한 사양들끼리 어떻게 연결되는지는 별개의 문제로 남는다.
예를 들어, 다음 요소들은 각각 올바르게 구현될 수 있다.
- 상세 페이지에 「편집 시작하기」 버튼이 있다.
- 편집 페이지에는 권한 확인이 있다.
- 저장 API는 요청된 데이터를 저장한다.
- 저장 후의 상세 페이지는 데이터를 다시 읽어온다.
그럼에도 불구하고, 버튼이 표시되는 이용자가 편집 페이지에 접근할 수 없다면 조작은 도중에 멈춘다. 저장 API가 반환한 식별자를 다음 페이지가 다룰 수 없다면 이용자는 성공을 확인할 수 없다. 저장 처리의 후반부만 실패하고 전반부의 데이터만 남는 경우, 단순히 「실패했습니다」라고 표시하는 것만으로는 복구할 수 없다.
이 문제는 각 성과물의 내부가 아니라, 그것들 사이에 있다.
태스크별 계약(Contract)만으로는 API, 화면, 인증을 가로지르는 경험을 보장할 수 없다. 페이지마다 목적, 주요 조작, 담당해야 할 책임을 정하더라도, 국소적인 설계 단위가 API에서 페이지로 옮겨갈 뿐이다.
필요한 것은 사양을 더욱 길게 만드는 것이 아니다. 이용자가 어떤 상태에서 어떤 상태로 나아가는지를 명시하고, 각 사양이 그 상태 전이(State Transition)의 어느 부분을 담당하는지 확인하는 것이다.
구현의 기점을 유저 스토리로 되돌리기
여기서 말하는 유저 스토리는 구현 태스크에 대한 설명이 아니다.
- 누가
- 무엇을 달성하고 싶어서
- 어떤 결과를 확인할 수 있으면 되는가
를 나타내는 프로덕트 상의 요구사항이다.
유저 스토리와 유저 저니(User Journey)도 같지 않다. 유저 스토리는 목적과 결과를 나타내고, 유저 저니는 그 목적을 달성하기까지 이용자가 거치는 상태와 조작을 나타낸다.
Experience Graph는 프로덕트 경험을 점과 선의 관계로 기술하는 프레임워크이다. 이용자, 유저 저니, 화면 상태, 업무 상태, 커맨드, 참조용 데이터를 노드(Node)로, 화면상의 조작이나 업무 상태의 변화를 유향 에지(Directed Edge)로 나타낸다. 본고에서는 이후 Experience Graph를 단순히 Graph라고 부른다.
본고에서 「Graph에 기록한다」는 것은 유저 저니를 단순히 도식화하는 것이 아니다. 이러한 요소와 관계에 식별자를 부여하여, 화면 사양, API 사양, 구현 태스크가 하나의 상태 전이를 동일한 대상으로 참조할 수 있도록 하는 것을 의미한다.
이용자의 목적과 과제
→ 유저 스토리를 정함
→ 목적을 달성하는 유저 저니를 설계함
...
Graph가 유저 스토리나 유저 저니를 만들어내는 것은 아니다. 이용자 조사, 업무 지식, 프로덕트 판단을 바탕으로 인간이 먼저 정한다. Graph는 그 판단 결과를 Agent가 구현과 검증에 사용할 수 있는 형태로 기록한다.
이 순서가 중요하다. WBS나 Issue를 기점으로 하면 이미 존재하는 태스크를 어떻게 완료할 것인가가 중심이 된다. 유저 스토리를 기점으로 하면, 그 태스크가 정말 필요한지, 다른 빠진 화면이나 처리는 없는지, 그것들을 조합하여 이용자가 결과에 도달할 수 있는지를 먼저 물을 수 있다.
유저 스토리나 유저 저니를 기점으로 하는 것 자체는 애자일(Agile) 개발에서 널리 행해지고 있다. 어려운 점은 하나의 유저 저니를 여러 화면, API, 데이터 처리, 권한 확인으로 나누었을 때, 원래의 목적과 연결 관계를 잃지 않는 것이다. 규모가 크고 여러 Agent가 서로 다른 태스크를 병행하여 구현하는 경우, 이 문제는 더욱 커진다. 각 Agent가 국소적인 수락 조건을 만족하더라도, 태스크 간의 경계에 필요한 처리가 누락될 가능성이 있기 때문이다.
태스크가 Graph(그래프)에서 자동으로 생성되는 것은 아니다. 오케스트레이터(Orchestrator)가 합의된 사용자 저니(User Journey)의 연결을 유지하면서, 구현 책임이 중복되거나 누락되지 않도록 태스크를 분해한다. 변경 대상이 되는 상태 전이(State Transition)로부터 관련된 화면, 업무 처리, 참조용 데이터, 다른 사용자 저니를 열거하고, 태스크의 경계와 의존 관계를 확인한다. 그 후, 각 태스크에 해당 태스크가 담당하는 사용자 저니, 상태 전이, 화면, 업무 처리의 식별자(Identifier)를 부여한다. 백엔드와 프론트엔드를 별도의 태스크로 나누더라도 동일한 상태 전이 식별자를 공유한다.
이를 통해 태스크 분해는 작업량이나 코드 구성만으로 결정되지 않는다. "이 태스크는 사용자 스토리(User Story)를 성립시키는 어떤 상태 전이를 담당하는가"를 설명할 수 있는 것이 분할의 조건이 된다.
프론트엔드를 상태 전이계로 파악하기
프론트엔드는 URL이나 페이지의 목록이 아니다. 이용자에게 보이는 상태와 이를 변화시키는 조작의 연속이다.
예를 들어, 공개 정보로부터 편집을 시작하는 경험에는 다음과 같은 상태가 있을 수 있다.
중요한 것은 URL의 변화 자체가 아니다. "공개 정보를 열람하고 있다", "변경 내용을 입력하고 있다", "편집할 수 있다", "일부만 작성되어 있다"라는 차이를 이용자가 이해하고 다음 조작을 선택할 수 있는 것이다. 동일한 페이지 내에서 상태가 변할 수도 있고, 다른 페이지로 이동할 수도 있다.
백엔드에도 영속적인 상태는 존재한다. 다만, 백엔드의 처리는 커맨드(Command), 인증(Authentication), 트랜잭션(Transaction), 처리 후 참조하는 데이터와 같은 책임 경계로 나누기 쉽다. 프론트엔드는 여러 처리 경계를 이용자에게 연속된 경험으로서 구성한다.
이용자가 하나의 조작이라고 생각하는 처리가 백엔드에서는 여러 개의 API 호출로 나뉘는 경우도 있다. 후반부만 실패하여 중간 결과가 남는다면, 프론트엔드에서는 적어도 다음과 같은 정보와 조작을 제시해야 한다.
- 무엇이 생성 완료되었는가
- 어떤 처리가 실패했는가
- 해당 상태에서 재개할 수 있는가
- 불필요한 중간 결과를 취소할 수단이 있는가
처리를 어느 범위까지 일괄적으로 성공 또는 실패시킬지는 백엔드 측의 설계이다. 그것이 이용자에게 보이는 중간 상태를 생성하는 경우에 한하여, 표시와 회복(Recovery) 방법이 프론트엔드의 설계 대상이 된다.
상태와 전이를 그래프로 나타내는 것 자체는 새로운 것이 아니다. XState는 상태 머신(State Machine)이나 상태 차트(Statechart)로부터 테스트 경로를 생성할 수 있고, GraphWalker는 정점(Vertex)과 간선(Edge)으로 나타낸 모델로부터 테스트 경로를 생성한다. 이번 제안은 그래프나 상태 전이를 발명한 것이 아니라, 이용자에게 보이는 상태 전이를 역할과 권한, 업무 상태, 커맨드, 참조용 데이터, 실패와 회복, 구현 태스크, 실제 환경에서의 검증, 인간에 의한 수락(Acceptance)을 연결하는 공통의 식별 단위로 삼았다는 점에 있다.
Agentic 개발에서의 추적성(Traceability) 측면에서는, 2026년 7월 21일에 논문이 arXiv에 공개되고 ISSTA 2026에 채택된 TraceDev도 유사하다. TraceDev는 여러 의미 요소를 포함하는 유스케이스(Use Case)를 기점으로 하여 요구사항, 설계 모델, 코드 산출물을 이종 추적성 그래프(Heterogeneous Traceability Graph)로 연결한다. 이에 반해 Experience Graph는 코드 산출물을 그래프 내에서 완전히 추적하는 것이 아니다. 이용자가 관측하는 상태 전이를 프로덕트 상의 계약(Contract)으로 삼고, 이를 사양과 태스크의 분할, 실제 API·인증·브라우저에 의한 재실행, 인간에 의한 수락까지 유지하는 데 중점을 둔다. 양자는 우열의 문제가 아니라, 그래프에서 무엇을 정전(Source of Truth)으로 관리하느냐가 다르다.
User Journey Graph라는 인접한 제안
매우 유사한 문제 설정을 가진 외부 제안도 나타나고 있다. User Journey Graph는 사람이 이용하는 프로덕트 시스템의 경험을 기계 판독 가능한 그래프로 표현하는, W3C Community Group에서 검토되고 있는 사양군이다.
현시점에서는 W3C 표준이 아니며, W3C의 표준화 트랙에 있는 사양도 아니다. Editor’s Draft로서 지속적으로 업데이트되고 있는 단계이지만, 문제 설정은 중요하다.
User Journey Graph Architecture는 경험을 URL의 목록이 아닌 상태와 전이로 구성된 것으로 취급하며, 설계상의 의도와 실제로 관측된 이용을 분리한다. 주요 개념은 다음과 같다.
- Journey, State, Transition을 명시적인 타입(Type)으로 표현한다.
- 각 요소에 안정적인 IRI를 부여한다.
- 설계된 경로와 실제로 관측된 경로를 분리한다.
- 실제 이용 기록을 인과관계가 있는 이벤트 열(Event Sequence)로 취급한다.
- 설계와 실제 이용을 대응시켜 이탈이나 마찰을 측정한다.
사양은 JSON-LD의 컨텍스트(Context), RDF의 어휘(Vocabulary), SHACL의 검증 규칙을 공개하고 있다. 단순한 저니 맵(Journey Map)의 교환 형식이 아니라, 서로 다른 도구가 동일한 의미로 데이터를 다루기 위한 온톨로지(Ontology)로서 설계되어 있다. Graph 사양은 Journey, entry, state, transition, exit, 중첩된 journey 등을 정의하며, Runtime 사양은 실제로 관측된 체험을 이벤트의 연쇄로서 기록한다.
디지털 아카이브에서는 자료의 내용뿐만 아니라, 자료 간의 관계, 출처, 동일성, 변경 이력을 기계 판독 가능(Machine-readable)하게 만드는 것이 중요하다. User Journey Graph도 마찬가지로, 화면의 모습 그 자체가 아니라 체험을 구성하는 개념과 관계에 식별자를 부여하려 하고 있다. 이러한 방향성은 여러 에이전트(Agent)나 도구가 동일한 프로덕트 이해를 공유하는 데 있어서도 유망해 보인다.
우리의 Experience Graph는 User Journey Graph를 구현한 것이 아니다. 양자는 비슷한 시기에 독립적으로 설계되었으며, 현재의 저장 형식도 JSON-LD나 SHACL에는 대응하지 않는다.
공통점과 차이점을 정리하면 다음과 같다.
| 관점 | User Journey Graph | 이번 Experience Graph |
|---|---|---|
| 주요 목적 | 체험의 의도, 실제 이용, 측정을 공통 형식으로 연결한다 | 체험을 에이전트에 의한 구현, 검증, 수용의 기점으로 삼는다 |
| ... |
User Journey Graph도 Surface나 조건 분기 등을 포함하는 넓은 사양군이며, "UX 도표만을 다룬다"라고 설명하는 것은 옳지 않다. 반면, Conditions module의 규정 대상에는 업무 상태의 모델이나 조건을 평가하는 실행 시점 API는 포함되지 않는다.
이번 시도는 User Journey Graph를 다른 형식으로 재현하는 것이 목적이 아니다. User Journey Graph가 다루는 일반적인 체험 표현에 대해, 프로젝트 고유의 업무 상태, 커맨드(Command), 참조용 데이터를 겹치고, 나아가 유저 저니를 개별 사양이 충족해야 할 계약(Contract)으로서 구현 태스크의 분할과 완료 판정에 사용했다는 점이 다르다.
장래에는 Journey, State, Transition, Surface를 User Journey Graph에 대응시키고, 업무 처리와 개발 절차를 프로젝트 고유의 확장으로서 분리할 여지가 있다.
Experience Graph를 업무 상태와 구현까지 확장하기
이번 Experience Graph에서는 다음 네 가지를 나누어 기록한다.
| 층 (Layer) | 기록하는 내용 | 여기서는 결정하지 않는 것 |
|---|---|---|
| 유저 저니 (User Journey) | 누가, 무엇을 목적으로, 어디서 시작하여, 어떤 결과를 확인하는가 | route나 API의 구성 |
| 화면과 조작 | 어떤 화면 상태에서 무엇을 표시하고, 어떤 조작을 제시하는가 | 업무상의 상태 그 자체 |
| 업무상의 상태 변화 | 어떤 커맨드에 의해 무엇이 변하고, 어떤 조건을 지키는가 | 화면의 배치나 모습 |
| 구현과의 대응 | API, 참조용 데이터, 구현 계획, 테스트 등이 어떤 상태 전이를 실현하는가 | 이용자의 목적이나 가치 판단 |
이 네 층을 나누는 목적은 이용자의 목적을 구현상의 편의로부터 보호하면서, 양자의 연결을 검사할 수 있도록 하기 위함이다.
유저 저니에는 route나 API를 쓰지 않는다. 먼저 누가 무엇을 달성하고 싶은지를 정한다. 그 후에 각 상태를 어떤 화면이 나타내는지, 어떤 업무 처리가 상태를 바꾸는지, 어떤 API와 read model이 그것을 실현하는지를 대응시킨다.
하나의 조작에 대해 적어도 다음 관계를 기록한다.
- 조작하는 이용자의 역할
- 조작이 나타나는 화면 상태
- 조작 전에 필요한 업무상의 조건
- 실행하는 커맨드
- 업무 상태가 어디에서 어디로 변하는가
- 성공 후 결과를 읽는 방법과 표시 대상
- 실패 시 남는 상태와 회복 방법
구체적인 예를 보인다. 우리가 개발하는 디지털 아카이브 웹 애플리케이션 "WMHGIS"에서는, 공개된 행정 구역을 기점으로 역사적 사실상의 변경을 기록할 때, 먼저 비공개 workspace를 생성하고 이어서 변경 내용을 나타내는 초기 데이터를 생성한다. Graph에서 생성한 유저 저니 도표에서는 다음과 같이 표현된다.
[IMG:1]
그림의 사각형은 화면과 그 상태를 나타낸다. 예를 들어 surface.historical_change#form은 역사적 사실상의 변경을 입력하는 화면의 입력 중 상태이다. 화살표는 이용자의 조작을 나타내며, "Workspace 생성"이라는 조작에 의해 입력 중 상태에서 미커밋(uncommitted) 변경이 있는 workspace의 편집 상태로 진행된다.
이 그림은 사용자 여정(User Journey)의 정상적인 경로에 초점을 맞춘 생성 뷰(generation view)이다. 그 정본(source of truth)은 nodes와 edges 배열을 가진 하나의 graph.json이며, 저장 형식은 JSONL이 아니다. 아래에서는 대응 관계를 읽기 쉽게 하기 위해 관련 필드만 추출하여, 한 요소를 한 줄로 하는 JSONL 형식으로 다시 나열하였다.
{"id":"journey.contributor_historical_change","type":"journey","actor":"actor.contributor","entry":"surface.place_detail#populated","terminals":["surface.workspace_editor#dirty"],"path":["interaction.place.start_historical_change","interaction.historical_change.create"]}
{"id":"interaction.historical_change.create","type":"interaction","from":"surface.historical_change#form","to":"surface.workspace_editor#dirty","failure_to":"surface.historical_change#partial_failure","command":"command.historical_change.bootstrap","transition":"transition.historical_change.bootstrap","reads":["read.workspace"]}
{"id":"command.historical_change.bootstrap","type":"command","endpoint":"POST /api/workspaces then POST /api/workspaces/{workspace_id}/historical-successions","atomicity":"manual_recovery","postconditions":["workspace exists","successor unit/event/relation entries exist"],"recovery":"if the second request fails, show the created workspace ID and link to resume or archive it"}
여기서 사용자 여정은 두 가지 조작을 순서대로 참조하며, 그중 'Workspace 생성'이 업무 커맨드(command)와 상태 전이(state transition)를 참조하고 있다. 성공 시에는 workspace 편집 화면으로 진행되는 반면, 두 번째 단계의 API 호출에 실패한 경우에는 partial_failure로 진행된다. 커맨드 측에는 일부만 생성된 workspace의 식별자를 표시하여, 재개 또는 취소를 선택할 수 있도록 한다는 회복(recovery) 방법도 기록되어 있다.
이것은 atomicity(원자성)를 항상 UX상의 계약으로 삼아야 한다고 주장하는 것이 아니다. 백엔드(backend)의 처리 경계에 의해 사용자에게 보이는 중간 상태가 발생하는 경우, 그 상태를 그래프(Graph)에 연결한다는 의미이다.
현행 그래프(Graph)에서는 사용자의 역할(actor), 사용자 여정(journey), 화면 상태(surface), 업무 상태(domain_state), 커맨드(command), 참조용 데이터(read_model)를 노드로 가지며, 화면 간의 조작과 업무상의 상태 변화를 에지(edge)로 가진다.
그래프(Graph)로부터 다음 리뷰·구현용 파일을 생성한다.
| 생성 파일 | 목적 |
|---|---|
journeys.md | 모든 사용자 저니 (User Journey)의 상태와 조작을 Mermaid 다이어그램으로 확인한다 |
page-contracts.md | 화면별 목적, 상태, 이용자의 역할, 책무, 조작을 확인한다 |
route-inventory.md | 등록된 경로와 화면, 계약 상태, 액세스 가능한 역할을 확인한다 |
journey-smoke-inventory.md | 각 저니의 시작 상태, 순서가 있는 조작, 완료 상태를 실제 브라우저 확인 단계로 전달한다 |
coverage.md | 계약 완료·미계약 화면과 저니의 이행 상황을 파악한다 |
검증 프로그램은 사용자 저니의 시작점부터 종료점까지의 연속성, 이용자의 역할과 화면의 대응, 변경 조작에 필요한 커맨드(Command)·상태 변화·참조용 데이터·실패 상태, 구현된 경로와 Graph와의 차이, 생성물의 차이 등을 검사한다.
단, 소스 코드나 테스트의 모든 것을 Graph로 자동 추적하고 있는 것은 아니다. Graph 내부의 관계는 자동으로 검사한다. 한편, 구현 계획, 태스크, 테스트, 검증 기록에는 동일한 식별자를 참조하게 한다. Graph와 실제 API, 인증, 화면과의 일치는 실제 환경에서 사용자 저니를 재실행하여 확인한다.
사용자 스토리로부터 구현하고, 동일한 스토리로 돌아오기
Graph가 설계 자료 상태에 머물러 있다면 구현의 기점은 변하지 않는다. 이번 운용에서는 구현 태스크를 Graph 상에서 연결된 사용자 저니 전체, 또는 그 일부의 상태 전이를 실현하는 것으로 한정했다. 고립된 API, 페이지, 컴포넌트만을 구현 태스크로 추가하지 않는다.
백엔드와 프론트엔드를 별도의 태스크로 나눌 수는 있다. 다만, 양쪽 모두 동일한 상태 전이를 참조하며, 연결 부분의 확인 책임을 명시한다. 태스크는 구현 책임을 나누는 것이지, 사용자 스토리를 분단하는 것이 아니다.
이번 시도에서는 하나의 사용자 가치에 대해, 의미의 확정부터 구현, 독립적인 검증, 실제 환경에서의 사용자 저니 재실행, 인간에 의한 수락(Acceptance), 학습까지를 다루는 단위를 내부적으로 Wave라고 부르고 있다.
여기서의 Wave는 병렬 실행 가능한 태스크의 집합을 의미하지 않는다. Kiro 등이 의존 관계에 따른 병렬 실행을 Wave라고 부르는 용법과는 다르다. 명칭 자체에 신규성은 없으며, 중요한 것은 태스크 완료가 아니라, 수락 가능한 사용자 경험을 완료의 단위로 삼았다는 점이다.
인간에 의한 주요 판단은 구현 전과 통합 후의 두 가지로 집약했다.
구현 전에는 대상이 되는 이용자, 목적, 시작 상태, 완료 시 확인할 수 있는 결과, 주요 조작을 합의한다. 구현 중에는 Graph, 승인된 구현 계획, 테스트, 기존 디자인 규칙을 바탕으로 Agent가 진행한다. 통합 후에는 실제 사용자 저니를 통해 의미, 정보의 우선순위, 다음 행동, 조작 결과를 인간이 확인한다.
사양 주도 구현 루프, 서로 다른 Agent에 의한 구현 계획 리뷰, 버전 관리된 결과물에 의한 비동기 인수인계는 이 흐름을 뒷받침하기 위해 이용했다. 이것들을 새로운 방법으로 제안하는 것이 아니라, Graph로 정의한 경험을 여러 Agent가 놓치지 않고 구현하기 위한 기반으로 삼고 있다.
실제 프로젝트에 적용하며 알게 된 점
여기서부터는 내부 실시 기록, WBS, 구현 계획, 검증 기록, Codex의 세션 로그를 바탕으로 어느 단계에서 무엇을 검출할 수 있었는지 보여준다. 이하에서는 각 Wave를 내부 관리상의 일련번호로 표기한다.
태스크의 완료와 사용자 저니의 성립은 다르다
Graph 도입 전에 실시한 Wave 17에서는 7개의 구현 태스크와 1,000건 이상의 자동 테스트가 모두 통과되었고, 빌드도 성공했다.
하지만 실제 이용자 역할(Role), API, 브라우저에서 사용자 저니를 확인하자, 알림을 받는 이용자가 알림 대상 화면에 액세스할 권한을 가지고 있지 않았다. 개별 화면이나 테스트에 문제가 없더라도, 알림에서 이동지까지를 하나의 경험으로서 확인하지 않으면 발견할 수 없는 불일치였다.
이 사례가 보여주는 것은 자동 테스트의 건수를 늘리는 것만으로는 태스크 간의 연결을 확인할 수 없다는 것이다. 사용자 스토리를 완료 조건으로 삼으려면 이용자의 역할, 입구, 조작, 이동지, 결과 확인까지를 하나로 이어지는 흐름으로 다루어야 한다.
Graph는 사양과 구현의 연결 불량을 검출하는 기준이 되었다
Experience Graph를 처음부터 기준으로 삼은 시도에서는 5개의 사용자 저니를 시작 상태부터 완료 상태까지 정의하고, 이를 8개의 구현 태스크로 나누었다. 구현 후에는 동일한 5개의 사용자 저니를 실제 API, 인증, 브라우저에서 재실행했다.
이 과정에서 다음과 같은 불일치가 발견되었다.
- Graph에 전이(Transition)가 정의되어 있음에도 불구하고, 실제 화면에는 링크나 조작 진입점이 없다
- 화면이 Graph에서 합의된 완료 상태로 진행되지 않고, 다른 처리를 실행한다
- 처리 후에 표시해야 할 정보를 일의적으로 특정할 수 없다
- 다단계 처리가 도중에 실패했을 때, 남은 상태로부터 재개할 수 없다
이러한 문제들은 페이지나 API의 존재 여부만 조사해서는 찾아내기 어렵다. Graph 상의 전이를 구현의 분할 단위 및 브라우저 확인의 단위로 삼았기에 검출할 수 있었다.
이미 구현이 진행 중이었던 Wave 21에 Graph를 사후에 대응시키자, 기록된 경로가 대상 기능의 전체를 포괄하지 못한다는 사실을 알 수 있었다. 병행하여 실시한 인수 감사(Acceptance Audit)에서도 15개의 인수 조건 중 완전히 충족된 것은 2건뿐이었으며, 13건은 부분적인 구현에 그쳐 있었다. 이 결과는 Graph 단독으로 얻은 것은 아니지만, 태스크나 산출물의 존재와 유저 스토리(User Story)의 성립을 분리하여 평가할 필요가 있음을 보여준다.
Graph의 검사와 인간에 의한 인수는 서로 다른 문제를 다룬다
Wave 21에서는 자동 테스트를 실행하고, 실제 브라우저에서도 15개의 시나리오를 확인했다. 나아가 모바일과 PC 양쪽 모두에서 화면 표시를 확인했다. 그 후 인간에 의한 인수 과정에서는 다음 세 가지 사항에 대해 재작업이 필요했다.
- 편집 화면에 도달해도 무엇을 수정하고 어떻게 완료해야 하는지 알 수 없다
- 후보가 되는 값이나 여러 개의 경합(Conflict)을 어떻게 다루어야 하는지 알 수 없다
- 목록과 상세의 책임이 동일한 화면에 혼재되어 있다
다만, 이것들은 Graph를 통한 연결 검사의 누락과는 성격이 다르다. 당시 Graph가 계약(Contract)하고 있었던 것은 이용자, 상태, 조작, 업무 처리 간의 관계였으며, 정보의 의미가 충분히 전달되는지, 화면의 책임이 적절한지, 다음 행동이 자연스러운지에 대한 평가는 인간에 의한 인수의 범위였다.
중요한 것은 두 가지를 동일한 검사라고 생각하지 않는 것이다. Graph는 합의된 경험과 구현이 연결되어 있는지를 검사한다. 인간은 애초에 그 경험이 이해하기 쉽고 목적에 부합하는지를 판단한다.
한편, 인간의 지적을 그 자리에서의 임시적인 화면 수정으로 끝내지 않고, 유저 저니(User Journey)와 화면의 책임으로 되돌릴 수 있었다. 화면을 목록과 상세로 나누고, 여러 개의 경합을 하나의 작업 단위로 취급하며, 수정 후 제출까지를 하나의 연속된 경험으로서 Graph에 반영한 뒤, 구현과 브라우저 확인을 다시 수행했다.
이 시도로 말할 수 있는 것, 아직 말할 수 없는 것
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기