# 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/
- 니즈
- 리액트 쓰면서 SEO 어케하지?
- cra써도 프로젝트 스캐폴딩 시간 걸린다
- CSR이 초기렌더링 측면에서 별로라는데 어떻게 개선하지?
- 블로그를 서버 없이 쉽게 만들기?
- 장단점
- 장점: SEO, 다양한 case 미리 만들어놔서 서비스개발 자체에 집중가능
- 단점: 블랙박스가 생김. Next.js에서 hydration이전상태 컨트롤이나, 빌드시 Window객체 사용에 제약 등
- 개츠비
- SSG형태 페이지 구성에 최적화. 플러그인 사용가능(CMS, PWA, GA 등)
- 페이지가 많아질수록 빌드가 오래걸림.
- Next.js
- SSG, SSR 모두 제공. 매번 빌드하는걸 피하고 싶다면 SSR을 통해 render하는게 좋을수도.
# 성공적인 면접의 90%는 준비에서 나온다
https://johngrib.github.io/wiki/better-interview/
- 가치있는 면접 질문이란: 1. 개인 역량? 2. 업무수행 능력이 있는가?
- 이 외에 퀴즈나 퍼즐은 개인역량/업무능력을 보여주지 않음. "왜?"라고 물어보지 않는다면 말이다. 위 2개가 보여질 때까지 '왜' 라 물어봐야 한다.
- 좋은 질문 만들기
- 최근 18개월동안 팀이 겪은 실전 문제 몇개를 꼽기. 각 문제에서 핵심 개념을 뽑아 첫 질문으로 던지기. 지원자가 자신감을 얻으면 난이도를 조금씩 높이기.
- 계속 질문을 던져 지원자가 자신이 잘 모르는 문제에 대응하는 방식을 살피기.
- 답 하나만을 고집하지 않기 <- 중요한듯
- 장점: 면접관도 즐겁고, 지원자도 실제로 중요한 문제를 경험하고 인터넷에서 공유받을수도 없다.
# 2/8
# CORS
https://evan-moon.github.io/2020/05/21/about-cors/
- 웹은 언제 리소스를 공유할 수 있는가?
- SOP(Same Origin Policy): 같은 출처에서만 리소스 공유가능
- 같은 출처가 아니더라도 CORS(Cross Origin Resource Sharing) 정책을 지켰다면 리소스 공유가능
- 출처가 같다는건?: 스킴(https://), 호스트(milooy.github.io), 포트(:80)가 동일. 브라우저에서 판단한다. 서버가 정상적으로 응답하더라도 브라우저에서 버림.
- CORS
- 브라우저에서 서버로 요청 보낼때 Origin에 요청을 보내는 출처를 함께 담아보냄
- 그럼 서버가 응답할 때 Access-Control-Allow-Origin이란 값에 이 리소스를 접근하는게 허용된 출처를 내려줌.
- 브라우저가 응답받을 때 요청보낸 Origin과 서버의 허용출처 비교하고 유효검사.
- CORS의 세 가지 시나리오
- Preflight Request: OPTION 으로 브라우저에서 서버 미리 찔러보기. 여기서 200나오면 그제서야 본요청 보냄.
- Simple Request: 예비요청 안보내고 본요청 때리기. 까다로운 조건 하에 가능.
- Credential Request: 요청 자체를 인증해서.
- CORS 해결법
- 정석: 서버에서 Access-Control-Allow-Origin에 허용출처 명시. *로 하면 모두 허용이지만 보안뚝떨.
- 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
- 왜만들었냐
- 세계가 PR로 연결된다는걸 시각화하고싶었다. 실제로 누를 수 있게 해서 더 immersive한 경험 줌. 당장 예쁘기만 한게 아니고, 모든 디바이스에서 스무스하게 동작하도록 개발.
- 지구는 WebGL로 만듦
- three.js의 WebGL컨텍스트 사용.
- PR들의 lat, lng계산해서 globe에 그려주기.
- 처음 진입하면 내 위치 기준으로 보여준다. 위치 수집하는게 아니고 device의 timezone기반으로 계산 <- 똑똑한데? 정확할 필요 없으면 이렇게 해도 무방할것같다.
- 풀리퀘스트의 arc그리는건 가까울수록 느리게 보여주고, ease애니메이션도 넣음.
- 성능최적화
- 느린 폰을 위해 antialise를 포기함. halo effect를 넣어 까득이지 않고 스무스하게 보이도록 개선.
- 그라디언트만 있는 지구 SVG를 먼저 로드(placeholder). 그리고 비쥬얼라이제이션이 ready되면 canvas로 갈아끼고 keyframe 애니메이션으로 스무스하게 커지도록.
- 퀄리티를 유지하면서 최대한 FPS 낮춘거: 55.5FPS
# 2/14
# Visualizing GitHub’s global community
https://github.blog/2020-12-21-visualizing-githubs-global-community/
- 데이터 골
- 걍 지구 애니메이션이 아닌, Live하고 engaging하는 데이터를 보여주고 싶었다.
- 문제: 어케 거대한 데이터에서 쿼리해오지? 그중 젤 흥미로운 데이터는 어케 뽑지? 유저 프라이버시 존중하면서 그들의 위치 받아오는방법? 깃헙 뿌시면 안되는데?
- 쿼리하기
- 프로덕션 db 바로 쿼리하면 너무 느릴거다. 일정한 스케쥴로 싱크되는 데이터 웨어하우스가 있는데 그거 쓰자. 아파치 카프카 event stream에서 Presto로 뽑아옴. PR이 머지될때마다 리포트되는 이벤트가 있음.
- 흥미로운 데이터 뽑기
- 데이터 웨어하우스에 저장소의 health도 랭크매겨놨다. current activity가 많은것 기반으로.
- 유저 위치받아오기.
- GitHub프로필에 옵셔널 필드로 있긴 하지만 막쓰는 사람도 많고 안쓴사람이 대다수. 그래도 쓴사람들 데이터는 읽고 알아내서 거기 기반으로 보여준다.
# 2/19
# 버려야 할 나쁜 TS습관
strict모드를 사용x
|| 대신 ??쓰삼 (모든 falsy값이 아닌 null/undefined만 쳌)
any쓰지마삼 굳이 써야한다면 unknown
자동추론 못하는 코드에 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 }
테스트 짤 때 as any로 퉁치기. 모킹 로직을 목하는곳으로 이동시켜서 타입추론 되도록.
서로 다른 타입을 퉁쳐서 프로퍼티를 옵셔널하게 만듦
// 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; }
제네릭을 T로 써버리기. 온전히 설명가능한 이름을 줘라.
// bad function head<T>(arr: T[]): T | undefined { return arr[0]; } // good function head<Element>(arr: Element[]): Element | undefined { return arr[0]; }
불린이 아닌걸 불린검사함.
// bad if (messageCount) // good if (messageCount !== undefined)
불린이 아닌걸 불린으로 변환
// bad if (!!messageCount) // good if (messageCount !== undefined)
!=null
. 명시적으로 검사하삼!== null
이든===undefined
든
# 2/23
# Before you memo()
https://overreacted.io/before-you-memo/
- 리액트에서 상태 업데이트가 느리다면?: production빌드인지 확인 / 상태가 트리에서 불필요하게 높이 있지 않는지 / React Devtools Profiler로 리렌더링되는 부분 확인 후 가장 비싼 하위트리를 memo()로 감쌈 + 필요한곳에 useMemo
- 마지막 단계는 성가심... 글구 장기적으론 개발자 말고 컴파일러가 해결해주면 더 좋을것임...
- 메모사용하지 않고 성능개선하기
- 상태를 아래로 내려서 필요한부분만 리렌더링되도록
// 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> ) }
- 내용물을 끌어올리기 (상태가 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> ); }
- 위 접근법들은 성능향상이라기보단 컴포넌트를 잘 쪼개서 데이터 흐름을 쉽게 따라가는 개선임. 성능은 따라오는거임. 일단 이렇게 구조변경을 하고 그 다음에 memo를 생각해라. 이렇게 상태를 잘 쪼개면 나중에 서버컴포넌트가 나올때 children을 서버로부터 받을수도 있잖냐?