# GraphQL: 엔터프라이즈의 허니문은 끝났다

> Clean Markdown view of GeekNews topic #25091. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=25091](https://news.hada.io/topic?id=25091)
- GeekNews Markdown: [https://news.hada.io/topic/25091.md](https://news.hada.io/topic/25091.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-12-15T16:33:23+09:00
- Updated: 2025-12-15T16:33:23+09:00
- Original source: [johnjames.blog](https://johnjames.blog/posts/graphql-the-enterprise-honeymoon-is-over)
- Points: 5
- Comments: 2

## Summary

**GraphQL**이 약속한 ‘필요한 데이터만 요청하는 효율성’은 **BFF(Backend for Frontend)** 구조가 일반화된 엔터프라이즈 환경에서는 이미 달성된 목표에 가깝습니다. 실제 운영에서는 스키마 관리, 캐싱, 오류 처리 등에서 복잡성이 급격히 높아지며, REST가 제공하는 단순성과 관찰성의 이점을 잃기 쉽습니다. 결과적으로 GraphQL은 특정 상황에서는 유용하지만, 대부분의 기업 시스템에서는 **과도한 선택**으로 평가됩니다.

## Topic Body

- **GraphQL**은 데이터 과다 요청 문제를 해결하려 하지만, **대부분의 엔터프라이즈 환경에서는 이미 다른 방식으로 해결된 문제**임  
- **BFF(Backend for Frontend)** 구조가 일반화된 기업 시스템에서는 GraphQL의 주요 장점이 크게 줄어듦  
- **구현 복잡도, 관찰성 저하, 캐싱 문제, ID 제약, 파일 처리의 불편함** 등으로 실제 운영 환경에서 비용이 커짐  
- **REST**는 단순하고 빠르며, 오류 처리와 온보딩이 쉬워 대규모 팀 환경에서 더 효율적임  
- 결론적으로 GraphQL은 **특정 상황에서는 유용하지만, 대부분의 엔터프라이즈에는 과도한 선택**이라는 평가  

---

### GraphQL이 해결하려는 문제
- GraphQL의 핵심 목적은 **overfetching(불필요한 데이터 과다 요청)** 방지  
  - 클라이언트가 필요한 필드만 요청해 불필요한 데이터 전송을 줄이는 구조  
  - 새로운 UI 요구사항마다 백엔드 수정이 필요 없다는 장점  
- 그러나 실제 환경에서는 이 이상적인 구조가 **복잡한 현실과 맞지 않음**

### BFF로 이미 해결된 overfetching
- 대부분의 엔터프라이즈 프런트엔드는 **BFF(Backend for Frontend)** 계층을 사용  
  - UI에 맞게 데이터를 조합하고, 여러 다운스트림 호출을 통합하며, 백엔드 복잡성을 숨김  
- REST 기반 BFF는 이미 필요한 데이터만 반환할 수 있어 **GraphQL의 장점이 중복됨**  
- GraphQL 계층이 REST API로부터 데이터를 가져올 경우, **overfetching이 단지 한 단계 아래로 이동**  
- 여러 페이지가 동일 엔드포인트를 공유할 때 GraphQL이 유용할 수 있으나,  
  - 그 이점은 **몇 킬로바이트 절약을 위해 더 많은 설정과 유지보수 부담을 감수하는 수준**

### 구현 복잡도와 생산성 저하
- GraphQL은 REST보다 **구현 시간이 훨씬 길고 복잡함**  
  - 스키마, 타입, 리졸버, 데이터 소스 정의 등 추가 작업 필요  
  - 스키마와 클라이언트 동기화 유지 부담 존재  
- GraphQL은 **소비(클라이언트 편의)** 를 최적화하지만, **생산(서버 개발 속도)** 을 희생  
- 엔터프라이즈 환경에서는 **생산 속도와 단순성**이 더 중요함

### 관찰성과 모니터링 문제
- GraphQL의 **HTTP 상태 코드 체계가 비일관적**  
  - 200 응답에도 오류가 포함될 수 있어, 모니터링 시 성공/실패 구분이 어려움  
- REST는 2XX/4XX/5XX로 명확히 구분되어 **대시보드 필터링이 직관적**  
- Apollo 등에서 커스터마이징 가능하지만, 이는 **추가 설정과 정신적 부담**을 초래  
- 운영 중 장애 대응 시 REST보다 **문제 파악이 어렵고 복잡함**

### 캐싱의 현실적 한계
- Apollo의 **정규화 캐싱(normalized caching)** 은 이론적으로 강력하지만 실제로는 **취약하고 복잡**  
  - 필드 하나만 다른 쿼리도 별도로 취급되어 수동 연결 필요  
  - 캐시 디버깅이 별도의 문제로 발전  
- 반면 REST는 단순히 전체 응답을 캐싱해 **안정적이고 유지보수 용이**

### ID 필드 제약의 문제
- Apollo는 모든 객체에 **id 또는 _id 필드**가 필요하다고 가정  
  - 많은 엔터프라이즈 API는 고유 ID가 없거나, 전역 식별자가 아님  
- 이를 맞추기 위해 BFF가 **로컬 ID 생성 로직을 추가**해야 함  
  - 결과적으로 **불필요한 필드와 로직 증가**, overfetching 감소 효과 상쇄

### 파일 업로드 및 다운로드의 비효율
- GraphQL은 **이진 데이터 처리에 부적합**  
  - 실제로는 다운로드 URL을 반환하고, 파일은 REST로 전송  
  - PDF 등 대용량 데이터를 GraphQL 응답에 포함하면 **성능 저하**  
- 이로 인해 “**단일 API**”라는 GraphQL의 이상이 깨짐

### 온보딩과 학습 곡선
- 대부분의 개발자는 **REST 경험이 풍부**하지만 GraphQL은 학습 필요  
  - 스키마, 리졸버, 쿼리 구성, 캐싱 규칙, 오류 처리 등 새 개념 학습 필요  
- 이로 인해 **팀 온보딩 속도 저하**  
- REST는 “지루하지만 확장성 높은” 접근으로 **대규모 팀에 적합**

### 오류 처리의 복잡성
- GraphQL 오류 응답은 **nullable 필드, partial data, errors 배열, 확장 상태 코드** 등으로 복잡  
  - 어떤 리졸버가 실패했는지 추적 필요  
- REST는 단순히 400/500으로 구분되어 **이해와 디버깅이 용이**

### 결론: GraphQL은 틈새 기술
- GraphQL은 **특정 상황에서는 유효한 도구**  
  - 그러나 대부분의 엔터프라이즈 환경에서는 이미 BFF와 REST로 문제 해결  
  - 주요 과제는 overfetching이 아니라 **관찰성, 신뢰성, 속도**  
- 결과적으로 GraphQL은 **좁은 문제를 해결하면서 더 넓은 복잡성을 초래**  
- “GraphQL은 나쁘지 않지만, **대부분의 경우 필요하지 않다**”는 결론

## Comments



### Comment 47849

- Author: colus001
- Created: 2025-12-16T16:51:53+09:00
- Points: 2

장단점이 있겠지만, 스키마 레벨로 데이터와 접근 제어를 설계하고, 뭐 하나 추가할때마다 Rest API 에서 추가하고 그러다가 나중에 다 리턴하는 것보단 나아 보입니다. 단점이 분명하지만, 장점도 분명해서 ㅎㅎ

### Comment 47776

- Author: neo
- Created: 2025-12-15T16:33:23+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=46264704) 
- GraphQL의 주요 문제를 **overfetching**이라고 규정한 글에 동의하지 않음  
  내가 보기엔 진짜 장점은 (a) **엄격한 타입 기반 계약**을 강제한다는 점, (b) **스키마 진화**가 훨씬 쉽다는 점임  
  타입 시스템 덕분에 입력과 출력이 항상 정의된 형태를 따르고, 커스텀 스칼라 타입(예: 전화번호, 이메일 등)을 쓰면 버그와 보안 이슈를 크게 줄일 수 있음  
  또, 새로운 필드 추가나 기존 필드 폐기가 표준화되어 있어서 서버·클라이언트 모두 인지 부하가 적음
  - 나도 overfetching이 핵심 문제라고 생각하지 않음  
    내가 GraphQL을 쓰는 이유는 **API 조합과 진화** 때문임. 특히 M:N 구조의 대규모 시스템에서 “클라이언트가 필요한 걸 기술 → 서버가 조합 → 도메인 서비스가 해결”하는 흐름이 장기적으로 훨씬 관리하기 쉬움  
    좋은 **observability**와 결합되면 데이터 접근의 강력한 기반이 됨
  - OpenAPI 스펙에서 TypeScript 타입을 생성하면 양방향 계약이 생기므로, 그 부분은 GraphQL이 해결할 문제가 아님
  - 나도 GraphQL의 **강력한 계약성**이 가장 큰 이유라고 생각함  
    또 하나는 **resolver 재사용과 federation**이 쉬운 점임. REST에서는 이게 꽤 번거로움
  - 요청과 응답을 **zod**로 pruning하는 건 간단함. 그 이유만으로 GQL을 도입하진 않겠음  
    스키마 진화는 **Protobuf**도 잘 처리함
  - GraphQL이 protobuf 통신과 뭐가 다른지 모르겠음. 둘 다 정의에 맞게 파싱되니까

- GraphQL의 진짜 장점은 **UI 데이터를 작은 조각으로 조합**할 수 있다는 점임  
  [이 영상](https://www.youtube.com/watch?v=lhVGdErZuN4)처럼 fragment colocation을 활용하면, 하위 컴포넌트를 수정해도 다른 부분에 영향이 없음  
  쿼리가 fragment 기반으로 자동 생성되므로, 필드 제거 시 다른 컴포넌트가 깨질 위험도 줄어듦  
  규모가 작거나 빠른 개발이 중요하지 않다면 GraphQL은 과투자처럼 보일 수도 있음
  - Apollo가 잘못된 방향으로 사람들을 이끌어서 GraphQL의 진짜 장점을 못 느끼게 했다고 생각함  
    **Colocation**은 정말 혁신적인 개념인데, Apollo는 이걸 거의 언급하지 않았음
  - 문제는 GraphQL이 아니라 **Apollo Client**임  
    Relay의 문서화는 여전히 부족하지만, Entrypoint 개념은 훌륭함
  - fragment masking에는 동의함  
    다만 graphql-codegen의 구현은 **플러그인 호환성**이 떨어져서, 우리는 직접 플러그인을 만들어야 했음  
    생태계 전반의 일관성이 부족함

- overfetching이 GraphQL의 핵심 문제라는 말은 과장임  
  GraphQL은 ORM이 해결하는 **임피던스 불일치**를 클라이언트 레벨에서 다루는 도구라고 생각함  
  Relay 같은 **컴파일러 기반 툴링** 없이 쓰는 건 안티패턴임  
  요즘은 AI가 데이터 레이어를 자동 생성해주니 GraphQL의 필요성은 줄어드는 듯함
  - “컴파일러 없이 GraphQL을 쓰면 안 된다”는 말에 공감하지만, 그게 BFF에서 몇 줄 코드 쓰는 것보다 쉬운지는 의문임
  - 좋은 GraphQL 툴링 예시로 [Isograph VSCode 확장](https://www.youtube.com/watch?v=6tNWbVOjpQw)을 추천함  
    존재하지 않는 필드를 선택하면 자동으로 생성해주는 등 **개발 경험(DevEx)** 이 뛰어남
  - **URQL**과 **gql.tada**는 훌륭한 클라이언트 사이드 툴링임
  - GraphQL 툴링으로 뭘 쓰는지 궁금함. **IntelliJ**와 **Postman**도 지원이 좋음
  - overfetching이 별문제 아니라는 말엔 동의 못함  
    현대 웹의 느려짐은 대부분 **데이터 과다 전송** 때문임. 실제로 많은 앱이 0.5% 이하의 효율로 동작함

- 나는 2016년부터 GraphQL을 써왔음  
  본질적으로 GraphQL은 **RPC 스펙**임. 서버의 “Action(Args) → ResultType” 맵으로 구현되는 형태임  
  REST의 여러 엔드포인트 대신, GraphQL은 하나의 `/query` 엔드포인트에서 resolver 맵을 통해 동작함  
  결국 OpenAPI나 gRPC처럼 입력·출력이 타입으로 정의된 구조임
  - 2015년부터 GraphQL을 써왔는데, **Relay 없이 GraphQL을 쓴다면 진짜 강점을 못 느낄 가능성**이 큼  
    Apollo가 fragment masking을 추가하면서 조금 나아졌지만, 여전히 Relay 중심의 사고가 중요함
  - 이 설명은 너무 단순함. **쿼리 해석 과정**을 완전히 생략했음
  - 클라이언트가 요청 필드를 지정할 수 있다는 점을 빼먹었음
  - 원문 글과 관련성이 약해 보임
  - GraphQL은 React 페이지 전체가 하위 컴포넌트의 요구사항을 모아 하나의 대형 쿼리를 만들고,  
    백엔드가 이를 **단일 SQL 쿼리**로 변환해 처리할 때 가장 효율적임  
    resolver는 DB에서 직접 가져올 수 없는 데이터에만 예외적으로 써야 함

- 예전에 팀을 이끌 때 FE가 GraphQL을 원해서 도입했음  
  결과적으로 각 페이지마다 하나의 거대한 쿼리로 모든 데이터를 가져오고, 수정 시 전체 JSON blob을 다시 보냈음  
  앱은 돌아갔지만, 결국 회사가 피벗하면서 그 코드는 사라짐  
  실제로 많은 GraphQL 프로젝트가 이런 식으로 **형식만 갖춘 구현**으로 끝나는 것 같음

- GraphQL의 **인증(auth) 흐름**은 가장 큰 난제 중 하나임  
  resolver가 다양한 컨텍스트에서 호출되기 때문에, 모든 경우를 고려해야 함  
  복잡성과 사고 비용이 너무 커서, 결국 필드를 잠그게 됨  
  직접 [graphql-autharoo](https://github.com/verdverm/graphql-autharoo)를 만들었지만 충분하지 않았음  
  대부분의 기능은 GraphQL 없이도 더 단순하게 구현 가능함
  - GitHub에서도 **권한 관리(authz)** 가 큰 문제임  
    GraphQL 리소스마다 세밀한 권한을 추가해야 해서, 전체 리소스가 업데이트되기 전까지 쿼리가 작동하지 않음  
    “**REST로 다시 만드는 게 낫다**”는 말이 나올 정도로 부담이 큼
  - **데코레이터 기반 인증**을 써봤는지 묻고 싶음  
    직접 조합하지 말고 완성도 높은 서버 프레임워크를 쓰는 게 낫다고 생각함

- GraphQL은 겉보기엔 좋아 보이지만, 실제로는 **시간이 지날수록 유지가 힘든 기술**임  
  많은 기술이 그렇듯, 결국 **바퀴는 바퀴일 뿐**이라는 교훈을 줌

- GraphQL의 장점은 스키마에 필드만 추가하면 모든 클라이언트가 바로 쿼리할 수 있다는 점임  
  “이 필드도 추가해달라”는 FE 요청이 사라져서 협업이 단순해짐  
  또, 스키마 스냅샷을 만들어 **통합 테스트에서 변경 감지**하기도 쉬움  
  REST보다 일관성이 높다고 느꼈지만, 이는 개인적 경험임
  - 하지만 그 장점이 **양날의 검**임  
    A에서 E까지 연쇄적으로 요청할 수 있으니, 성능 저하나 **프론트엔드-데이터 구조 결합**이 심해짐
  - 요즘은 대부분 **풀스택 TypeScript 환경**이라 이런 협업 문제는 줄어듦  
    React도 이제는 프레임워크 기반 SSR과 **서버 컴포넌트**를 기본으로 함  
    결국 **TypeScript가 클라이언트와 서버를 통합**하는 방향으로 가고 있음

- GraphQL이 **DB 부하나 비효율 쿼리** 문제를 어떻게 막는지 궁금함  
  악의적인 쿼리가 내부 상태를 폭발시킬 수도 있지 않나?
  - 대부분의 서버는 **쿼리 복잡도(비용) 제한**을 두고, 기준을 넘으면 요청을 거부함

- REST가 너무 지루해서 GraphQL을 시도 중임  
  서버와 클라이언트가 요청·응답을 **컴파일 타임에 합의**할 수 있다는 점이 마음에 듦  
  블로그들이 “이건 별로야”라고만 하지 말고, **대안 기술**도 함께 제시했으면 좋겠음
  - 만약 **isomorphic TypeScript**를 좋아한다면, **tRPC**가 GraphQL보다 더 깔끔한 대안임  
    두 기술 모두 **클라이언트-서버 계약 문제**를 잘 해결함
