느릿늘있

[TIL] Naver FE News 2023-09 본문

개발공부

[TIL] Naver FE News 2023-09

JHKim93 2023. 10. 10. 19:31
[TIL] Naver FE News는 Naver FE 팀에서 매월 첫째주 수요일에 업로드하는 FE 관련 이슈들을 팔로우 하면서 관심있는 내용을 학습하고 정리하는 컨텐츠입니다. [ https://github.com/naver/fe-news ]

1. 성능하면 빠질 수 없는 메모이제이션, 네가 궁금해

https://d2.naver.com/helloworld/9223303

메모이제이션 소개

  • 메모이제이션은 함수 호출의 결과를 캐싱하고 요청 시 다시 불필요한 계산을 다시 하지 않고 캐싱된 결과를 반환하는 프로그래밍 기술이다.
  • React에서는 useCallback 또는 useMemo와 같은 메모이제이션 훅이 있습니다.
  • 하지만 메모이제이션은 특정한 값을 메모리에 저장하는 것이기 때문에 잘못 사용하면 메모리가 오히려 낭비될 수 있습니다.

함수형 프로그래밍과 메모이제이션

  • 함수형 프로그래밍의 5가지 특징
    1. 불변성 : 불변 데이터를 선호하며 원본 데이터를 수정하는 대신 복사본을 사용하여 새 데이터 구조를 만든다.
    2. 순수 함수 : 동일한 입력에 대해 동일한 출력을 생성한다. (+ no side effect)
    3. 고차 함수 : 다른 함수를 인수로 사용하거나 결과로 반환할 수 있다. (추상화, 재사용성)
    4. 재귀 : 종료 조건이 충족될 때까지 자신을 호출한다.
    5. 기능 구성 : 한 함수의 출력이 다음 함수의 입력이 되는 파이프라인을 구성할 수 있다.
  • 이 중에서 순수 함수의 특징으로 인해 함수형 프로그래밍에서 동일한 입력에 대해 미리 계산된 값을 반환하는 메모이제이션이 성능 향상을 야기하는 강력한 기술인 것이다.

함수형 프로그래밍 언어에서 메모이제이션 구현

  • 클로저, 고차 함수, 해시 테이블과 같은 데이터 구조를 통해 함수형 프로그래밍 언어에서 메모이제이션을 구현한다.

성능 테스트

  • jsperf를 활용한 피보나치 수열 메모이제이션 적용 결과 성능 테스트
  • 20까지 피보나치 수열을 수행한 결과 메모이제이션 사용 시 약 250배의 성능 향상을 확인하였다.

React에서의 메모이제이션 사용 (useMemo)

  • useEffect로 setInterval 1초를 주면 전체 코드가 1초마다 수행되며 선언 값이 (값의 변화와 상관없이) 계속 갱신된다.
  • useMemo를 사용하면 관련 값이 변경되었을 때만 갱신된다. (성능 향상)
  • 하지만 관련 값이 많아지는 경우, 의존성이 발생하고 관련 값들의 변화를 체크하기 위해 메모리를 더 사용하게 되고 가비지 컬렉팅을 방해하여 오히려 성능 저하가 발생할 수 있다.

메모이제이션이 필요한 경우

  • 비용이 많이 드는 계산
  • 자식 컴포넌트에 함수를 props로 넘길 때 (reRendering방지)
  • 다른 훅의 의존성에 사용될 때 (특히, useEffect의 의존성으로 콜백함수가 사용된 경우)

메모이제이션이 필요 없는 경우

  • 자주 다시 렌더링되는 컴포넌트 (props 값이 자주 변경되는 경우)
  • 작고 빠른 컴포넌트 또는 작업 (메모이제이션은 계산 비용이 큰 컴포넌트 또는 작업에 유용하다.)

불필요한 메모이제이션을 제거하는 원칙

  1. 컴포넌트가 자식을 랩핑할 때 JSX를 통해 래퍼 컴포넌트에서 state가 변경되어도 React에서 자식은 재렌더링될 필요가 없음을 인지한다.
  2. 로컬 state를 사용하고, state를 상위 컴포넌트와 공유하는 것을 지양한다.
  3. 렌더링 논리를 순수하게 유지한다. (컴포넌트 버그를 메모이제이션으로 해결하려 하지 마라)
  4. state를 업데이트하는 불필요한 Effect를 피한다.
  5. Effect의 불필요한 의존성을 제거한다.
    • 전체적으로 useEffect를 잘 못 사용하는 경우에 대해 경고한다.
    • 여기서는 객체와 객체 안의 값을 모두 의존성으로 넣지 말고 객체가 변하는 경우와 객체 안의 값이 변하는 경우의 로직을 분리하도록 권한다.
    • 변화에 '반응'하는 기능을 위해 의존성으로 추가를 많이 하는데 최신값을 읽는 것이 목적이라면 의존성을 추가하기 보다는 useRef나 외부 함수로 로직을 분리한다.
    • 의존성이 외부에 선언된 객체인 경우, 의존성을 반드시 추가해야하는 값만 추려내고 필요한 데이터들이 있다면 useEffect 내부에 선언하여 사용한다.

마치며

메모이제이션은 동일한 입력 값이 정기적으로 표시될 가능성이 높은 함수에 적합하다. 동일한 인수로 함수를 자주 호출하는 경우가 아니라면 캐시 적중이 드물고 인수 직렬화 및 비교로 인해 오히려 성능이 저하될 수 있다. 또한 캐시를 유지하면 이전의 모든 입력과 출력을 유지해야 하므로 메모리 사용량도 증가한다. 즉, 메모이제이션은 결코 공짜가 아니다. 최적화를 포함한 모든 연산에는 비용이 든다.

Optimizing speed on eBay.com

https://web.dev/shopping-for-speed-on-ebay/

 

Shopping for speed on eBay.com

This case study explains how eBay increased key business metrics by optimizing the performance of their web and app experiences.

web.dev

Intro

  • 웹페이지 속도는 eBay에서 2019년부터 전사적인 과제로 부각되었다.
  • 통상적으로 100ms의 로딩 속도 개선이 0.5%의 "장바구니에 추가" 클릭 수 증가를 만들어냈다.

웹 성능개선 "cuts(절단)"

  • eBay가 성능 향상을 위해 처음으로 수행한 것은 가능한 모든 개체들의 사이즈와 시간을 cuts하는 것이었습니다.
  • 아래에 eBay에서 경험한 cut들을 소개합니다.

1. 모든 텍스트 리소스의 낭비된 페이로드를 줄이기

  • 사이트를 더 빠르게 만드는 단순한 방법은 코드량을 줄이는 것이다.
  • eBay는 사용되지 않고 불필요하게 남아있는 JavaScript, CSS, HTML 및 JSON 코드들을 정리했습니다.
  • 이러한 불필요한 코드 잔여물들은 시간이 지남에 따라 누적되어 성능 병목 현상을 야기합니다.
  • 여기서 cut은 낭비되는 Byte에 대한 것입니다.

2. above-the-fold content에 대한 주요 경로 최적화

* fold : 브라우저가 끝나는 부분
* above-the-fold : 스크롤하지 않아도 브라우저에 보이는 부분
* below-the-fold : 스크롤하면 볼 수 있는 브라우저 하단에 숨겨진 부분
  • above-the-fold의 영역은 below-the-fold의 영역보다 훨씬 중요하다.
  • eBay의 FE 아키텍쳐에는 Experience Services라는 영역이 존재합니다. ES로 요청이 들어오면 above-the-fold 영역의 데이터만 따로 먼저 처리하고 즉시 응답합니다. 그러고나서 below-the-fold 영역의 데이터를 병렬로 수행하고 later chunk 또는 lazy-load로 처리합니다.
  • 여기서 cut은 서비스가 관련 콘텐츠를 표시하는 데 소요되는 시간입니다.

3. 이미지 최적화

  1. JPEG, PNG, GIF를 대체하는 저용량의 WebP 사용
  2. 이미지 업로드 도구 최적화 규칙 정해서 사용하기 (enforces the rules)
  • 여기서 cut은 유저에게 보내지는 낭비된 이미지 Byte에 대한 것입니다.

[참고] https://web.dev/serve-images-webp/

 

WebP 이미지 사용

WebP 이미지는 JPEG 및 PNG 이미지보다 작습니다. 일반적으로 파일 크기가 25~35% 감소합니다. 이렇게 하면 페이지 크기가 줄어들고 성능은 향상됩니다.

web.dev

4. 정적 자료들의 예측 prefetch

  • 유저의 페이지 이동은 어느 정도 예측 가능하다.
  • 그 예측 가능한 동선을 따라 정적 자료들을 미리 준비하는 것을 예측 prefetch라고 한다.
  • 예측한 페이지로 유저가 이동한 경우 유저는 미리 캐싱되어있던 정적 자료들을 보게 된다.
  • 그런데 사실 한 번 접근한 페이지는 자동으로 브라우저에 캐싱이 되기 때문에 캐시가 지워졌거나 최초 방문하는 페이지에 대해서만 의미가 있다.
  • 여기서의 cut은 최초 접근 시 발생하는 CSS와 JS의 정적 자료의 네트워크 시간에 관한 것입니다.

5. 상위 검색 결과 prefetch

  • eBay에서는 사용자가 검색을 할 때, 상위 10개 항목으로 이동할 가능성이 매우 높다는 사실을 발견했다.
  • 검색 결과의 prefetch는 두 가지 레벨에서 발생한다.
    1. server-side cache
    2. client-side cache
  • 이에 대한 자세한 설명은 https://www.youtube.com/watch?v=ogEhUnQdQiU&t=984s 영상을 참고
  • 여기서의 cut은 캐싱을 통한 서버 처리와 네트워크 시간에 관한 것입니다.

6. 검색 이미지를 적극적으로 다운로드

  • eBay 검색의 두 단계
    1. 검색어와 관련도 높은 아이템들 반환
    2. 유저 컨텍스트 고려, 가중치 분석 후 결과 반환
  • 위 결과로 반환된 상위 10개 항목에 대한 이미지 다운로드를 전역적으로 즉시 실행
  • 여기서 cut은 검색 결과에 대한 이미지 다운로드 시작 시점에 관한 것입니다.

7. 자동 추천 데이터를 위한 엣지 캐싱

  • 사용자가 검색창에 문자를 입력하면 추천 단어들이 자동으로 제안된다.
  • 이러한 단어 추천은 CDN에 캐싱되어 이상적인 제안으로 유지되는 시간만큼(최대 24시간) 동안 동일하게 제안된다.
  • 단점으로는 개인화된 제안을 고려하기 어렵다는 점이 있지만 eBay에서는 대기 시간의 이점이 더 크다고 판단했다.
  • 여기서 cut은 자동 추천에 대한 네트워크 대기 시간 및 서버 처리 시간입니다.

8. 인식할 수 없는 사용자에 대한 엣지 캐싱

  • 인식할 수 없는 사용자(비로그인 유저, 최초 접속자)에 대해서는 어차피 개인화된 페이지를 제공할 수 없다.
  • 따라서, eBay에서는 이러한 사용자들에게 멀리 있는 데이터 센터가 아닌 엣지에 캐싱된 홈페이지를 제공한다.
  • 여기서 cut은 마찬가지로 인식할 수 없는 사용자에 대한 네트워크 대기 시간 및 서버 처리 시간입니다.

마치며

eBay의 성능 최적화는 장기간에 걸쳐 몇십 milliseconds 씩 아주 천천히 개선되어 왔습니다. (단기간에 할 수 있는 일이 아니다.) 성능 최적화는 다른 기업들과의 경쟁에서 우위를 점할 수 있는 중요한 요소이다. eBay에서 시도한 다른 모든 cuts들을 보고 싶다면 아래 링크를 방문해라.
https://innovation.ebayinc.com/tech/engineering/speed-by-a-thousand-cuts/

Decoupling UI and Logic in React: A Clean Code Approach with Headless Components

https://itnext.io/decoupling-ui-and-logic-in-react-a-clean-code-approach-with-headless-components-82e46b5820c

 

Decoupling UI and Logic in React: A Clean Code Approach with Headless Components

In the realm of front-end development, terms and paradigms can sometimes be mystifying, and ‘headless UI’ or ‘headless components’ may very…

itnext.io

Intro

  • Headless Component라는 말은 많이 들어봤을 것이다.
  • 하지만 이 용어의 뜻은 FE 씬에서 상당히 난해하게 사용되고 있다.
  • Headless Component는 다음과 같은 특징을 갖는다.
    1. 유연성
    2. 재사용 가능성
    3. 클린코드

A Toggle Component Example

  • 이 글에서 useToggle이라는 훅을 만드는 예제를 보여주는데 자세한 내용은 본문을 참조하기 바랍니다.
  • 토글 버튼을 개별적으로 만들 수 있지만 아래와 같이 커스텀 훅으로 재사용 가능하게 만들 수도 있다.
const useToggle = (init = false) => {
  const [state, setState] = useState(init);
  
  const toggle = useCallback(() => {
    setState((prevState) => !prevState);
  }, []);

  return [state, toggle];
};
  • 이렇게 하면 State를 관리하는 로직에서 발생하는 오류를 쉽게 발견하고 통제할 수 있다.

The Headless Component

  • 이러한 방식으로 행위(state management)와 시각적 요소를 분리하는 패턴을 많은 라이브러리들에서 사용하고 있다.
  • 그 중 가장 대표적인 라이브러리인 Downshift를 소개한다.
  const {
    isOpen,
    selectedItem,
    getToggleButtonProps,
    getLabelProps,
    getMenuProps,
    highlightedIndex,
    getItemProps,
  } = useSelect({items: states});
  • Downshift는 위와 같은 방식으로 쉽게 Headless UI를 생성할 수 있도록 다양한 훅들을 제공한다.

한 걸음 더 나아가기

  • 이처럼 행위와 UI를 분리하기 위해서 우리는 점진적으로 계층화된 구조를 만들어야 한다.

  • JSX Fragment : 최상위 계층, 전달된 props에 대한 UI 구성을 책임진다.
  • Headless Component : 중간 계층, 행위를 유지하고 상태를 관리하며 JSX와 상호작용할 인터페이스를 생성한다.
  • Data Model : 기본 계층, 도메인별 데이터 관리와 비즈니스 로직을 관리하는 책임을 갖는다.

균형잡힌 시각(Headless UI의 장단점)

  • 장점
    1. 재사용성
    2. logic과 UI의 분리를 통한 코드 간소화
    3. 유연성
    4. 테스트 가능성 : logic이 분리되기 때문에 테스트가 쉬워진다.
  • 단점
    1. 초기 오버헤드 : 간단하거나 재사용이 굳이 필요 없는 곳에 적용하면 복잡성이 오히려 증가한다.
    2. 러닝 커브
    3. 남용 가능성
    4. 잠재적 성능 문제 : 렌더링 관련 성능 이슈가 있을 수 있다.
  • 결론 : 좋다고 무작정 쓰지 말고 상황에 따라 잘 판단해서 효율적으로 써라.

10 essential VS Code tips & tricks for greater productivity

Intro

  • 전 세계 개발자의 73%가 VSCode를 코드 에디터로 사용한다.

1. Timeline view: local source control

  • built-in source control을 제공한다.

2. Autosave: no more Ctrl + S

3. Do anything with Command Palette

  • 대표적으로 파일 관련 명령, 탐색 명령, 편집 명령 및 터미널 명령이 있다.
  • Windows/Linux : ctrl + shift + p
  • Mac : shift + command + p

4. Go to file quickly

  • 파일 검색 기능 : ctrl + p
  • ctrl + tab으로 열려있는 탭 이동도 가능
    • alt + 좌우 방향키로 이동도 가능

5. Go to line quickly

  • ctrl + g, 번호 입력

6. Delete line quickly

  • ctrl + shift + k

7. Enjoy typing with smooth cursor

  • Command Palette로 Settings UI 파일을 열고 smooth caret을 검색한다.
  • Editor: Cursor Smooth Caret Animation setting로 이동 후 아래 3가지 옵션 중 on을 선택한다.
    • off / explicit(커서를 명시적(?)으로 배치할 때만 동작) / on

8. Format code rapidly

  • Settings에서 Editor: Format On Save를 체크한다.
  • 수동으로 적용하는 방법
    • Windows : shift + alt + f
    • Mac : shift + Option + f
    • Linux : ctrl + shift + i

9. Save time with multi-cursor editing

  • 멀티 커서 생성 방법
    1. alt + click
    2. ctrl + alt + 상하 방향키

10. Create new folder / file quickly

  • Explorer panel을 더블클릭하면 새 파일을 만들 수 있다.
  • "폴더명/파일명"과 같은 방식으로 없는 폴더도 생성할 수 있다.

유용한 도구들

TS Reset

https://github.com/total-typescript/ts-reset

 

GitHub - total-typescript/ts-reset: A 'CSS reset' for TypeScript, improving types for common JavaScript API's

A 'CSS reset' for TypeScript, improving types for common JavaScript API's - GitHub - total-typescript/ts-reset: A 'CSS reset' for TypeScript, improving types for common JavaScri...

github.com

  • Typescript의 기본 타입을 교정해 주는 라이브러리 (like CSS reset)
    • fetch 함수의 .json()과 JSON.parse()가 any가 아닌 unknown을 반환
    • .filter(Boolean)가 undefined를 걸러줌
    • array.includes()가 readonly 배열에서 동작이 좀 더 유연해짐
    • 등등 여러 기능 (https://www.totaltypescript.com/ts-reset)

JS Visualizer 9000

https://www.jsv9000.app/

 

JS Visualizer 9000

 

www.jsv9000.app

  • 자바스크립트의 동작을 시각화해주는 사이트
  • 학습에 주로 쓰이고 디버깅에도 가끔 쓰일듯?

Regulex

https://jex.im/regulex/

 

Regulex:JavaScript Regular Expression Visualizer

 

jex.im

  • 정규 표현식 시각화 해주는 사이트
  • 시각적으로 예쁘지는 않은 것 같음;; 시각화가 꼭 필요할 때나 쓸 듯

React Timer Hook

https://www.npmjs.com/package/react-timer-hook

 

react-timer-hook

React timer hook is a custom react hook built to handle timers(countdown), stopwatch and time logic/state in your react component.. Latest version: 3.0.7, last published: 3 months ago. Start using react-timer-hook in your project by running `npm i react-ti

www.npmjs.com

  • 리엑트에서 스톱워치, 타이머, 시계가 필요할 때는 react-timer-hook을 써보자!