Files
document-haness/docs/n+1liner/final/.techviz/strategy-journey/spec.json
T

214 lines
7.0 KiB
JSON
Executable File

{
"version": "1.1",
"id": "strategy-journey",
"title": "두 형제 문제는 Fetch Join에서 합류한 뒤 단계별 해법으로 최종 구조가 된다",
"question": "과제 요구사항에서 시작해 기준선의 N1·N2 분기와 실패·개선을 거쳐 최종 피드 조회 구조는 어떻게 발전하는가?",
"type": "flow",
"direction": "LR",
"audience": [
"백엔드 엔지니어",
"성능 개선 과정을 검토하는 독자"
],
"summary": "요구사항과 모델을 거친 기준선에서 N1·N2가 동시에 갈라져 Fetch Join으로 합류하고, 실패 뒤 Batch Fetch·DTO Projection·Top-3·Keyset·가시성 인덱싱을 차례로 거쳐 최종 피드 조회 구조에 도달한다.",
"alt": "요구사항과 모델에서 기준선으로 진행한 뒤 N1과 N2로 분기하고 Fetch Join에서 합류해, 실패와 다섯 개선 단계를 거쳐 최종 피드 조회 구조에 이르는 흐름도.",
"long_description": "왼쪽에서 과제 요구사항, 도메인·데이터 모델, 최초 피드 조회 기준선 순으로 시작한다. 기준선에서 컬렉션 N+1(N1)과 User·Page 연관의 숨은 쿼리(N2)가 서로 앞뒤가 아닌 형제 문제로 동시에 갈라지고, 두 경로는 Fetch Join 시도에서 합류한다. 이 시도는 다중 컬렉션·페이징 실패로 이어진다. 마지막 노드는 Batch Fetch, DTO Projection, 아이템별 Top-3, Keyset Pagination, 가시성 조건 인덱싱을 거쳐 최종 피드 조회 구조에 도달하는 순서를 담는다.",
"source_context": {
"document": "/home/donghyeon/workspace/ai-tool/topic-arrange/n+1liner/n+1liner.md",
"document_sha256": "1bb38964ca2a849690f5355646c1aa988111b4cd4e1055c6cb05cf7e5fc35cde",
"anchor": {
"kind": "marker",
"value": "strategy-journey",
"line": 27
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "요구사항에서 최종 조회 구조까지 한 방향으로 발전하면서 기준선의 두 형제 문제가 분기했다가 Fetch Join 시도에서 합류하므로, 좌측 출발점·중앙의 분기와 합류·우측 종착점을 갖는 component-flow가 전체 여정을 가장 직접적으로 드러낸다.",
"focus_node": "fetch-join-failure"
},
"groups": [],
"nodes": [
{
"id": "requirements-model-baseline",
"label": "요구사항·모델·기준선",
"kind": "journey-stage",
"role": "source",
"description": "전체 여정은 과제 요구사항에서 도메인·데이터 모델을 거쳐 최초 피드 조회 기준선으로 시작한다.",
"details": [
"1 과제 요구사항",
"2 도메인·데이터 모델",
"3 최초 피드 조회"
],
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "collection-n-plus-one",
"label": "컬렉션 N+1 (N1)",
"kind": "problem",
"role": "service",
"description": "기준선에서 N2와 동시에 나타나는 컬렉션 조회 문제다.",
"details": [
"유형: 컬렉션 N+1",
"발생: 기준선과 동시에",
"관계: N2와 형제 문제",
"진행: Fetch Join으로 합류"
],
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "hidden-to-one-queries",
"label": "User·Page 숨은 쿼리 (N2)",
"kind": "problem",
"role": "service",
"description": "기준선에서 N1과 동시에 나타나는 User·Page 연관의 숨은 쿼리 문제다.",
"details": [
"유형: User·Page 숨은 쿼리",
"발생: 기준선과 동시에",
"관계: N1과 형제 문제",
"진행: Fetch Join으로 합류"
],
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "fetch-join-failure",
"label": "Fetch Join → 실패",
"kind": "query-strategy",
"role": "service",
"description": "N1과 N2가 Fetch Join 시도에서 합류한 뒤 다중 컬렉션·페이징 실패로 이어진다.",
"details": [
"1 N1·N2 합류",
"2 다중 컬렉션·페이징 실패"
],
"emphasis": "warning",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "improvement-chain",
"label": "후속 개선 → 최종 구조",
"kind": "query-strategy",
"role": "sink",
"description": "실패 뒤 다섯 조회 전략 단계가 명시된 순서로 발전해 최종 피드 조회 구조를 만든다.",
"details": [
"1 Batch Fetch",
"2 DTO Projection",
"3 아이템별 Top-3",
"4 Keyset Pagination",
"5 가시성 조건 인덱싱",
"6 최종 피드 조회 구조"
],
"emphasis": "primary",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
}
],
"edges": [
{
"id": "baseline-reveals-n1",
"from": "requirements-model-baseline",
"to": "collection-n-plus-one",
"label": "기준선에서 갈라짐",
"kind": "problem",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "baseline-reveals-n2",
"from": "requirements-model-baseline",
"to": "hidden-to-one-queries",
"label": "기준선에서 갈라짐",
"kind": "problem",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "n1-joins-fetch-join",
"from": "collection-n-plus-one",
"to": "fetch-join-failure",
"label": "Fetch Join으로 합류",
"kind": "flow",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "n2-joins-fetch-join",
"from": "hidden-to-one-queries",
"to": "fetch-join-failure",
"label": "Fetch Join으로 합류",
"kind": "flow",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
},
{
"id": "failure-to-improvements",
"from": "fetch-join-failure",
"to": "improvement-chain",
"label": "실패 뒤 단계별 개선",
"kind": "improvement",
"evidence": [
{
"start_line": 25,
"end_line": 25
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "line 25의 전체 순서를 유지하면서 문서 폭에 맞추기 위해 연속된 출발 세 단계, Fetch Join과 그 실패, 실패 뒤 다섯 개선 단계를 각각 하나의 단계 노드 안에 번호로 묶었다."
}
}