Introduction

Introduction

GraphQL을 쓰는 이유

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

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

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

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

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

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

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

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

    • id 필드를 통해 GraphQL 클라이언트가 자동으로 상태 관리
    • 데이터/ 뷰 일관성을 위해 따로 리소스 필요 x
  2. 컴포넌트에 데이터 의존성 정의

    • 컴포넌트는 선언한 props에 직접적으로 의존 하지만, 대부분 그리고자 하는 모델에도 간접적으로 의존한다.
    • 결국 상위 모델이 바뀐다면, 이를 간접적으로 의존하고 있는 하위 컴포넌트들도 확인이 필요한 side effect가 존재한다.
    • fetch on render ⇒ fetch then render

Fragment: 데이터 의존성 조각

  • 데이터 의존성을 표현할 수 있는 모델, 표현하는 문법
  • 컴포넌트는 모델에 포함된 값을 필요로 한다.
    • 프래그먼트를 통해 모델의 의존 관계를 잘 나타낼 수 있음.

      # 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은 연관된 것끼리 가까운 곳에 모으기

  • 어떤 컴포넌트인지, 어떤 의존성을 가지고 있는지 한 눈에 알 수 있도록