# Introduction

## GraphQL을 쓰는 이유

1. **데이터 정규화**는 힘들다.

   > 데이터 정규화: **중복되는 데이터 제거**

   * JSON 응답이 도착하면, 응답 내 특정 *모델* 을 찾아내 정규화하는 과정이 필요하다.
   * 적은 리소스를 효율적으로 사용해야 한다.

   \[ **규칙성** 이용 ⇒ 자동화를 통해 ]

   * 약속을 정한다 (약속 = 언어) ⇒ GraphQL
   * 약속을 통한 쉬운 정규화
   * 더 쉬운 상태 관리

   ⇒ 1. **타입 시스템을 통한 자연스러운 데이터 정규화: 스키마 이용**

   * **모델 타입**을 정의함으로써

   ⇒ 2. **ID 값**을 통해 자동적으로 데이터/ 뷰 **일관성** 달성하기

   * id 필드를 통해 **GraphQL 클라이언트가 자동으로 상태 관리**
   * 데이터/ 뷰 일관성을 위해 따로 리소스 필요 x
2. 컴포넌트에 **데이터 의존성** 정의
   * 컴포넌트는 선언한 *props에 직접적으로 의존* 하지만, 대부분 **그리고자 하는 모델에도 간접적으로 의존**한다.
   * 결국 상위 모델이 바뀐다면, 이를 **간접적으로 의존하고 있는 하위 컴포넌트들도 확인이 필요**한 side effect가 존재한다.
   * fetch on render ⇒ **fetch then render**

## Fragment: 데이터 의존성 조각

* **데이터 의존성**을 표현할 수 있는 모델, 표현하는 문법
* **컴포넌트는 모델에 포함된 값을 필요로** 한다.

  * 프래그먼트를 통해 **모델의 의존 관계**를 잘 나타낼 수 있음.

  ```graphql
  # Article 모델의 title 필드가 필요
  fragment FragmentName on Article {
  	title
  }
  ```

  * **UI를 그리는데 필요한 데이터들의 집합**을 프래그먼트들의 집합으로 표현 가능

## Co-location

* 컴포넌트와 프래그먼트를 **같은 파일**에 작성하기
* **같은 목적의 코드를 같은 곳에** 위치시키기

## 잘 분리된 컴포넌트

* **명확해진 데이터 의존성**
* 각 컴포넌트가 **어떤 모델의 어떤 필드를** 참조하는지, 표현하고자 하는지, 의존하는지 쉽게 알 수 있음

## Relay의 역할: 데이터 프레임워크

**해결해야 할 문제**: 쿼리 선언(정의)와 서브컴포넌트 간의 불명확한 의존성

* 하나의 쿼리: 성능 향상, 하나의 로딩 state를 사용 ⇒ UX 개선
* 모든 컴포넌트가 각자 데이터를 패칭하면, 독립된 컴포넌트 단위의 데이터 요청 용이

### locally 요청 + globally 최적화

1. **모든 데이터를 하나의 큰 쿼리로** 패칭
2. 각각의 컴포넌트는 **의존 관계를 가진 데이터를 컴포넌트 안에서 정의** (colocating)

👇

* *relay의 compilation(편집) 단계* : 모든 변화는 컴포넌트 데이터 의존성을 수정한다.
  * 하나의 큰 쿼리를 매번 모든 컴포넌트에서 작성할 필요 없이, **각각의 컴포넌트 안에서 독립적으로 필요한 데이터만 패칭**할 수 있게 프래그먼트를 사용
  * **fragment reference**: reference 값에서 데이터 읽기
  * 독립된 데이터 의존성은 **의도치 않은 데이터 업데이트를 방지**한다.
* *선언적인 GraphQL 문법* 사용: **not HOW, but WHAT**

### relay-compiler

* 릴레이 컴파일러가 프래그먼트의 모음을 단일 GraphQL 쿼리로 생성
* 릴레이 컴파일러가 타입 체크 등 오류가 발생할 여지를 줄여줌
* 컨벤션 강제하는 프레임워크적인 면모도 갖고 있음

### relay-runtime

* 릴레이 런타임은 최적화된 쿼리를 런타임에 수행하고 자동으로 상태 관리
* 모델 업데이트 시 의존하는 모든 프래그먼트에 대해 자동 업데이트

## Data Aggregation

* GraphQL을 사용해 **여러 서비스의 모델들을 단일 스키마로** 표현: 여러 REST API 서비스를 **하나의 GraphQL 스키마로 병합**하기

  * e.g. 동네 업체/ 구인구직/ 부동산/ 지역광고

  ⇒ 오로지 클라이언트의 요구에 따라 추가적인 서버 스택을 이용하는 것은 부담... ⇒
* **클라이언트 스키마**: GraphQL 서버를 클라이언트에서 작성하기

  > **\[isomorphic schema]** REST API: DB DB: 클라이언트에서 구현

  * 서버 레이어를 증가시키면, 네트워크 지연시간/ 디버깅 등의 어려움 등 다양한 문제 발생
  * 클라이언트 스키마: GraphQL 서버 코드를 클라이언트 내에 포함하기

## 클라이언트 스키마의 장단점

**\[단점]**

* 워크플로우가 복잡해짐
  * graphQL 스키마 수정 → TS 타입 생성 (graphQL code generator) → graphQL 리졸버 수정 → 컴포넌트 수정 → 릴레이 컴파일 → 결과
* 타입 선언을 이중으로 해주어야 함
* 번들 사이즈 증가

**\[장점]**

* 프래그먼트 **코로케이션**을 통해 유지보수성이 높아짐
* 데이터를 어떻게 처리하느냐 → **어떻게 선언하느냐**
* **컴파일 타임에 오류를 미리** 알 수 있음
* 데이터 관련한 버그가 현저히 줄어듦
  * 이상한 동작을 릴레이가 전부 잡아줌
  * e.g. 페이지네이션 결과에서 같은 아이템이 중복해서 내려온다면, 중복된 아이템을 릴레이가 자동으로 삭제해 줌

## 선언적으로 작성한다는 것

Relay는 컴포넌트마다 필요한 데이터를 **근처에 선언**하기 위해 만들어졌습니다. 이것은 **어떻게 데이터를 가져올지에 대한 걱정을 하지 않고** ***각 컴포넌트마다 어떤 데이터가 필요한지만 선언하는 방식을 말합니다.***

> how는 Relay가 알아서 맡을테니, 우리는 **what을 선언적으로 모아서 관리**해야 한다.

### how와 what으로 코드를 분석해서 분리하기

### how는 npm 라이브러리처럼

* **범용적으로** 사용될 수 있도록 설계하기
* **유닛 테스트**를 촘촘하게 수행해서 안전성 높이기

### what은 연관된 것끼리 가까운 곳에 모으기

* ***어떤 컴포넌트인지, 어떤 의존성***&#xC744; 가지고 있는지 **한 눈에** 알 수 있도록
