효과적인 컴포넌트 설계하기 - part 2 #354
jinyoung234
started this conversation in
02 Technical
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
안녕하세요 :) 지난 part1 에서는 PerformanceEntireList 컴포넌트와 SearchResultList 컴포넌트의 효과적인 컴포넌트 재 설계에 대해 이야기 했었습니다. 이번에는 좋은 컴포넌트를 설계하기 위한 5가지 방법을 토대로 리팩토링을 진행한 경험을 공유하고자 합니다.
5가지 방법에 대한 좋은 레퍼런스 자료가 있었고 그 자료에 근거하여 이야기를 진행하고자 합니다.
단일 책임 원칙(SRP)
객체 지향 프로그래밍에서 SRP란 "모든 클래스는 하나의 책임만 가지며, 클래스는 그 책임을 완전히 캡슐화 해야 한다."를 의미합니다.
SRP를 고려하지 않고 컴포넌트를 개발하게 된다면 다음과 같은 문제가 발생합니다.
SRP를 위반한 컴포넌트는 주로 UI와 로직이 분리되지 않은 경우인데 프로젝트의 사례를 들어 예시를 보여드리겠습니다.
Bad(SearchHeader)
SearchHeader.tsx
공연 정보 메인 페이지에서 검색 아이콘을 클릭 할 시 등장 하는 컴포넌트 입니다. 이 컴포넌트의 역할은 다음과 같습니다.
현재 SearchHeader는 여러 가지 책임을 가지고 있기 때문에 SRP를 위반 하였고, 만약 검색 관련 컴포넌트가 필요할 경우 비슷한 로직을 복사 붙여넣기 한 식의 새로운 컴포넌트가 만들어질 가능성이 높아 보입니다.
SearchResultHeader.tsx
실제로 검색 결과 페이지에서 검색을 위해 사용되는 SearchResultHeader 컴포넌트가 비슷한 컴포넌트임에도 불구하고 새로운 컴포넌트를 만든 것을 확인할 수 있었습니다.
이제 하나씩 개선해보겠습니다.
Good
useSearchForm.ts
공연 검색 폼과 관련된 custom hook을 생성하여 비슷한 로직에 대해 재사용 할 수 있도록 합니다.
useOpenBanner.ts
이제 더 이상 컴포넌트 내부에서 상태를 관리하여 여러 책임을 두기 보단 Banner 컴포넌트를 SearchHeader로 부터 분리하기 위해 마찬가지로 custom hook으로 분리합니다.
SearchHeaderHeadless.tsx
Form 관련 데이터 로직과 View를 완전히 분리 및 form이 submit 되는 책임을 분산하고자 Headless 컴포넌트를 생성합니다.
SearchResultHeader.tsx
이제 더 이상 SearchResultHeader에는 데이터 관련 로직이 존재하지 않기 때문에 스타일 변경점만 신경쓰면 됩니다.
SearchModal.tsx
SearchHeader에 많은 책임이 있었지만 책임을 분산하고자 children을 props로 받는 layout 컴포넌트 형태로 변경했으며, 이제 SearchHeader는 Modal의 역할로 열고 닫는 기능을 수행하게 됩니다.
SearchModalHeader.tsx
이제 SearchHeader는 모달의 헤더로써 입력, 리셋, 메인 페이지로 이동의 기능을 수행하는 독립적인 컴포넌트 즉, 단일 책임을 갖는 컴포넌트가 되었습니다. SearchModalBody도 동일하게 단일 책임을 갖게 되었습니다.
SearchBanner.tsx
SearchBanner도 이제 배너가 등장하고 닫히는 단일 책임을 갖는 컴포넌트로써의 기능을 수행합니다.
Header.tsx
이제 SearchModal이 layout 형태의 컴포넌트 이기 때문에 Banner 이외에 다른 요구사항이 발생해도 Modal 내부에 컴포넌트를 추가하거나 제거 해도 유연하게 대처가 가능합니다.
2. 재 사용 가능성
컴포넌트를 사용하는 가장 큰 이유 중 하나는 유사한 기능을 가진 컴포넌트 들을 재 사용함으로써, 개발 시간을 단축 및 코드 중복과 더 나은 유지 보수를 가능하게 하는 것 입니다.
2번도 마찬가지로 SearchHeader의 개선 과정에서 UI와 로직의 분리를 통해 재 사용성과 유지보수성을 향상 시킬 수 있습니다.
이렇게 분리 시 다른 페이지에서 컴포넌트를 사용하기 수월 하며 변경이 발생해도 스타일만 변경 or 데이터 로직만 변경 하기 때문에 쉬운 변경이 가능합니다.
3. 성능 최적화
리액트의 성능은 lighthouse 등에서 확인이 가능한데, 컴포넌트의 최적화가 되지 않은 경우 Web Core Vitals(TTFB, LCP, FCP, CLS) 라고 하는 성능 지표에 영향이 생겨 UX에 영향이 생길 수 있습니다.
리액트에서 성능 최적화를 위한 방법은 다음과 같습니다.
4. 테스트 가능성
테스트를 고려한 컴포넌트 설계는 코드의 품질을 높이고 버그를 줄이는데 도움이 됩니다.
이러한 방법들을 통해 단위 테스트 및 통합 테스트, E2E 테스트, UI 테스트 등을 수행하여 컴포넌트의 동작을 검증할 수 있습니다.
PerformanceList.tsx
위 컴포넌트는 공연 정보 메인 페이지에서 일 별로 공연 정보를 보여주는 경우 사용되는 컴포넌트 입니다.
내부에 로직을 가지고 있는 것이 아닌 외부에 위임 된 상태 이기 때문에 동작 확인 및 UI 확인이 용이 합니다.
PerformanceList.stories.tsx
Danverse에서는 대부분의 컴포넌트를 스토리북을 통해 독립적으로 확인을 하고 있습니다.
컴포넌트의 비즈니스 & UI 로직을 외부로 위임 했기 때문에 스토리북 파일 내에서 상태를 정의 후 독립적인 환경에서 컴포넌트의 동작 여부를 테스팅 할 수 있습니다.
5. 가독성과 유지보수성
가독성과 유지보수성을 고려하는 것은 개발에 있어서 상대방에게 예의를 갖추는 행동이라 생각했습니다.
많은 사람들이 쉽게 파악이 가능하며, 빠르게 이해할 수 있는 코드를 만드는 것이 제품의 품질을 높이고 유지 보수 하기 쉬운 제품을 만드는 것이라고 생각했습니다.
제가 생각한 가독성 및 유지보수를 위한 코드는 다음과 같습니다.
Danverse에서 공연 정보 메인 페이지에 사용 되는 캘린더 컴포넌트의 인터페이스 입니다.
컴포넌트가 필요한 상태가 많아짐에 따라 props로 받는 데이터들이 점점 늘어났고, 후에 같은 프론트엔드 팀인 K님이 이 코드를 볼 때 조금이라도 이해를 돕고자 다음과 같이 주석을 통해 props로 받는 데이터들이 어떤 역할을 하는지 명시 함으로써, 가독성을 신경 쓰려고 노력했습니다.
레퍼런스
Beta Was this translation helpful? Give feedback.
All reactions