-
Notifications
You must be signed in to change notification settings - Fork 47
[2팀 정나리] Chapter3-2. 디자인 패턴과 함수형 프로그래밍 그리고 상태 관리 설계 #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
naringst
wants to merge
73
commits into
hanghae-plus:main
Choose a base branch
from
naringst:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
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
- 쿠폰 사용 가능 체크 함수 - 실제 쿠폰 적용 로직 으로 분리
745ae5e to
8f7436e
Compare
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.
과제 배포 링크
과제의 핵심취지
과제에서 꼭 알아가길 바라는 점
기본과제
Component에서 비즈니스 로직을 분리하기
비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
뷰데이터와 엔티티데이터의 분리에 대한 이해
entities -> features -> UI 계층에 대한 이해
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
특정 Entitiy만 다루는 함수는 분리되어 있나요?
특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
이번 심화과제는 Context나 Jotai를 사용해서 Props drilling을 없애는 것입니다.
어떤 props는 남겨야 하는지, 어떤 props는 제거해야 하는지에 대한 기준을 세워보세요.
Context나 Jotai를 사용하여 상태를 관리하는 방법을 익히고, 이를 통해 컴포넌트 간의 데이터 전달을 효율적으로 처리할 수 있습니다.
Context나 Jotai를 사용해서 전역상태관리를 구축했나요?
전역상태관리를 통해 domain custom hook을 적절하게 리팩토링 했나요?
도메인 컴포넌트에 도메인 props는 남기고 props drilling을 유발하는 불필요한 props는 잘 제거했나요?
전체적으로 분리와 재조립이 더 수월해진 결합도가 낮아진 코드가 되었나요?
과제 셀프회고
과제를 하면서 내가 알게된 점, 좋았던 점은 무엇인가요?
[디자인 패턴들]
컴포넌트 합성
Button,DeleteButton,CartQuantityHandler,CartItemPrice등)을 조합하여 더 큰 컴포넌트를 만드는 패턴을 경험했습니다. 이를 통해 각 컴포넌트의 재사용성과 테스트 용이성이 크게 향상되었습니다.CartItemComponent에서 여러 작은 컴포넌트들을 합성하여 복잡한 UI를 구성하는 과정에서, 각 컴포넌트가 단일 책임을 가지도록 설계하는 것이 얼마나 중요한지 깨달았습니다.변경에 유연한 코드
cart.service.ts)에 순수함수들을 분리함으로써, 계산 로직을 독립적으로 테스트하고 재사용할 수 있게 되었습니다. 예를 들어calculateItemTotal,calculateCartTotalPrice같은 함수들은 어디서든 동일한 결과를 보장하는 순수함수로 작성되어 있어, 코드의 예측 가능성이 높아졌습니다.Container-Presenter 패턴의 실전 적용
basic버전에서 Container 컴포넌트가 상태와 비즈니스 로직을 관리하고, Presenter 컴포넌트는 UI 렌더링만 담당하는 패턴을 적용했습니다. 이를 통해 관심사의 분리가 명확해졌고, 컴포넌트의 책임이 분명해졌습니다.화면과 코드의 1:1 매칭
CartSection,CartTitle,CartItem같은 컴포넌트 이름이 실제 화면의 구조를 그대로 반영하도록 했습니다. 이를 통해 코드를 읽는 사람이 화면을 보지 않아도 어떤 부분을 담당하는지 쉽게 이해할 수 있도록 했습니다.이번 과제에서 내가 제일 신경 쓴 부분은 무엇인가요?
[함수형 프로그래밍]
cart.service.ts에서 모든 계산 로직을 순수함수로 분리했습니다.calculateItemTotal,getMaxApplicableDiscount,calculateCartTotalPrice같은 함수들은 입력값에 대해서만 결과를 반환하고, 외부 상태를 변경하지 않도록 작성했습니다.useCart,useCoupon,useProduct)에서는 상태 관리와 부수효과(side effect)를 처리하고, 순수한 계산 로직은 Service 레이어로 분리하여 함수형 프로그래밍의 원칙을 지키려고 노력했습니다.calculateItemTotal은 순수 계산 함수로,useCart의addToCart는 상태 변경과 부수효과를 처리하는 액션으로 명확히 구분했습니다. (시간이 없어서 다 분리는 못했지만, 이 방향으로 계속 개선해나가고 싶습니다!)[관심사의 분리 - 응집도 높이고 결합도 낮추기]
엔티티 기반 계층 구조 설계
cart,products,coupons)와 그렇지 않은 상태(isAdmin,isShowPopup)를 명확히 구분했습니다.CartItemComponent,ProductItem)와 UI 컴포넌트(Button,Input,Select)를 분리하여, 각각의 책임을 명확히 했습니다.features폴더 구조를 통해 cart, product, coupon, notification 등 각 도메인별로 관련된 컴포넌트, 훅, 서비스를 응집도 높게 구성했습니다.Custom Hook을 통한 로직 캡슐화
useCart,useCoupon,useProduct등의 Custom Hook을 통해 각 도메인의 상태 관리와 비즈니스 로직을 캡슐화했습니다. 이를 통해 컴포넌트는 UI 렌더링에만 집중할 수 있게 되었습니다.데이터, 로직, UI의 명확한 구분
코드 분리 시점과 기준
인터페이스의 직관성
calculateItemTotal은 "아이템의 총액을 계산한다"는 의미가 바로 드러나고,useCart는 "장바구니 관련 로직을 다룬다"는 것을 명확히 합니다.[전역 상태를 써서 props drilling을 막으면 과연 무조건 좋을까?]
basic버전에서는 props drilling이 발생했습니다.App→ShopPage→Cart→CartItem같은 깊은 prop 전달이 필요했고, 이는 코드의 가독성을 떨어뜨렸습니다.advanced버전에서는 Jotai를 사용하여 전역 상태를 관리했습니다.cartAtom,isAdminAtom등을 통해 여러 컴포넌트에서 공유되는 상태를 효율적으로 관리할 수 있었습니다.isShowPopup같은 UI 상태)는 전역 상태로 만들 필요가 없습니다.products는 전역 상태로 관리해야 할까?products는 여러 컴포넌트(상품 목록, 장바구니, 관리자 페이지)에서 사용되지만, 읽기 전용 데이터에 가깝습니다.이번 과제를 통해 앞으로 해보고 싶은게 있다면 알려주세요!
useNotificationhook을useCart에 통합하는 것이 좋을지, 아니면 별도의 이벤트 시스템을 구축하는 것이 좋을지 고민해보고 싶습니다.리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
derived atom을 사용할 때와 일반 atom을 사용할 때의 성능 차이와 사용 시점에 대한 조언이 필요합니다.totalCartItemCountAtom같은 derived atom이 매번 계산되는데, 이게 최적의 방법인지 궁금합니다.calculateItemTotal이getMaxApplicableDiscount를 사용하는데, 이런 의존성을 어떻게 관리하는 것이 좋을까요?CartItemComponent는 엔티티 컴포넌트인데, 내부에Button,DeleteButton같은 UI 컴포넌트를 사용하고 있습니다. 이런 구조가 적절한지, 아니면 더 분리할 수 있는지 궁금합니다.useCart가useProduct의 데이터를 필요로 하거나,useCoupon이useCart의 상태를 참조해야 할 때, 이런 의존성을 어떻게 관리하는 것이 좋을까요?"이건 이렇게 해도 될까?", "이 방식이 과연 좋은 방식일까?" 하고 망설였던 선택들
전역 상태 관리 범위
products를 전역 상태로 관리할지, props로 전달할지 고민이 많았습니다. 결국 전역 상태로 관리하기로 했지만, 이게 정말 최선인지는 계속 의문이 듭니다.isAdmin같은 UI 상태도 전역으로 관리했는데, 이게 과한 건 아닐까요?컴포넌트 분리 수준
CartItemComponent내부에DeleteButton,CartQuantityHandler,CartItemPrice같은 작은 컴포넌트들을 만들었는데, 이 정도로 세분화하는 것이 과한 건 아닐까요?Service 레이어의 함수 분리
getMaxApplicableDiscount를 private 함수로 두고calculateItemTotal에서만 사용하도록 했는데, 이게 맞는 선택인지 고민이 됩니다.처음엔 이렇게 하려다가 나중에 전혀 다른 방향으로 바꾼 것들
useProducts라는 하나의 큰 Hook으로 상품 목록 관리와 폼 관리를 모두 처리하려고 했습니다.useProductForm으로 분리해서 각각의 책임으로 분리했습니다.useProducts는 상품 목록의 CRUD 작업에만 집중useProductForm은 폼 상태 관리와 유효성 검사에만 집중배포 이슈 및 해결 과정
문제 상황
GitHub Pages에 배포할 때, 빌드는 성공했지만 실제 배포된 사이트에서 리소스(JS, CSS 파일)를 찾지 못하는 문제가 발생했습니다. 브라우저 콘솔에서 404 에러가 발생하며 애플리케이션이 제대로 로드되지 않았습니다.
원인 분석
https://username.github.io/front_7th_chapter3-2/같은 형태로 배포됩니다./)를 기준으로 리소스를 로드하는데, 서브 경로에 배포할 경우 상대 경로 문제가 발생합니다.vite.config.ts에서base옵션을 설정하지 않으면, 빌드된 HTML 파일에서 절대 경로(/assets/...)로 리소스를 참조하게 되어 GitHub Pages의 서브 경로에서 제대로 작동하지 않습니다.해결 방법
vite.config.ts파일에base옵션을 추가하여 GitHub Pages의 서브 경로를 명시했습니다:배운 점
base옵션은 빌드 시 모든 asset 경로에 prefix를 추가합니다. 이를 통해 서브 디렉토리에 배포할 때도 올바른 경로로 리소스를 참조할 수 있습니다..github/workflows/deploy.yml)에서 빌드 단계와 배포 단계가 분리되어 있어, 빌드 산출물(dist폴더)이 올바르게 생성되는지 확인하는 것이 중요합니다.base경로를 동적으로 설정할 수 있도록 환경 변수를 활용하는 방법도 고려해볼 수 있습니다 (예: 개발 환경은/, 프로덕션은/front_7th_chapter3-2/).