[3팀 이호재] Chapter 2-2. 디자인 패턴과 함수형 프로그래밍 #62
Open
kevinhojae wants to merge 36 commits intohanghae-plus:mainfrom
Open
[3팀 이호재] Chapter 2-2. 디자인 패턴과 함수형 프로그래밍 #62kevinhojae wants to merge 36 commits intohanghae-plus:mainfrom
kevinhojae wants to merge 36 commits intohanghae-plus:mainfrom
Conversation
added 30 commits
April 25, 2025 00:46
added 6 commits
April 25, 2025 00:46
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.
https://kevinhojae.github.io/front_5th_chapter2-2/
과제의 핵심취지
과제에서 꼭 알아가길 바라는 점
기본과제
Component에서 비즈니스 로직을 분리하기
비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
뷰데이터와 엔티티데이터의 분리에 대한 이해
entities -> features -> UI 계층에 대한 이해
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
특정 Entitiy만 다루는 함수는 분리되어 있나요?
특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
재사용 가능한 Custom UI 컴포넌트를 만들어 보기
재사용 가능한 Custom 라이브러리 Hook을 만들어 보기
재사용 가능한 Custom 유틸 함수를 만들어 보기
그래서 엔티티와는 어떤 다른 계층적 특징을 가지는지 이해하기
UI 컴포넌트 계층과 엔티티 컴포넌트의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
엔티티 Hook과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
과제 셀프회고
과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
[ 폴더 구조 ]
사용자 도메인에 따라 컴포넌트를 효과적으로 구분하기 위해 components 폴더 하위에
admin/과user/폴더로 분리했습니다.ui폴더는 프로젝트 전체에서 사용되는 primitive 컴포넌트들을 모아둔 곳으로, 재사용 가능한 기본 UI 요소들을 구현하였습니다.[ Context를 활용한 상태 관리 ]
prop drilling 문제를 해결하기 위해 필요한 영역에서만 context를 활용하여 상태를 관리하도록 개선했습니다.
CartPage에서는 CartContext를, 관리자 기능에서는 AdminContext를 적용하여 불필요한 prop 전달을 제거했습니다.
beforeafterCartPage에서 호출한useCart의updateQuantity,removeFromCart로직이 prop을 타고타고CartItem으로 전달해야 했고, 컴포넌트를 쪼갤수록 prop drilling이 깊어지는 문제가 발생했습니다해당 함수를 사용하는
CartItem에서 바로 호출해서 사용하여 클린한 형태로 개선했습니다[ UI 컴포넌트 개발 전략 ]
Button 컴포넌트
cva와 cn 유틸리티를 활용하여 variant 기반의 스타일 시스템을 구현했습니다.
color prop을 통해 다양한 스타일 변형을 쉽게 적용할 수 있도록 설계했습니다.
기존 HTML button 속성을 확장하면서 커스텀 color variant를 추가하여 유연하고 타입 안전한 컴포넌트를 구현했습니다.
Accordion 컴포넌트
기존에는 상위 컴포넌트에서 아코디언의 열림 상태를 관리했으나, 각 아코디언이 자체적으로 상태를 관리하도록 개선했습니다.
Context API를 활용하여 아코디언 내부 컴포넌트 간
open상태 공유를 구현했습니다.Radix UI의 구조를 참고하여 컴포넌트 내부에서 상태를 효율적으로 관리하도록 설계했습니다.
Accordion 컴포넌트를 사용하는 곳에서는 아래와 같이 사용합니다.
ToggleButton 컴포넌트
Accordion과는 다르게, 버튼을 클릭했을 때 content를 보여줬다 숨겼다 하는 다른 동작의 컴포넌트를 Button, Accordion과는 별도로 두었습니다.
사용할 때는 다음과 같이 사용합니다.
[ Form 컴포넌트 개선 (React Hook Form 적용) ]
기존에는 form 내부 상태를 컴포넌트에서 직접 관리하여 복잡성이 증가했습니다.
React Hook Form을 도입하여 상태 관리 로직을 위임하고 비즈니스 로직에 집중할 수 있도록 개선했습니다.
불필요한 리렌더링 감소: 각 입력값 변경마다 useState를 사용하는 방식과 달리, React Hook Form은 언제 컴포넌트를 리렌더링할지 최적화되어 있어 성능을 개선할 수 있습니다.
복잡한 폼 상태 관리 간소화: 여러 입력 필드가 있는 폼에서 각 필드마다 상태와 핸들러를 만드는 반복적인 코드를 제거했습니다.
react hook form을 위한 form schema와 핸들링 로직을 별도의 훅으로 분리하여 작성했습니다 (
useProductEditForm,useProductAddForm,useCouponAddForm)이후에 form 요구사항에 따른 validation 로직과, 에러 메시지 등을 추가로 도입하기에 용이합니다.
beforeafter[ Compound Component 패턴 적용 ]
복잡한 React JSX 코드의 가독성 문제를 해결하기 위해 전체적인 구조를 빠르게 이해할 수 있도록 Compound Component 패턴을 넉용했습니다.
CartItem 컴포넌트를 처음 본 개발자) 아 요 컴포넌트는 item의 정보가 표시되고, action 버튼이 있어서 add를 하면 수량이 1씩 올라가고, decrease를 하면 수량이 1씩 감소되며, remove를 하면 카트에서 제거되는구나!
로직이 복잡해지는 경우 별도의 컴포넌트 파일로 분리하여 관리합니다.
[ 테스트 코드 전략 ]
순수함수의 테스트가 예상한 것과 같도록 올바르게 동작하면, 순수함수 파이프라인도 올바른 결과를 보장할 것이고, 결국 ui 상태 업데이트도 의도한대로 진행될 것으로 생각하여 순수 함수 중심의 테스트를 추가로 구현했습니다.
테스트 케이스를 상수로 정의하고
test.each를 활용하여 테스트 로직을 재사용했습니다.이 접근 방식은 테스트 케이스의 가독성을 높이고 테스트 의도를 명확하게 파악할 수 있게 한다고 생각했습니다.
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
전역 상태 관리 최적화
테스트 커버리지 확대
순수 함수 중심의 테스트도 좋지만, UI 컴포넌트와 사용자 인터랙션에 대한 추가 테스트를 더 작성했으면 좋았을 것 같습니다.
특히 form hook의 로직을 검증하는 테스트 코드를 추가하면 좋을 것이라 생각합니다.
entity 경계 분리 디벨롭
useCart,useProduct) 좀 더 구체화된 entity 기반으로 로직을 리팩토링하고 싶습니다.리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
Compound component 패턴으로 처음 접했을 때에도 코드가 언어적으로 표현되어 이해하기 쉬운 구조로 리팩토링하고자 노력했는데, 컴포넌트 파일로 분리해야 하는 기준이 모호했던 것 같습니다.
이번에 리팩토링을 하면서는 컴포넌트의 내부에 포함되는 동작 로직이 과도해질 때 compound component의 일부분 → 독립적인 컴포넌트 파일 로 분리하였는데,
beforeafter이 과도해진다는 기준이 모호했던 것 같습니다. 독립적인 컴포넌트 파일로 분리할 떄 좀 더 명확한 기준이 있을까요?
Domain Driven Design에서의 business logic / domain usecase 와 Functional Programming 에서의 계산 / 액션
DDD 방법론에서 비즈니스 로직과 도메인 유스케이스는 각각 도메인의 규칙과 사용자의 시나리오 흐름을 나타낸다고 이해하고 있습니다.
이번 과제에서 함수형 프로그래밍 관점에서 코드를 리팩토링하다 보니, 이 두 개념이 각각 FP의 계산(calculation)과 액션(action) 개념과 유사하다고 느꼈습니다.
이를테면,
비즈니스 로직은 입력에 따라 출력이 결정되어야 하며, 도메인 내부 규칙(예: 장바구니 개수 제한, 할인 계산 등)을 구현 → calculation
도메인 유스케이스는 여러 비즈니스 로직의 파이프라인으로 구성되고, 외부 시스템 호출 등 부수 효과를 포함한 흐름 → action
특히 도메인에 특화된, 도메인 엔티티를 다루는 순수 함수들이 대부분 비즈니스 로직에 해당한다고 느꼈고, 이들을 기반으로 유즈케이스가 구성된다는 점에서 두 개념이 밀접하게 연결된다고 생각했습니다.
이러한 해석은 DDD 철학과 FP 개념 간의 매핑으로 자연스럽게 받아들여질 수 있는 해석일까요? 이해한 내용에 있어 제가 잘못 이해했거나 놓치고 있는 부분이 있는지 여쭤보고 싶습니다!