BNB Lesson

2019년 8월 13일

주최자 : 김민상

참가자 : 김종범, 맹세열, 최우석

0. 서론

진행방식

  • 오늘은 정말로 강의 형식으로 진행할 예정

  • 지금부터 시작하여 끝날 때까지, 모자라면 내일 계속

    • 이전 미팅 때 잠깐씩 빠르게 설명하고 넘어가는 방식이 아님
    • 매 파트마다 질문 시간 / 실습 시간을 아주 길게 갖을 것
    • 따라서 뭘 물어볼지, 뭘 체크할지 계속 고민하면서 프리하게 진행

숙지사항

  • 이 문서는 당연히 모두에게 공유할 거지만, 각자 노트 펴고 각자의 방식으로 필기하기
    • 따라서 모든 내용을 담으려고 하지 말고, 본인들이 그동안 들어는 왔지만 깊이 찾아보지 않았던 것들을 찾아서 체크할 것
    • 그 체크한 내용에 따라서 질문 내용을 찾아볼 것
  • 이 강의에서 제시하는 모든 내용에 대해 아래와 같은 고민을 하나씩 다 해 보기
    • 왜 이걸 써야 하는지?
    • 이걸 어디에 쓸 건지?
    • 쓰지 않았을 때와 비교해 뭐가 좋은지?
    • 내가 이해한 개념이 제시된 것과 맞는지?

1. Javascript (ES8)

ES?

  • 우리가 쓰던건 ES5, 앞으로 쓸 건 ES8 + Typescript
  • Typescript 는 이따 보고 우선 ES8 부터.

ES8 - ES5 = ?

  • forEach, map, filter, reduce, some, every

    • arrow function
    • var, let, const
    • class
    • module import/export
    • Promise
    • Decorator
    • async await

2. Node.js

왜 Node.js?

  • 장점
    • 개발자들의 활성도 가장 높음
      • 거의 모든 진보한 기술들의 구현체가 다 있음
      • 거의 모든 개발 서포트 툴이 다 있음
    • Isomorphic
    • 스타트업들의 de facto standard
  • 단점
    • 뭐가 있을까? 생각나는대로 찾아보자.
      • non-blocking 이라서 귀찮은거?
      • 속도?
      • 잘 죽는다? (single thread니까)
      • 동적 언어라서?
      • 콜백 지옥?
      • 점점 더 설정 지옥?

그냥 지금 생각나는 구현체 각자 찾아보기

  • 본인이 이전에 만들고 싶었던 거나, 관심 있었던 것.
  • 혹은 PHP / Python 등에서 혹시 있나? 하며 찾아봤던 것.

Isomorphic

  • 어떤 효과를 얻을 수 있을까?
    • SSR이 되는 유일한 언어
    • 서버/클라이언트가 공용 코드를 가지는 데에서 오는 이점?
    • 우리 내부적으로, 공통으로 사용할만한 라이브러리를 만들 수 있을까?

2019년에 알아야 할 상식

  • npm 말고도 yarn 이라는 패키지 매니저가 있음
    • npm 이 워낙 느려서 yarn 이 미친듯 치고 올랐으나 npm 도 절치부심하여 현재는 다 따라잡은 상태
  • package.json 은 아주 철저하게 관리해야 함
    • dependency / dev-dependency 구분도 확실히
    • 사용하는 패키지가 아주아주 많으므로 이 관리를 대충하면 망할 수 있음
  • 번들러는 Webpack 으로 천하통일되는 분위기
    • 심지어 Angular 도 쓰기 시작함
    • grunt, gulp, yeoman 을 아직 쓰는 곳도 많으나, webpack 하나로 통합하여 사용하는 것이 추세
  • 그외 궁금한 것?

기본적인 사용법

  • npm init
  • npm install
  • npm uninstall
  • node-cli
  • npm run

3. Typescript

왜 정적타입인가?

  • 일반적으로 정적타입은 대규모 개발에 동적타입은 소규모 개발에 어울린다고 알려짐
    • 대규모/소규모는 어떻게 나눌까?
    • 개인적으로, 한 코드를 다루는 구성원이 컨벤션을 모두 완벽히 따르기가 어려울 때-가 소규모 를 벗어났다고 생각.
  • 강력한 도구의 지원
    • 맛들이면 벗어나기 싫어짐
  • 생산성 향상
    • 많은 버그를 '미리' 발견할 수 있음
    • 단위테스트 해야 할 분량이 크게 줄어듦
  • 설정이 귀찮은데...
    • 뭘 써도 2019년엔 어차피 Webpack 돌려야 함. 기왕 돌릴 거 같이 돌리자.

그럼 왜 Typescript 인가?

  • Flow 라는 대안
    • 깊이 본 적은 없음
  • ES7 의 상위호환?
    • ES버전이 몇인지 신경 쓸 필요없이 걍 씀
  • Angular 쓸 거잖아?
    • 끗.

쓰기 위해 알아야 할 것들

설정에서 알아야 할 것들

  • tsconfig.json 문서
    • 이 내용을 다 알 필요는 없겠지만 이것들이 대충 뭐인지 정도는 알고 있어야 함
    • 특히 paths 설정은 필수
  • tsc, tsc -watch, ts-node
    • 뭔지 정도는 알고 있어야 함

4. Nest.js

왜 Nest.js 인가?

  • 모두가 다 쓰는 그냥 express.js 는?
  • 그럼 Nest.js 는 뭐가 다르지?
    • 많이 다름, First Steps만 달려보자 Nest.js First Steps
    • "우린 니가 뭘 하고 싶든 다 할 수 있게 준비해뒀지"
      • 하지만 바퀴를 재발명하진 않겠어. 우린 그냥 모듈 래퍼라고.
  • express 도 nest 도 내가 뭘 써야 할지 강요하지 않음
    • 하지만 뭘 써야 하는 경우, express 는 가이드가 전혀 없고, nest 는 가이드가 있음
    • nest 의 가이드 는 2019년에 해당 분야에서 가장 활발히 사용되는 기술을 Angular-way 한 방법으로 모듈화 해 놓은 것이 포인트.

Controllers / Providers / Modules

  • Controllers
    • Decorator를 통해 조금 가독성 좋게 만들어놓은 app.get / post / put / delete
    • 사실 우린 별로 쓸 일이 없지.
  • Providers
    • Angular 의 Service 와 비슷한 개념 (angluarjs 의 서비스와 비교해도 그렇게 많이 다르지는 않다)
    • 한마디로, Injection 을 하기 위해 존재하는 코드 묶음.
    • Resolver도 이 자리에 들어간다. (GraphQL)
  • Modules
    • CommonJS 의 모듈보다는 Angular NgModule 을 닮은 놈
    • 4가지를 기술한다.
      • imports : 가져올 놈
      • exports : 내보낼 놈
      • providers : 내 프로바이더
      • controllers : 내 컨트롤러
    • Dynamic Module
      • 모든 모듈이 정적으로 그냥 선언되어 정의되면 그만일까?
        • 개중에는 분명 설정 파일이 필요한 케이스가 있음. (사실 더 많음)
        • 그럴 때 모듈 선언 자체를 동적으로 할 수 있다!
      • 이럴 때 사용하는게 forRoot
  • Middleware 와 그 비슷한 따까리들
    • Exception Filters
      • Request/Response 처리 도중 Exceptionthrow 되었을 때 메세지 필터링
      • 막 튀어나온 Exception 을 클라이언트가 보기 편하게 정리하는 역할
    • Pipe
      • Request 가 던져준 쌩 데이터를 우리의 필요에 맞게 가공(Transform) 하거나 검증(Validation) 하는 처리
      • 문서에서는 Joi 말고 class-validator 부분만 볼 것 (우린 이것만 씀)
      • 사실 별로 쓸 일은 없는게 GraphQL 단에서 다 거름
    • Guards
      • Authentication 처리 목적을 위한 전용 middleware 라고 보면 됨
      • canActivate 메소드를 override 하여 해당 메소드에 승인 가능/불가능 여부를 판단하여 리턴하는 구조
      • @SetMetadata 데코레이터를 통해 로그인한 유저의 role 을 구분 처리하는 것도 가능
    • Interceptors
      • AOP (Aspect Oriented Programming)
        • 개발자 교양 삼아 알아두면 좋은 것 (참고 포스트)
        • 서로 다른 일을 하는 오만가지 것들 중 절차상 비슷한 일을 하는걸 묶어서 동시에 처리하는 개념
      • RxJs 방식을 통해 Request/Response 앞뒤로 다양한 작업이 가능
      • 현재 쓸 곳은 딱히 없음
  • Custom Decorators
    • Nest.js 에서 상당히 중요한 개념 (정확히는 ES7 에서 나온 개념) 인 Decorator 지시자 를 커스텀하게 구현하는 방식
    • Decorator directive 를 간단하게 보면, class 에도 property 에도 걸어놓을 수 있는 '함수'
    • 현재는 @CurrentApp, @CurrentUser 두 곳에서만 사용중

Techniques & Recipes

  • Authentication
    • 필수 파트, 여기서 제안하는 방식으로 passport-jwt 적용
  • Database
    • 필수 파트, 여기서 제안하는 방식으로 typeorm 적용 (TypeORM 파트에서 설명)
  • File upload
    • 필수 파트, 여기서 제안하는 방식으로 multer 적용
  • Validation
    • 필수 파트, 여기서 제안하는 방식으로 class-validator 적용
  • Logger
    • f9 log 대체, 적용 예정 (자체 로거 / winston 사용)
  • Configuration
    • config/entp 대체, 적용 예정 (dotenv 사용)
  • Compression
    • 적용 예정 (compression 사용)
  • HTTP module
    • F9Http 대체, 적용 예정 (axios 사용)
  • HMR
    • 이슈가 있어 잠시 홀드, 추후 적용 필요할 듯
  • GraphQL
    • GraphQL 파트에서 설명

CLI

  • f9-cli 개발 예정이라 nest-cli 자체를 바로 사용하지 않을 예정이지만, f9-cli 개발을 위해 사용법은 알아둘 필요가 있음

현재 구현된 사항 중 알아둘 부분

  • Global path prefixwildcard 로 사용하여 @CurrentApp 구현
    • 이 처리는 initCurrentApp middleware 를 통해 처리함
  • @CurrentUser 처리시 ControllerResolver 가 각각 대응하는 방식이 다른데, 이를 통합하여 처리하도록 구현
    • 이 처리는 PublicAuthGuard guard 에서 하고 있음
  • 디렉토리 구조 / 파일명
    • 디렉토리 구조와 파일명은 별도의 파일에 기술할 예정 (복잡함;)
    • 파일명은 기본적으로 모두 name.something.ts 구조
      • module, options, controller, resolver, decorator, filter, middleware, guard, interceptor, entity, args, result, dto 등
  • 데이터 마이그레이션 스크립트 (from closedshops)
    • Webpack 의 entry 설정으로 scripts/migration/index.ts 에 기술
    • F9Migration Class 를 구현하여 Adapter Pattern 으로 정의함
  • 클라이언트 코드 트랜스포터 (to Angular)
    • Webpack 의 entry 설정으로 scripts/gentypes/index.ts 에 기술
    • 현재 몇가지 추가 대응해야 할 이슈가 있음
  • 모델별로 만들어야 하는 클래스들은 모두 f9 prefix 로 시작하는 상위 클래스를 상속받게 구현
    • F9BaseResolver
    • F9BaseDto
    • F9BaseListArgs
    • F9BaseMutationResult
    • F9BaseEntity
      • 여기에 가장 내용이 많은데 TypeORM 파트에서 설명

5. TypeORM

왜 ORM 인가?

  • 우리의 데이터는 구조화되어 있고, 앞으로 이 구조화 된 데이터를 정적 타입 으로 기술하여 type-safe 하게 사용할 예정
  • 또한 GraphQL 을 사용하면 어느 정도 정형화 된 스키마가 코드 상에 존재하는 것이 강제됨
  • ORM 도입을 꺼렸던 여러 이유들이 있지만, 모두 대응 가능하다고 판단
    • N+1 Problem
    • 복잡한 JOIN 으로 만들어진 쿼리
    • Cursor-based Pagination

왜 TypeORM 인가?

  • Node.js 기반의 ORM 은 종류가 많은데 가장 대표적인 모듈은 Sequelize
    • 기능은 가장 많고, 용례도 가장 많아서 가장 우선순위 도입 고려대상이었으나,
      • Typescript 의 Type-based 를 전혀 활용하지 못함
      • Decorator 패턴 그런거 모름
    • 그래서 FAIL
  • 최근 주목을 받고 있는 PrismaPrisma 2 - PhotonJS
    • Prisma 는 docker 가 기본임. 일단 여기서 탈락.
    • Prisma2 는 아주 설계가 잘 되어 있다는 느낌을 받았고 docker 도 빠져 있는데, 아직 너무 PREVIEW 단계.
    • 실제로 적용해보니 티져 상에서 제공하는 멋진 기능들 외에 꼭 필요한 기능들이 죄다 빠져있음.
  • 그래서, TypeORM
    • 필요로 하는 거의 모든 기능을 지원하고,
    • 대응이 안되는 케이스는 QueryBuilder 를 제공하여 raw 방식으로 처리 가능
    • Typescript + Decorator 패턴을 예쁘게 지원
    • Nest.js 문서상에 두번이나 등장할 정도로 매칭 좋음

Entity / Relations

  • 그냥 문서를 살짝 읽어보는 것만으로 이해에 어려움이 없음
    • 일반적인 ORM 정의서가 아니라 그냥 일반적인 클래스 정의서를 쓰듯이 씀 (@Decorator 를 통해 가능)
  • 세부적으로 알아야 할 사항,
    • 특별한 컬럼들
      • @PrimaryGeneratedColumn
      • @CreateDateColumn, @UpdateDateColumn
    • 컬럼 타입 지정
      • MySQL 에서 실제로 지정될 타입 지정
        • Primitive 인 경우 그냥 지정하면 됨
        • Enum 인 경우 처리 방식
      • 매개변수
        • length
        • default
        • nullable
        • unique, index 는 따로 Decorator 를 통해 지정하는 방식으로 통일
    • Relations
      • @OneToOne
        • 어느 쪽에 참조 필드를 놓을지가 중요
      • @ManyToOne, @OneToMany
        • 둘은 한쌍으로 움직이는데, 헷갈리지 않도록 주의
      • @ManyToMany
        • Join Table 에 추가 필드가 필요한 경우 이 지시자 대신 @ManyToOne 을 양쪽으로 걸어 씀

Query

  • 총 5가지 방식이 있음

  • Active Record and findOptions

    • QueryBuilder 를 사용하지 않을 때 (일반적인 쿼리일 때) 사용하는 findoptions
    • 매우 중요해서 이 문서에 있는 모든 옵션들에 대해 알고 있어야 함
  • Query Builder

    • findOptions 가 제공하지 않는 형태의 모든 쿼리는 이 방식으로 사용
    • 특히 GraphQL 과 결합되는 createList (f9-base-entity.ts) 가 이 방식이 아니면 안 됨
    • CodeIgniterQuery Builder 와는 맥락만 같고 사용하는 방식이 완전히 달라 제대로 쓰려면 많은 삽질이 필요ㅠ
  • Create / Update / Delete 쿼리 사용

    • Active Record 만으로 충분함 (아직까지는)

6. GraphQL

왜 GraphQL 인가?

  • GraphQL 은 뭐지?
  • RESTful? 하지도 않았지만... (ㅋㅋ)
    • GraphQL 도입 전, 우리는 RESTful 했나?
      • 아님, 우린 그냥 독자규격 JSON-RPC
    • 우리가 REST를 꺼려했던 부분은?
      • 우리 정도의 복잡도에도 GET/POST/PUT/PATCH/DELETE 5개의 동사로 표현 가능한 범위에 한계가 있었음
      • 요새는 Postman 같은 툴이 좋아져서 테스트가 그나마 좋아졌지만, 예전엔 GET/POST 만을 사용하는게 훨씬 유리했음
  • GraphQL 은 REST 를 대체할 수 있는 완벽한 대안
    • 모든 구조화 된 데이터를 type-safe 하게 관리함 (또 그래야 함)
    • 클라이언트에서 필요한 데이터만 딱 잘라 요청할 수 있음 (경제적 효과)
    • REST 에서 불만이었던 '동사'의 제한이 없음
    • 필요한 여러 요청을 한번에 보낼 수 있음 (프론트엔드에서의 효과)
      • 컴포넌트 베이스의 프론트엔드에서 전혀 예상 못한 효과
      • 필요한 데이터 때문에 다른 컴포넌트와 강하게 coupling 될 필요가 사라짐
      • 캐시 덕분에 단일 저장소(Single source of truth), 단방향 데이터 흐름(Uni-directional data flow) 이런거 다 불필요

GraphQL 구현체는?

  • Apollo
    • Nest.js 는 Apollo 를 지원함 (GraphQLModule (@nestjs/graphql) 구현 자체가 Apollo Server 기반, 정확히는 type-graphql + apollo-server)
    • Recipe 도 깨알같이 자세함
    • Apollo 는 Angular 를 지원함 (Apollo Client - Angular Docs)
  • Flutter 에서는 하나뿐인 구현체 확인 필요
    • 잘 되어 있기를ㅠ

알아야 할 GraphQL 용어

  • Query
    • 우리가 아는 그것
    • 데이터 변조 없이 데이터 내놔- 하는 요청
  • Mutation
    • Query 외의 거의 모든 것 (데이터를 변조함)
  • Subscription
    • 단순히 데이터를 쿼리하고, 변조하는 것이 아니라 지속적으로 데이터를 내려주는 경우 (e.g 채팅)
  • Type
    • 일종의 클래스 개념
    • 데이터의 구조와 타입(여기서의 타입은 동적-정적 할 때 그 타입)을 정의
  • Input
    • 일종의 DTO 개념
    • Mutation 처리시 전달받는 데이터 객체의 스키마로서 정의
  • Enum
    • Typescript 의 Enum 과 같은 개념이지만, GraphQL 쪽에 별도로 등록해주어야 함
  • Resolver
    • GraphQL Endpoint 로 Query/Mutation 요청이 들어왔을 때 이를 처리하는 핸들러 역할을 하는 코드

서버 구현

  • Schema First? / Code First?
    • Nest.js GraphQL Quick Start
    • Schema First
      • 타입 관련 스키마(SDL)를 먼저 생성하고 resolver 를 구현하는 방식
    • Code First
      • 타입 관련 스키마를 별도로 생성하지 않고, 바로 EntityDecorator 로 때려넣는 방식
      • 이걸 해주는 게 바로 type-graphql
      • 이 방식으로!
  • Type 생성
    • 그냥 엔티티에 아래 데코레이터들을 넣으면 끝.
    • 데코레이터
      • @ObjectType (Type)
      • @InputType (Input)
      • @ArgsType (스키마 아님)
      • @Field (Field of Type/Input)
  • Resolver
  • Resolver - TypeORM
    • 위에서 GraphQL 의 이점이 '필요한 필드만 요청할 수 있다'고 했는데, 그 요청을 받아다가 '필요한 필드만 응답'만 하는건 GraphQL 이 해줌
    • 다만 DB에서 가져올 때의 처리는 직접 해야함
      • 그걸 해주는 코드를 직접 구현함 F9BaseEntity 안에 있는 createList 함수
      • createList 함수는 resolver 에서 전달받은 @Info 데이터를 파싱하는데 resolveGqlInfo 함수 사용 (별도 구현, resolve-gql-info.ts)

클라이언트 구현

  • 위에서 링크한 Angular 에서의 Apollo 구현체 사용 (Apollo Client - Angular Docs)
    • 이 문서에 특별히 Angular 에만 있는 파트가 바로 Query, Mutation, Subscription services
    • DI 가능한 서비스로써 GraphQL 쿼리를 사용할 수 있음.
    • 이 방식으로 모델 단위 모듈에서 export 하고 필요한 쪽에 import 하면 다 갖다 쓸 수 있음
  • 아름다운 In-memory Cache 를 제공
    • 그래서 심지어 그 캐시 저장소에 로컬 데이터를 입력할 수도 있음 (Local state management)
    • 꺼내오는건 GraphQL-way, 똑같음
  • 순서 상관없이 아무렇게나 필요한거 막 요청해도 통합 처리
    • 실수로라도 같은 데이터를 두번 다시 받는 일은 없음
  • 이로써 ReduxScopedModel 도 없는 평화로운 프론트엔드! 는 아래 Angular 파트에서 계속

7. Angular

왜 Angular 인가?

  • 다른 대안은?

    • React
    • Vue
    • angularjs
  • Angular 만의 장점이라면?

    • Typescript
      • small-sized 에서 mid-sized 로 나아가는 우리 개발팀의 플랫폼 전환 목적에 Typescript 는 꼭 필요한 요소인데, Angular 외의 나머지 것들은 Typescript 적용에 따로 공수가 듦
    • 가장 잘 설계된 Template Syntax
      • 스트링/변수 바인딩 구분
      • Event binding
      • Attribute binding
      • Class binding
      • Style binding
    • 가장 잘 설계된 Native Component Interaction
      • @Input, @Output 지시자를 구분하여 별도로 관리하는 부분
      • 이걸 Template Syntax 에 가장 부드럽게 잘 녹아들게 표현
    • 우리는, 한때, angularjs
      • 이전에 만들어놓은걸 약간만 변형해서 그대로 쓸 수 있음
      • Template Syntax 문법도 가장 유사함 (당연한거지만ㅋㅋ)
      • Native 하게 제공하는 two-way binding (ngModel)
      • 기존과 같이 HTML/SCSS 코드를 별도의 파일로 사용 (JSX 대신에)
        • 하지만 기존처럼 완전히 다른 위치에 저장되는게 아니라 컴포넌트와 함께 사용 가능.
    • Nest.js 와 닮았다.
      • 닭이 먼저냐 달걀이 먼저냐ㅋㅋ
    • Native 하게 지원하는 SSR
      • React 는 next.js, Vue 는 nuxt.js 를 씀

    디렉토리 / 파일 구조

    angular.json

    • Angular 는 하나의 코드베이스 안에 여러개의 project 를 관리할 수 있음 (별도로 ng serve, ng build 하는 구조)
    • 따라서 설정 파일 역시 개별 project 마다 필요한데, 이 정보가 angular.json 에 담겨 있음
    • 알아야 할 부분
      • asset : 에셋 (주로 이미지)
      • styles : import 해야 할 SCSS 파일 별도 지정
      • polyfills : 구 버전의 브라우져 대응하는 코드 파일
      • aot : AOT-compile 여부 설정 (AOT Compiler)

    Routing

    • 기본적인 라우팅 설정은 크게 어렵지 않음 (문서)
    • 모듈 단위 Lazy Loading 이 가능함
      • 당분간 큰 필요 없으면 사용하지 않을 예정
    • 기존 레드데이즈의 URL 경로 fallback 처리 필요

    RxJs/Observables

    • Observables 는 Angular 에서 매우 중요한 개념이자, 매우 자주 사용되는 개념

      • 동작하는 방식과 사용하는 방식에 대해 계속해서 스터디가 필요할 듯 (나도ㅠ)
    • 기본적으로는 Promise 의 대체재라고 보면 되는데, 훨씬 더 잘 정리된 개념으로 보임 (다른 테크닉과 비교)

      • Observable 은 선언적입니다. Subscribe 하기 전까지는 연산이 시작되지 않아요. 반면 Promise 는 생성 즉시 실행 됩니다. 이 차이는 "당신이 결과를 필요로 할 때" 사용 가능한 레시피처럼 활용되기에 유용합니다.

      • Observable 은 여러 값들을 제공할 수 있습니다. 반면 Promise 는 하나밖에 제공할 수 없죠. 계속해서 복수의 값들을 받아야 할 때 Observable 이 잘 활용될 수 있습니다.

      • Observable 은 chainingsubscription 을 구분합니다. Promise 에는 오직 .then 뿐이죠. 그래서 Observable 은 복잡한 데이터 변환 레시피를 만드는데 유용합니다. 작업을 바로 수행하지 않은 상태에서요.

      • Observable 은 에러 처리를 subscribe() 에게 맡깁니다. Promise 는 에러를 자식 Promise 에게 넘기죠. 따라서 보다 중앙화 되고 예측가능한 에러 처리를 가능하게 합니다.

    • Async Pipe

      • 셋업된 Observable 을 반드시 코드 단에서 subscribe() 할 필요 없이 거기서 나올 데이터를 바로 뷰에 바인딩하는 것이 가능함. 그걸 가능하게 해주는 것이 Async Pipe, 아래와 같이 사용 가능.

          <div class="product" *ngFor="let product of products | async">
            {{ product.title }}
          </div>

    상태 관리

    • GraphQL replaces Redux
      • 우리는 ReduxScoped Model 같은 별도의 레이어/저장소 없이 컴포넌트 단위에서 직접적으로 데이터를 호출하여 사용하게 됨
        • GraphQL 의 In-memory Cache 가 우리의 단일 저장소(Single source of truth) 인 셈
        • 개별 컴포넌트가 필요한 정보는 모두 해당 컴포넌트가 직접 호출
        • 순전히 데이터의 필요에 의해 다른 컴포넌트와 coupling 되지 않음
      • 이를 Flux Architecture 의 개념을 빗대어 설명하면,
        • Reducer : 클라이언트가 안함, 서버의 Resolver가 함 (클라이언트에게 딱 맞는 데이터 제공)
        • Dispatch : GraphQL 의 Query/Mutation (심지어 문서도 만들어줌)
        • Action : GraphQL Schema
        • Store : Apollo GraphQL Client 의 In-memory Cache
      • Query 는 아예 신경 쓸 필요가 없고, Mutation 시에는 캐시 갱신에만 신경쓰면 됨
    • AJAX 콜 말고 다른 데이터의 상태는?
      • The Angular way 로 충분함.
      • 2~3 뎁스인 경우 계속해서 @Output 을 올려주는 방식으로 처리하고, 이보다 뎁스가 높은 경우 Local Cache 를 사용하는 방식을 고려할 수 있음
        • 현 시점에서 그래야 할 부분은 없음

    이전 코드를 Migration 할 때 고려사항