배포링크
과제의 핵심취지
- 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과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
-
엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?
과제 셀프회고
로컬스토리지 연동을 위해 영서님의 코드를 조금 가져다 사용했습니다.
createStore와 useLocalStorageObject 을 가져다 사용해보았는데 정말 만족스럽네요. 회사에서 아쉽게 nextJS
를 사용중이라 못쓸것같지만 클라이언트사이드 SPA환경에서는 충분히 엔터프라이즈급에서도 사용가능할법한 코드인것같습니다. 멋집니다 영서님!!
과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
이번 과제를 진행하면서 가장 신경 쓴 부분은 데이터의 단방향 흐름과 각 계층의 명확한 책임 분리였습니다. 특히 다음과 같은 구조를 만드는데 집중했습니다
View (UI) Layer
↓
Presenter/ViewModel Layer (중간 계층)
↓
Service Layer
↓
Store Layer
각 계층별 역할과 책임
-
View Layer (components/* or pages/*)
- 순수하게 화면 렌더링에만 집중
- props로 받은 데이터와 콜백만 사용
- 비즈니스 로직 제로
-
Presenter/ViewModel Layer (viewmodel or presenter)
- 가장 고민했던 부분이 이 중간 계층의 네이밍이었습니다
- 처음에는 'Controller'로 할까 고민했지만, MVC 패턴과 혼동될 수 있어서 제외
- 'Presenter'로 할까 했지만, MVP 패턴의 Presenter와도 차이가 있었음
-
Service Layer (services/*)
- 순수한 비즈니스 로직 담당
- Entity 관련 핵심 로직 수행
- 여러 Store의 데이터를 조합해서 비즈니스 로직 수행
-
Store Layer (store/*)
- 가장 기본적인 상태 관리
- CRUD 작업만 담당
- localStorage 연동 등 영속성 처리
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
-
Props Drilling vs 함수 인터페이스 명시성
- 가장 고민이 많았던 부분이 props drilling 문제였습니다.
- 예를 들어
addToCart,updateQuantity,removeFromCart같은 함수들을 - 전역 상태로 관리하면 props drilling은 해결되지만, 함수의 인터페이스가 가려지는 문제가 있었습니다.
- 결국 props로 전달하는 방식을 선택했는데, 이게 정말 올바른 선택이었는지 계속 고민했습니다.
-
함수의 책임 표현 vs 코드 복잡도
- props로 함수를 전달하면 해당 컴포넌트가 어떤 책임을 가지고 있는지 명확하게 보입니다.
- 하지만 깊은 계층 구조에서는 props drilling이 발생할 수밖에 없었습니다.
- 예를 들어:
// 현재 방식 - 함수 인터페이스가 명확함 <ProductSection addToCart={addToCart} updateQuantity={updateQuantity} /> // 전역 상태 방식 - props drilling은 해결되지만 인터페이스가 가려짐 <ProductSection /> // 내부에서 useCartStore() 직접 사용 -
DX vs Clean Code의 균형
- 개발자 경험(DX)을 위해서는 props drilling을 피하고 전역 상태를 사용하는 것이 편할 수 있습니다.
- 하지만 Clean Code 관점에서는 함수의 의존성이 명시적으로 드러나는 것이 더 좋다고 생각합니다.
- 이 두 가치 사이에서 어떤 것을 우선시해야 하는지 계속 고민했습니다.
-
테스트 코드 부족
- 순수 함수들에 대한 단위 테스트를 더 꼼꼼하게 작성했으면 좋았을 것 같습니다.
- 특히 장바구니 계산 로직이나 할인 정책 관련 테스트가 부족했습니다.
-
에러 처리 개선
- 현재는 대부분의 에러를 notification으로 처리하고 있는데, 좀 더 체계적인 에러 처리 시스템을 구축했으면 좋았을 것 같습니다.
- 커스텀에러를 위로 전파시켜 NotificationBoudary를 통해 상위에서 에러를 잡아 토스트메시지 구현을 했으면 좋았을것 같습니다.
- 예를 들어 ValidationError, BusinessError 등으로 구분해서 처리할 수 있었을 것 같습니다.
-
Custom Hook 재사용성
useLocalStorageObject같은 훅은 잘 분리했지만, 다른 커스텀 훅들의 재사용성을 더 높일 수 있었을 것 같습니다.- 특히 폼 관련 로직들은 좀 더 일반화해서 만들 수 있었을 것 같습니다.
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문
-
ViewModel vs Presenter
- 중간 계층의 네이밍으로 'ViewModel'을 선택했는데, 이게 적절한 선택이었을까요?
- React 생태계에서는 이런 중간 계층을 어떤 이름으로 부르는 것이 관례인가요?
-
Props Drilling vs 함수 인터페이스 명시성
- 전역 상태로 함수를 관리하면 props drilling은 해결되지만, 컴포넌트의 의존성이 가려지는 문제가 있습니다.
- 반대로 props로 전달하면 인터페이스는 명확하지만 drilling 문제가 발생합니다.
- 이런 상황에서 어떤 방식을 선택하는 것이 더 좋은 코드일까요?
-
함수의 책임 표현 방법
- props로 함수를 전달하는 것이 함수의 책임을 표현하는 좋은 방법인가요?
- 아니면 다른 더 나은 방법이 있을까요?
- handle / setter ..
-
DX vs Clean Code 우선순위
- 개발자 경험을 위해서는 편의성을, 코드 품질을 위해서는 명시성을 우선시해야 하는데
- 실제 프로덕션 환경에서는 어떤 가치를 더 중요하게 생각해야 할까요?
-
데이터 흐름 방향
- 현재 View → ViewModel → Service → Store 방향으로 단방향 데이터 흐름을 구현했는데,
- 실제 대규모 애플리케이션에서도 이런 방식이 유지 가능할까요?
- 특히 실시간 업데이트나 웹소켓 같은 기능을 구현할 때는 어떻게 이 흐름을 유지할 수 있을까요?
-
Entity를 다루는 순수 함수들의 위치
- 현재는 대부분의 순수 함수들을 service 내부에 구현했는데, 이들을 별도의 utils로 분리하는 것이 더 나았을까요?
이런 고민들을 하면서 느낀 점은 "완벽한 해결책은 없다"는 것이었습니다. 각각의 방식이 장단점이 있고, 상황에 따라 적절한 선택을 해야 한다는 것을 배웠습니다. 하지만 이런 상황에서 어떤 기준으로 판단해야 하는지에 대한 명확한 가이드라인이 궁금합니다.
과제 피드백
수고했어요 준형~ "* 가장 고민이 많았던 부분이 props drilling 문제였습니다." Props Drilling vs 함수 인터페이스 명시성 결국 props로 전달하는 방식을 선택했는데, 이게 정말 올바른 선택이었는지 계속 고민했습니다." 준형의 회고에서 많은 고민을 해봤다는게 느껴지네요.
이번 과제의 여려가지 취지 중의 하나가 이 균형감각에 대한 이해였습니다. 극단적으로 가면 props drilling의 단점이 너무 부각되고 반대로 props를 없지 전역으로만 가면 명시성을 잃고 테스트가 어려워지고 재사용성이 떨어지죠.
"이 두 가치 사이에서 어떤 것을 우선시해야 하는지 계속 고민했습니다." 준형의 나름의 중간 결론이 궁금하네요. 둘 중의 하나가 아니라 어떤 경우에 각 장점이 더 부각되는가가 중요합니다. 어떤 코드는 재사용과 명시성을 살리는게 더 좋고 어떤 코드는 클린함을 살리는게 더 나은가?
6주차 과제 한번 더 남았죠. 이제는 이 모든 결론을 총동원하고 다른 사람의 코드들을 살펴보면서 어떤 전략이 좋은지를 생각해보고 시도해보길 바래요! 화이팅입니다.