과제 링크
https://yuhyeon99.github.io/front_6th_chapter2-2/
과제의 핵심취지
- React의 hook 이해하기
- 함수형 프로그래밍에 대한 이해
- 액션과 순수함수의 분리
과제에서 꼭 알아가길 바라는 점
- 엔티티를 다루는 상태와 그렇지 않은 상태 - cart, isCartFull vs isShowPopup
- 엔티티를 다루는 컴포넌트와 훅 - CartItemView, useCart(), useProduct()
- 엔티티를 다루지 않는 컴포넌트와 훅 - Button, useRoute, useEvent 등
- 엔티티를 다루는 함수와 그렇지 않은 함수 - calculateCartTotal(cart) vs capaitalize(str)
기본과제
- Component에서 비즈니스 로직을 분리하기
- 비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
- 뷰데이터와 엔티티데이터의 분리에 대한 이해
- entities -> features -> UI 계층에 대한 이해
- Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
- 주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
- 계산함수는 순수함수로 작성이 되었나요?
- Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
- 주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
- 계산함수는 순수함수로 작성이 되었나요?
- 특정 Entitiy만 다루는 함수는 분리되어 있나요?
- 특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
- 데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
- 재사용 가능한 Custom UI 컴포넌트를 만들어 보기
- 재사용 가능한 Custom 라이브러리 Hook을 만들어 보기
- 재사용 가능한 Custom 유틸 함수를 만들어 보기
- 그래서 엔티티와는 어떤 다른 계층적 특징을 가지는지 이해하기
- UI 컴포넌트 계층과 엔티티 컴포넌트의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
- 엔티티 Hook과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
- 엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
과제 셀프회고
과제를 하면서 내가 제일 신경 쓴 부분
명확한 책임 분리를 통한 예측 가능한 코드 작성
이번 과제를 진행하면서 가장 중점을 둔 부분은 함수와 컴포넌트의 단일 책임 원칙(SRP)을 지키는 것이었습니다. 특히, 작은 유틸리티 함수부터 시작하여 코드의 예측 가능성을 높이고자 노력했습니다.
구체적인 사례: formatPrice 함수의 분리
- 문제점
기존
formatPrice함수는isAdmin이라는 boolean 플래그를 받아 관리자용 포맷과 사용자용 포맷을 분기 처리했습니다.
// 기존 방식
export const formatPrice = (price: number, isAdmin: boolean = false): string => {
if (isAdmin) {
return `${price.toLocaleString()}원`; // 관리자용
}
return `₩${price.toLocaleString()}`; // 사용자용
};
- 개선점
이 방식은 함수를 사용하는 쪽에서 항상
isAdmin플래그를 신경 써야 하고, 함수의 이름만으로는 어떤 결과가 나올지 예측하기 어렵다는 단점이 있었습니다. 이 문제를 해결하기 위해, 각기 다른 책임을 가진formatPriceForAdmin과formatPriceForShop두 개의 명시적인 함수로 분리했습니다.
// 개선된 방식
export const formatPriceForAdmin = (price: number): string => {
return `${price.toLocaleString()}원`;
};
export const formatPriceForShop = (price: number): string => {
return `₩${price.toLocaleString()}`;
};
- 결과
이렇게 분리함으로써, 함수를 사용하는
AdminPage.tsx나ShoppingPage.tsx에서는 더 이상 조건부 로직에 대해 고민할 필요 없이 필요한 함수를 직접 가져와 사용할 수 있게 되었습니다. 코드의 가독성과 예측 가능성이 향상되었고, 각 함수의 책임이 명확해져 유지보수가 용이해졌습니다.
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점
페이지 컴포넌트의 과도한 책임
리팩토링을 통해 많은 부분을 개선했지만, 페이지 레벨 컴포넌트(ShoppingPage.tsx, AdminPage.tsx)가 여전히 너무 많은 책임을 가지고 있다는 점이 아쉽습니다.
컴포넌트 분리가 더 세밀하게 이루어졌다면 좋았을 것 같습니다.
구체적인 사례: ShoppingPage.tsx의 복잡성
-
문제점
ShoppingPage.tsx는 상품 목록, 장바구니, 쿠폰 적용, 검색 등 쇼핑 페이지의 거의 모든 상태와 로직을 총괄하고 있습니다.useProducts,useCart,useCoupons,useNotifications등 여러 커스텀 훅을 동시에 사용하여 데이터를 가져옵니다.- 검색어 상태(
searchTerm,debouncedSearchTerm)와 그에 따른 필터링 로직을 직접 포함하고 있습니다. completeOrder와 같은 주요 비즈니스 로직 콜백 함수를 페이지 컴포넌트 내에서 정의하고 있습니다.
-
아쉬운 점 이로 인해
ShoppingPage는 30줄이 훌쩍 넘는 상태 관리 로직과 100줄이 넘는 JSX를 가지게 되어 비대해졌습니다. 예를 들어, 상품 목록을 보여주는 부분과 장바구니 부분을 각각 별도의 컨테이너 컴포넌트(ProductListContainer,CartContainer)로 분리했다면,ShoppingPage는 이들의 레이아웃만 담당하게 되어 훨씬 간결해졌을 것입니다. 각 컨테이너가 필요한 데이터만 주입받도록 설계하여 관심사를 분리하지 못한 점이 가장 아쉽습니다.
리뷰 받고 싶은 내용이나 궁금한 것
-
formatPrice함수 분리 방식에 대한 피드백- 현재
formatPriceForAdmin과formatPriceForShop으로 역할을 분리한 방식에 대해 어떻게 생각하시는지 궁금합니다. SRP를 잘 적용한 사례라고 볼 수 있을까요? 혹은, 이렇게 작은 기능은 하나의 함수에type과 같은 옵션을 받아 처리하는 것이 더 나은 설계였을지, 실무에서는 어떤 패턴을 더 선호하는지 궁금합니다.
- 현재
-
거대 페이지 컴포넌트의 효과적인 분리 전략
ShoppingPage.tsx와 같이 여러 도메인의 상태(상품, 장바구니, 쿠폰)를 조합해야 하는 페이지 컴포넌트를 리팩토링하는 더 좋은 전략이 궁금합니다.- 제가 아쉬운 점으로 꼽았듯이, 각 섹션(상품 목록, 장바구니)을 컨테이너 컴포넌트로 분리하고 필요한 훅을 각각의 컨테이너에서 호출하는 방식이 괜찮은 접근일까요? 이 경우, 컴포넌트 간에 상태 공유가 필요할 때(예: 상품을 장바구니에 담는 상호작용)는 어떻게 처리하는 것이 가장 효율적인지에 대한 조언을 구하고 싶습니다.
과제 피드백
안녕하세요 유현님! 5주차 과제 잘 진행해주셨네요 ㅎㅎ 다만 클린코드 챕터의 경우 코드를 작성하는 것도 물론 중요하지만 내가 왜 이렇게 작성했고 왜 이렇게 생각했는지에 대한 과정이 더 중요해서요! 나중에라도 회고해보시면 좋겠어요!
고생하셨습니다~!