07 — Patterns Distilled
한 줄 답: 앞 6개 사례를 교차하면 공통 패턴 8개와 3개의 결정 분기점이 남는다. 모바일 우선이냐 / 공개 API냐 / 마이크로서비스 통합이냐가 도구의 모양을 결정한다. 이 문서는 사례를 추상화하여 당신의 문제에 적용 가능한 결정 트리로 압축한다.
Why — 사례에서 패턴을 뽑아야 하는 이유
사례 글을 그대로 따라 하면 작동하지 않는다. Netflix가 150 subgraphs를 운영한다고 우리도 federation 가자는 조직 크기를 무시한 결정이다. GitHub의 5,000 points/hour를 그대로 베끼면 우리 부하 패턴에 안 맞는 값을 쓰는 것.
사례에서 공통 패턴과 분기점을 분리하면 — 어떤 결정이 보편적이고 어떤 결정이 상황 의존적인지 보인다.
| 흔한 오해 | 현실 |
|---|---|
| ”유명 회사가 쓰면 우리도 써야 한다” | 문제 모양이 같을 때만 같은 도구가 작동 |
| ”패턴은 기술 결정에만 영향” | 패턴은 조직 결정까지 좌우 (federation은 조직 문제) |
| “결정 트리는 첫 도입 때만” | 도입 후 3년·5년 뒤에도 분기점이 다시 나타남 |
결정 트리 = 자기 상황을 사례에 매핑하는 도구. 이 문서가 이 챕터의 실용적 결론이다.
How — 패턴 추출 방법
1) 공통 패턴 — 모든 사례에 반복 등장
8개 패턴 — 6개 사례 중 최소 4곳 이상에서 확인된 것만 포함.
P1. 단일 endpoint + Introspection
| 사례 | 적용 |
|---|---|
| Meta | /graphql 단일, persisted query ID로 변환 |
| GitHub | api.github.com/graphql 단일 |
| Shopify | /api/{version}/graphql.json 분기별 |
| Netflix | Router 단일, subgraphs 내부 |
| Airbnb | Gateway 단일 |
| Atlassian | api.atlassian.com/graphql 단일 |
→ 모든 사례가 단일 endpoint. REST의 path 라우팅을 완전히 포기. 대신 introspection으로 schema 탐색.
P2. Persisted Query
| 사례 | 적용 |
|---|---|
| Meta | 강제 — 모든 production 쿼리가 ID 기반 |
| Shopify (Hydrogen) | edge SSR에서 사용 |
| Airbnb | persisted query + client 표준화 |
| Netflix | persisted query + signing |
Persisted query가 푸는 문제:
- 네트워크 페이로드 — 매 요청에 쿼리 텍스트 안 보냄
- 보안 — 등록되지 않은 쿼리 거부 (introspection 차단 가능)
- 분석 — operation별 추적 용이
→ 대규모 production에서 거의 표준. 작은 팀은 DEV 모드만 raw query, PROD는 persisted.
P3. Schema Registry + Check
| 사례 | 적용 |
|---|---|
| Netflix | GraphOS schema registry |
| Airbnb | 자체 + Apollo Studio |
| PayPal | 사내 schema registry |
| GitHub | 내부 schema review + CI |
rover subgraph check 같은 명령이 CI에서 깨지는 변경을 차단한다. Federation은 schema registry 없이는 운영 불가.
P4. Connection Pagination (Relay)
type Query {
issues(first: Int, after: String, last: Int, before: String): IssueConnection!
}
type IssueConnection {
edges: [IssueEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type IssueEdge {
node: Issue!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}| 사례 | 적용 |
|---|---|
| GitHub | 모든 list가 connection (offset 없음) |
| Shopify | 동상 |
| Meta / Relay | spec 발원지 |
| Netflix / Airbnb | federation에서 기본 페이지네이션 |
→ offset pagination을 거의 안 쓴다. 이유: cursor가 분산 시스템에서 안정적, Relay client cache와 정합.
P5. 버전 없음 + Deprecation Policy
| 사례 | 정책 |
|---|---|
| GitHub | preview header + @deprecated reason + 18~24mo deprecation |
| Meta | 내부 schema는 지속 진화, client compile 시점 검증 |
| Netflix | composition check + safe deprecation (field usage) |
| Airbnb | 동상 |
| Shopify | 예외 — 분기별 URL 버전 (2024-10) + deprecation |
→ URL 버전을 피한다. 대신 field-level deprecation + 분석으로 안전성 확인.
P6. 클라이언트 라이브러리 표준화
| 사례 | 클라이언트 |
|---|---|
| Meta | Relay |
| GitHub (공개) | Apollo, urql, Relay, others |
| Shopify | Apollo, Hydrogen 내장 |
| Netflix | DGS + Apollo (서버), Apollo Client (소비자 앱) |
| Airbnb | Apollo Client (전 플랫폼) |
| PayPal | Apollo Client (사내 표준) |
→ 회사 안에선 Apollo Client 또는 Relay 하나로 표준화. 여러 클라이언트가 섞이면 cache 정합·devtools·codegen 모두 깨짐.
P7. REST/RPC와의 공존
| 사례 | 공존 모델 |
|---|---|
| GitHub | REST v3 + GraphQL v4 — 같은 데이터 |
| Shopify | Storefront/Admin GraphQL + REST 일부 |
| Atlassian | REST 위에 GraphQL gateway |
| Airbnb | Thrift RPC + GraphQL layer |
| 내부 GraphQL, 공개 REST |
→ GraphQL이 REST를 죽이지 않는다. 서로 다른 use case를 각자의 강점으로 푼다.
P8. Operation Analytics → Field Usage
| 사례 | 도구 |
|---|---|
| GitHub | 내부 operation tracking |
| Netflix | GraphOS field usage |
| Airbnb | 자체 + Apollo Studio |
| PayPal | 사내 metrics |
*“이 필드를 누가 쓰는가”*를 추적할 수 없으면 deprecation을 영영 못 한다. Schema 거대화는 분석 부재에서 시작.
2) 결정 분기점 — 상황에 따라 다른 결정
분기점 1. 공개 API인가 / 내부인가
| 공개 API (GitHub, Shopify, Atlassian) | 내부 (Meta, Netflix, Airbnb, PayPal) |
|---|---|
| 외부 개발자의 알 수 없는 쿼리 | 내부 컴파일러가 쿼리 통제 |
| Cost-based rate limit 필수 | persisted query만으로 충분 |
| Schema preview/deprecation 엄격 | 내부 compile-time 검증 |
| Introspection 노출 (또는 제한) | introspection 차단 가능 |
| Naming convention 엄격 (Relay) | 사내 표준만 맞으면 OK |
| 인증: API key, OAuth, JWT | 내부 인증 (mTLS, JWT) |
공개 API는 Day 1부터 cost system + deprecation policy. 내부는 시작은 가볍게 가능.
분기점 2. 조직 규모 100명 미만 / 200명 이상
| 100명 미만 | 200명 이상 |
|---|---|
| 모놀리스 graph (단일 schema) | Federation 또는 stitching |
| 한 팀이 schema 소유 | 도메인별 subgraph 소유 |
| Schema review PR이 하루 | Schema review가 주 단위 병목 → federation 도입 |
| DGS/Apollo Server 단독 | + Apollo Router + Schema registry + Composition CI |
| 운영 비용 낮음 | 운영 비용 높음 (플랫폼 팀 필요) |
100~200 사이는 모놀리스를 유지하면서 모듈 분리가 보통 더 싸다. Federation은 플랫폼 팀 1~3명 비용을 감당할 수 있을 때.
분기점 3. 처음부터 GraphQL / 기존 시스템 위
| 처음부터 (Greenfield) | 기존 시스템 위 (Brownfield) |
|---|---|
| AppSync, Hasura, Postgraphile | Airbnb 패턴: REST/RPC + GraphQL layer |
| schema = source of truth | schema = 통합 facade |
| DB → schema 자동 생성 가능 | 도메인 어댑터를 수동 작성 |
| 빠르게 prototype | 마이그레이션 5년 |
| 작은 팀에 유리 | 큰 기존 시스템에 유리 |
Brownfield가 압도적으로 흔하다. Airbnb의 점진 패턴이 기본 도입 경로.
3) 결정 트리 (실용)
4) 안티패턴 — 사례에서 반대로 가지 말라
| 안티패턴 | 어디서 깨지는가 | 대응 |
|---|---|---|
| 공개 API에 cost system 없이 | DDoS-by-query | GitHub의 point system 차용 |
| GraphQL = REST 제거 | 외부 통합 모두 깨짐 | GitHub처럼 공존 |
| Federation을 50명 조직에 | 플랫폼 팀 비용 못 감당 | 모놀리스 graph로 시작 |
| 클라이언트 라이브러리 혼용 | cache 정합 깨짐 | 회사 안 하나로 통일 |
| Schema registry 없이 federation | subgraph 한 팀 변경이 supergraph 다운 | CI에 subgraph check |
| persisted query 없이 production | 페이로드 + 보안 + 분석 모두 손해 | Meta 패턴 차용 |
| Money를 Float scalar로 | 결제 금액 1원 차이 | Decimal scalar (Shopify) |
| 버전을 URL에 | ”버전 없는 진화”의 장점 포기 | field-level deprecation |
| Introspection을 production에 그대로 | 공격자가 schema 전체 탐색 | persisted query + introspection 차단 |
| Schema 거대화를 방치 | Coursera의 7000 types 위기 | field usage 추적 Day 1 |
What — 6개 사례의 최종 비교표
| 항목 | Meta | GitHub | Shopify | Netflix | Airbnb | Atlassian |
|---|---|---|---|---|---|---|
| 도입 동기 | 모바일 N+1 | 공개 API 차별화 | 헤드리스 + 외부 앱 | 50~60 내부 앱 통합 | BFF 폭증 해소 | 멀티 프로덕트 통합 |
| 출발 | 2012 | 2016 | 2018~ | 2018 (Studio Edge) | 2018 | 2020~ |
| 공개/내부 | 내부 | 공개 | 공개 (두 API) | 내부 | 내부 | 공개 |
| Federation | 단일 graph | 단일 graph | 두 분리 graph | Federation v2 | Federation + Viaduct | 단일 gateway |
| Cost system | (내부, 비공개) | Points/hour | Leaky bucket | (내부) | (내부) | (불명) |
| Persisted query | 강제 | 옵션 | Hydrogen 내장 | 강제 | 표준 | 옵션 |
| 오픈소스 산출 | graphql-js, Relay, spec | (해당 없음) | Hydrogen | DGS framework | Viaduct (2026) | (해당 없음) |
| 외부 영향 | 모든 사례의 기원 | 공개 API 청사진 | e-commerce 표준 | Federation 운영 표본 | 점진 채택 표본 | 멀티 프로덕트 표본 |
What-if — 패턴을 잘못 적용하면
1) 패턴을 순서 없이 도입하면
→ Federation 먼저 + Schema registry 나중 = 수개월간 깨진 supergraph 운영. 대응 순서:
- 단일 graph 운영 안정화 (P1·P4·P6)
- Persisted query·analytics (P2·P8)
- Schema registry + deprecation (P3·P5)
- Federation 검토 (조직이 200명 넘으면)
- REST와의 공존 정책 명문화 (P7)
2) 분기점을 한 번만 보면
→ 도입 후 3년·5년 뒤에 조직 규모가 바뀌면 분기점도 다시 본다. 대응: 연 1회 분기점 재검토. Coursera는 3년 뒤 schema 거대화에서 다시 결정.
3) 안티패턴을 모르고 시작하면
→ 위 10개 안티패턴 중 3~4개를 동시에 밟는다 — 가장 흔한 실패 모드. 대응: 안티패턴 표를 PR 체크리스트로 만든다.
4) “큰 회사 사례 = 우리 사례”라고 믿으면
→ 50명 조직이 Netflix를 따라가면 플랫폼 팀 비용으로 회사가 깨짐. 대응: 우리 조직 사이즈와 가장 가까운 사례를 기준으로 잡는다.
5) 패턴 적용 후 측정 없이 진행하면
→ “GraphQL 도입했는데 빨라졌나”를 정량 측정 못 함 — Airbnb의 10x faster 같은 회고가 안 나옴. 대응: 도입 전 baseline 메트릭 측정 (페이지 로드, 코드 라인 수, 배포 빈도).
Insight — 흥미로운 이야기
”패턴 8개 중 5개가 Meta 내부에서 먼저 검증”
P2(persisted query), P4(connection), P5(버전 없음), P6(Relay 클라이언트), P8(operation analytics)은 Meta가 내부에서 먼저 검증한 뒤 외부에 흘렸다. Facebook이 만든 것을 다른 회사가 검증하는 흐름이 아니라 — *Meta가 내부 운영 압력에서 발견한 패턴이 생태계 표준이 됐다는 점이 의미심장. 즉 생태계의 베스트 프랙티스 = Meta 14년 운영 노하우의 외부화.
”Federation은 기술이 아니라 조직 패턴”
Netflix·Airbnb·PayPal 모두 Federation을 기술 우월성이 아니라 Conway’s Law의 압력에서 도입했다. 즉 Federation 채택률은 조직 사이즈 분포와 상관관계가 있지 기술 성숙도와는 약하게 관계한다. 작은 조직은 Federation 거의 안 쓴다 — 그게 정답이지 덜 진화한 게 아니다.
”Public API GraphQL의 채택이 2017~2020년에 정체”
GitHub(2016), Shopify(2018) 이후 큰 공개 API GraphQL이 별로 안 나왔다. 이유는 cost system + deprecation policy 운영이 너무 비싸다. 대부분 회사는 내부 GraphQL + 공개 REST(Twitter 모델)로 정착. 공개 GraphQL은 GitHub·Shopify처럼 외부 개발자 생태계가 critical할 때만 가치가 있다.
”AppSync · Hasura · Postgraphile의 의미”
AppSync(2017), Hasura(2018), Postgraphile(2016) 같은 DB → GraphQL 자동 생성 도구의 등장은 GraphQL 도입 곡선의 두 갈래를 만들었다 — 직접 운영 (Meta 패턴) vs 자동 생성 (greenfield 패턴). 작은 팀이 GraphQL을 빠르게 받을 수 있는 길이 생겼고, 큰 회사의 내부 표준과 작은 회사의 빠른 시작이 다른 패턴으로 분기.
”Viaduct는 Federation의 진화 또는 회귀”
Airbnb의 Viaduct(2026)는 Federation에서 다시 단일 거대 schema로 일부 회귀한 패턴이다 — 단 분산 실행 엔진은 유지. 이 의미는 — Federation도 영원한 답이 아니다. 5~10년 운영하다 보면 다음 패턴이 나타난다. GraphQL 생태계는 아직 진화 중이고, 결정 트리도 5년 단위로 갱신해야 한다.
”사례 글이 생태계 학습 곡선을 압축”
이 챕터의 진짜 가치는 6개 회사가 5~14년에 걸쳐 발견한 패턴을 1.5시간에 압축한다는 점이다. 사례 글이 없었다면 — 각 회사가 처음부터 다시 같은 실수를 한다. 기술 블로그·컨퍼런스 토크·spec WG 참여가 생태계의 집단 학습 메커니즘. 다음 회사가 이 챕터를 읽고 1년을 단축할 수 있다.
요약 + 다이어그램
6개 사례에서 공통 패턴 8개(단일 endpoint, persisted query, schema registry, connection pagination, deprecation policy, 클라이언트 표준화, REST 공존, operation analytics)와 결정 분기점 3개(공개/내부, 100/200명, greenfield/brownfield)가 추출된다. 어떤 사례가 옳다가 아니라 우리 분기점에서 어느 쪽인가가 결정의 기준. 안티패턴 10개를 PR 체크리스트로 만들면 3~5년의 흔한 실수를 미리 차단할 수 있다.
이 챕터에서 다른 챕터로 돌아가는 링크
| 패턴/분기점 | 돌아갈 챕터 |
|---|---|
| P1 단일 endpoint | 00-foundations, 04-transport |
| P2 persisted query | 04-transport, 05-cache-performance |
| P3 schema registry | 07-security-governance, 06-federation |
| P4 connection pagination | 01-schema-sdl |
| P5 deprecation policy | 07-security-governance |
| P6 클라이언트 표준화 | 02-execution-resolvers, 04-transport |
| P7 REST 공존 | 08-theory-and-alternatives |
| P8 operation analytics | 07-security-governance |
| 분기점 2 (federation) | 06-federation |
| 안티패턴: N+1 | 03-n-plus-1-dataloader |
| 안티패턴: cost system | 07-security-governance |
참고 자료 (이 챕터의 원천 자료 모음)
- (사례별 출처는 01~06 문서 각각 끝의 참고 자료 섹션 참고)
- Lee Byron, GraphQL Working Group —
github.com/graphql/graphql-spec - GraphQL Summit (Apollo) —
youtube.com/c/ApolloGraphQL - GraphQL Conf (Linux Foundation) —
graphql.org/conf - spec.graphql.org — October 2021 (현재 안정),
@defer/@streamproposal (WG) - Apollo Federation spec —
specs.apollo.dev/federation/v2.x
챕터 종료: 이 챕터를 다 읽었다면, GraphQL이 무엇인가에서 우리 문제에 적용 가능한가까지의 전체 결정 경로를 가지고 있다. 다음 챕터는 없다. *글로서리(
99-glossary)*로 가서 기억 안 나는 용어를 다시 정리하거나, 처음으로 돌아가 챕터 1을 지금의 눈으로 다시 읽는 것을 권한다 — 같은 글이 다르게 보일 것.