# 2021.02

# 2/1

# Rehydration

  • SSR(= 유니버셜렌더링): 클라이언트 렌더링과 서버 렌더링 간의 절충을 원활하게!
    • 네비게이션 요청(전체페이지 로드/리로드)은 서버에서 선처리해 빠른 First Contentful Paint를 보여주고 rehydration이란 기술을 사용해 js로 동작가능하게 만듦 (근데 빠르게 보여도 동작하기까지 시간이 걸려서 사람들이 화날 수 있음)
  • 개선법
    • 스트리밍 서버 렌더링: 브라우저가 받은대로 점진적 렌더링가능한 청크로 HTML보내기. 리액트의 renderToNodeString(이는 동기인 renderToStream보다 빠름)
    • 점진적 Rehydration: 시간이 지남에 따라 '부팅'됨. 페이지에서 우서눈위가 낮은 클라측 업글을 지연.

# 2/6

# NextJS, GatsbyJS

https://shylog.com/which-is-better-nextjs-or-gatsbyjs/

  1. 니즈
  • 리액트 쓰면서 SEO 어케하지?
  • cra써도 프로젝트 스캐폴딩 시간 걸린다
  • CSR이 초기렌더링 측면에서 별로라는데 어떻게 개선하지?
  • 블로그를 서버 없이 쉽게 만들기?
  1. 장단점
  • 장점: SEO, 다양한 case 미리 만들어놔서 서비스개발 자체에 집중가능
  • 단점: 블랙박스가 생김. Next.js에서 hydration이전상태 컨트롤이나, 빌드시 Window객체 사용에 제약 등
  1. 개츠비
    1. SSG형태 페이지 구성에 최적화. 플러그인 사용가능(CMS, PWA, GA 등)
    2. 페이지가 많아질수록 빌드가 오래걸림.
  2. Next.js
    1. SSG, SSR 모두 제공. 매번 빌드하는걸 피하고 싶다면 SSR을 통해 render하는게 좋을수도.

# 성공적인 면접의 90%는 준비에서 나온다

https://johngrib.github.io/wiki/better-interview/

  1. 가치있는 면접 질문이란: 1. 개인 역량? 2. 업무수행 능력이 있는가?
    1. 이 외에 퀴즈나 퍼즐은 개인역량/업무능력을 보여주지 않음. "왜?"라고 물어보지 않는다면 말이다. 위 2개가 보여질 때까지 '왜' 라 물어봐야 한다.
  2. 좋은 질문 만들기
    1. 최근 18개월동안 팀이 겪은 실전 문제 몇개를 꼽기. 각 문제에서 핵심 개념을 뽑아 첫 질문으로 던지기. 지원자가 자신감을 얻으면 난이도를 조금씩 높이기.
    2. 계속 질문을 던져 지원자가 자신이 잘 모르는 문제에 대응하는 방식을 살피기.
    3. 답 하나만을 고집하지 않기 <- 중요한듯
    4. 장점: 면접관도 즐겁고, 지원자도 실제로 중요한 문제를 경험하고 인터넷에서 공유받을수도 없다.

# 2/8

# CORS

https://evan-moon.github.io/2020/05/21/about-cors/

  1. 웹은 언제 리소스를 공유할 수 있는가?
    1. SOP(Same Origin Policy): 같은 출처에서만 리소스 공유가능
    2. 같은 출처가 아니더라도 CORS(Cross Origin Resource Sharing) 정책을 지켰다면 리소스 공유가능
    3. 출처가 같다는건?: 스킴(https://), 호스트(milooy.github.io), 포트(:80)가 동일. 브라우저에서 판단한다. 서버가 정상적으로 응답하더라도 브라우저에서 버림.
  2. CORS
    1. 브라우저에서 서버로 요청 보낼때 Origin에 요청을 보내는 출처를 함께 담아보냄
    2. 그럼 서버가 응답할 때 Access-Control-Allow-Origin이란 값에 이 리소스를 접근하는게 허용된 출처를 내려줌.
    3. 브라우저가 응답받을 때 요청보낸 Origin과 서버의 허용출처 비교하고 유효검사.
  3. CORS의 세 가지 시나리오
    1. Preflight Request: OPTION 으로 브라우저에서 서버 미리 찔러보기. 여기서 200나오면 그제서야 본요청 보냄.
    2. Simple Request: 예비요청 안보내고 본요청 때리기. 까다로운 조건 하에 가능.
    3. Credential Request: 요청 자체를 인증해서.
  4. CORS 해결법
    1. 정석: 서버에서 Access-Control-Allow-Origin에 허용출처 명시. *로 하면 모두 허용이지만 보안뚝떨.
    2. Webpack dev server로 리버스프록싱: 서버에서 허용출처에 localhost:3000을 넣기 좀 그렇다면, 웹팩 프록시로 내 로컬에서 보낸 요청이 마치 https://milooy.github.io 에서 보낸것처럼 우회한다.

# 2/12-2/13

# How we built the GitHub globe

https://github.blog/2020-12-21-how-we-built-the-github-globe/ https://github.com/home

  1. 왜만들었냐
    1. 세계가 PR로 연결된다는걸 시각화하고싶었다. 실제로 누를 수 있게 해서 더 immersive한 경험 줌. 당장 예쁘기만 한게 아니고, 모든 디바이스에서 스무스하게 동작하도록 개발.
  2. 지구는 WebGL로 만듦
    1. three.js의 WebGL컨텍스트 사용.
    2. PR들의 lat, lng계산해서 globe에 그려주기.
    3. 처음 진입하면 내 위치 기준으로 보여준다. 위치 수집하는게 아니고 device의 timezone기반으로 계산 <- 똑똑한데? 정확할 필요 없으면 이렇게 해도 무방할것같다.
    4. 풀리퀘스트의 arc그리는건 가까울수록 느리게 보여주고, ease애니메이션도 넣음.
  3. 성능최적화
    1. 느린 폰을 위해 antialise를 포기함. halo effect를 넣어 까득이지 않고 스무스하게 보이도록 개선.
    2. 그라디언트만 있는 지구 SVG를 먼저 로드(placeholder). 그리고 비쥬얼라이제이션이 ready되면 canvas로 갈아끼고 keyframe 애니메이션으로 스무스하게 커지도록.
    3. 퀄리티를 유지하면서 최대한 FPS 낮춘거: 55.5FPS

# 2/14

# Visualizing GitHub’s global community

https://github.blog/2020-12-21-visualizing-githubs-global-community/

  1. 데이터 골
    1. 걍 지구 애니메이션이 아닌, Live하고 engaging하는 데이터를 보여주고 싶었다.
    2. 문제: 어케 거대한 데이터에서 쿼리해오지? 그중 젤 흥미로운 데이터는 어케 뽑지? 유저 프라이버시 존중하면서 그들의 위치 받아오는방법? 깃헙 뿌시면 안되는데?
  2. 쿼리하기
    1. 프로덕션 db 바로 쿼리하면 너무 느릴거다. 일정한 스케쥴로 싱크되는 데이터 웨어하우스가 있는데 그거 쓰자. 아파치 카프카 event stream에서 Presto로 뽑아옴. PR이 머지될때마다 리포트되는 이벤트가 있음.
  3. 흥미로운 데이터 뽑기
    1. 데이터 웨어하우스에 저장소의 health도 랭크매겨놨다. current activity가 많은것 기반으로.
  4. 유저 위치받아오기.
    1. GitHub프로필에 옵셔널 필드로 있긴 하지만 막쓰는 사람도 많고 안쓴사람이 대다수. 그래도 쓴사람들 데이터는 읽고 알아내서 거기 기반으로 보여준다.

# 2/19

# 버려야 할 나쁜 TS습관

  1. strict모드를 사용x

  2. || 대신 ??쓰삼 (모든 falsy값이 아닌 null/undefined만 쳌)

  3. any쓰지마삼 굳이 써야한다면 unknown

  4. 자동추론 못하는 코드에 as쓰지마삼(products as Product[]). 타입가드로 대체.

    // bad
    async function loadProducts(): Promise<Product[]> {
       const response = await fetch(Foo);
       const products: unknown = await response.json();
       return products as Product[];
    }
    
    // good
    async function loadProducts(): Promise<Product[]> {
       const response = await fetch(Foo)
       const products: unknown = await response.json()
       if (!isArrayOfProducts(products)) {
          throw new TypeError('API 응답 타입이 다릅니다!')
       }
       return products
    }
    
  5. 테스트 짤 때 as any로 퉁치기. 모킹 로직을 목하는곳으로 이동시켜서 타입추론 되도록.

  6. 서로 다른 타입을 퉁쳐서 프로퍼티를 옵셔널하게 만듦

    // bad
    interface Food {
      name: string;
      type: "my" | "your";
      myName?: string;
      yourName?: string;
    }
    
    // good
    interface Food {
      name: string;
      type: "my" | "your";
    }
    interface MyFood extends Food {
      type: "my";
      myName: string;
    }
    interface YourFood extends Food {
      type: "your";
      yourName: string;
    }
    
  7. 제네릭을 T로 써버리기. 온전히 설명가능한 이름을 줘라.

    // bad
    function head<T>(arr: T[]): T | undefined {
      return arr[0];
    }
    
    // good
    function head<Element>(arr: Element[]): Element | undefined {
      return arr[0];
    }
    
  8. 불린이 아닌걸 불린검사함.

    // bad
    if (messageCount)
    
    // good
    if (messageCount !== undefined)
    
  9. 불린이 아닌걸 불린으로 변환

    // bad
    if (!!messageCount)
    
    // good
    if (messageCount !== undefined)
    
  10. !=null. 명시적으로 검사하삼 !== null이든 ===undefined

# 2/23

# Before you memo()

https://overreacted.io/before-you-memo/

  1. 리액트에서 상태 업데이트가 느리다면?: production빌드인지 확인 / 상태가 트리에서 불필요하게 높이 있지 않는지 / React Devtools Profiler로 리렌더링되는 부분 확인 후 가장 비싼 하위트리를 memo()로 감쌈 + 필요한곳에 useMemo
    1. 마지막 단계는 성가심... 글구 장기적으론 개발자 말고 컴파일러가 해결해주면 더 좋을것임...
  2. 메모사용하지 않고 성능개선하기
    1. 상태를 아래로 내려서 필요한부분만 리렌더링되도록
    // before: color가 바뀔때마다 ExpensiveTree도 함께 바뀜
    function App() {
       let [color, setColor] = useState('red');
       return (
          <div>
             <input value={color}/>
             <p>{color}</p>
             <ExpensiveTree />
          </div>
       )
    }
    // after: color는 ColorForm컴포넌트에서 알아서 지지고 볶음. ExpensiveTree는 리렌더x
    function App() {
       return (
          <div>
             <ColorForm>
             <ExpensiveTree />
          </div>
       )
    }
    
    1. 내용물을 끌어올리기 (상태가 ExpensiveTree상위에 있어서 1번처럼 간단히 분리불가능할때)
    function App() {
      return (
        <ColorPicker>
          <ExpensiveTree />
        </ColorPicker>
      );
    }
    function ColorPicker({ children }) {
      let [color, setColor] = useState("red");
      return (
        <div style={{ color }}>
          <input value={color} />
          <p>{color}</p>
          {children}
        </div>
      );
    }
    
  3. 위 접근법들은 성능향상이라기보단 컴포넌트를 잘 쪼개서 데이터 흐름을 쉽게 따라가는 개선임. 성능은 따라오는거임. 일단 이렇게 구조변경을 하고 그 다음에 memo를 생각해라. 이렇게 상태를 잘 쪼개면 나중에 서버컴포넌트가 나올때 children을 서버로부터 받을수도 있잖냐?