[5팀 여찬규] Chapter 4-2 코드 관점의 성능 최적화#23
Open
chan9yu wants to merge 18 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
과제 체크포인트
배포 링크
과제 요구사항
Promise.all이해)과제 셀프회고
기술적 성장
Promise.all
과제를 진행하면서
Promise.all사용법에서 잘못된 부분을 발견했습니다. 배열 안에서 await를 사용하면 순차 실행되는데, Promise 객체 자체를 넘겨야 병렬 처리가 된다는 점을 참고해서 수정했습니다.React.memo
React.memo를 효과적으로 사용하는 방법도 배울 수 있었는데 부모 컴포넌트에서 객체나 함수를 직접 생성해서 props로 전달하면 memo로 감싸도 의미가 없다는 점이 제일 중요한 것 같습니다.
useMemo와 useCallback으로 참조를 안정화하거나, 복잡한 객체 대신 원시값들을 개별적으로 전달하는 방식으로 작업을 진행했습니다.
Chakra UI 컴포넌트 VS JSX Element
Chakra UI 컴포넌트와 HTML 요소 간의 성능 차이가 제일 의외의 최적화 작업이였던거 같아요.. 대량 데이터 렌더링에서 Chakra UI의 Tr, Td 컴포넌트를 순수 HTML tr, td로 바꾸는 것만으로도 80%? 정도의 성능 개선이 되었습니다.
UI 라이브러리 컴포넌트들이 매번 theme 계산, props 처리, hooks 실행 등의 오버헤드를 가진다는 걸 알 수 있었습니다. 특히 100개 행에서 각 행마다 8개의 컴포넌트가 있으니 총 800번의 함수 호출이 HTML 요소로는 단순한 DOM 요소 생성으로 바뀌는 차이가 컸습니다.
Context Provider 범위 축소하기
제일 중요했던 DND에서는 Context Provider의 위치가 제일 중요한 부분이었습니다.
ScheduleDndProvider를 App 레벨에서 각 테이블 레벨로 이동시키니 한 테이블의 DnD가 다른 테이블에 영향을 주지 않게 되었습니다.Context 범위를 축소하는 것만으로도 렌더링 범위를 크게 줄일 수 있다는 점을 배웠습니다. 기존에는 한 테이블을 드래그해도 모든 테이블의 모든 컴포넌트가 리렌더링되었는데, 이제는 드래그하는 테이블 내부의 컴포넌트들만 리렌더링됩니다.
API 캐싱 시스템을 구현할 때는 단순한 결과 캐싱이 아닌 Promise 자체를 캐싱하는 방식을 썼습니다. 동시에 같은 API가 여러 번 호출되어도 실제로는 한 번만 요청이 발생할 수 있도록 구현했습니다
코드 품질
LectureService클래스로 API 로직을 UI에서 분리한 부분이 만족스럽습니다. 싱글톤 패턴을 적용해서 캐싱 시스템까지 통합할 수 있었고, 관심사 분리도 명확하게 할 수 있었습니다.컴포넌트 분리 전략에서는 각 검색 옵션을 독립적인 컴포넌트로 만들었습니다. QueryInput, CreditSelect, GradeSelect 등으로 나누니 하나의 옵션만 변경되어도 다른 컴포넌트들은 리렌더링되지 않았습니다.
의외로 key 값도 중요했는데 DnD에서 index를 key로 사용하니 순서가 바뀔 때마다 React가 컴포넌트들의 내용이 변경된 것으로 잘못 인식했습니다. 고유한 id를 key로 사용하도록 바꾸니 불필요한 리렌더링이 크게 줄었습니다.
아쉬운 부분은 Promise.all에서 하나라도 실패하면 전체가 실패하는 구조입니다. Promise.allSettled 같은 대안을 고려해볼 필요가 있습니다.
메모이제이션을 어느 정도까지 해야 하는지도 고민이었습니다. 모든 걸 메모이제이션하면 메모리 사용량이 늘어날 수 있어서, DevTools로 성능을 측정하면서 필요한 부분만 선별적으로 적용했습니다. (그래도 너무 메모이제이션을 남발한거 아닌가? 같은 생각을 하고있습니다..ㅠㅠㅠ)
학습 효과 분석
성능 최적화를 이론이 아니라 실제 애플리케이션에서 해보고 DevTools로 수치까지 확인한 게 가장 큰 학습이 되었던 거 같아요. 그냥 '느리다'에서 시작해서 원인 분석하고 해결책 찾아서 적용하는 전체 과정을 경험할 수 있었습니다.
과제 피드백
실제로 성능 문제를 체감할 수 있는 복잡한 애플리케이션을 제공한 점이 좋았습니다. API부터 렌더링까지 여러 영역을 한번에 다룰 수 있어서 종합적인 학습이 가능했습니다.
리뷰 받고 싶은 내용
이번 과제를 진행하면서 과도한 리렌더링을 줄여나가면서 "과연 어느 정도까지 리렌더링을 허용해줘야 할까?"라는 궁금증이 있습니다. 리렌더링이 발생한다고 해도 성능에 영향이 적을 수도 있고, 반대로 리렌더링을 모두 막으려다가 코드가 과도하게 복잡해지거나 시간이 많이 소모되는 등의 문제가 생길 수 있다고 생각합니다.
또한 메모리 관점에서도 useMemo, useCallback, React.memo 같은 최적화 기법은 내부적으로 값을 캐싱하기 때문에 남발할 경우 메모리 사용량이 늘어날 것이라고 생각이 되는데. 그렇다면 실제 서비스에서 리렌더링을 어느 정도까지 진행해야 하는지, 그 기준을 어떻게 잡는지 궁금합니다.
코치님은 실무에서 메모이제이션을 자주 하시는 편인가요? 만약 메모이제이션을 한다면? 전체적으로 다 메모이제이션하는 것을 선택하시는 편인지, 아니면 최소한의 부분에 대해서만 메모이제이션 하시는 편인지도 궁금합니다.