[9팀 임두현] Chapter 2-2. 디자인 패턴과 함수형 프로그래밍#50
[9팀 임두현] Chapter 2-2. 디자인 패턴과 함수형 프로그래밍#50ldhldh07 wants to merge 49 commits intohanghae-plus:mainfrom
Conversation
- 포매터 미적용된 경우 적용
JunilHwang
left a comment
There was a problem hiding this comment.
안녕하세요, 과제 잘 진행하셨습니다. 전체 리팩토링(원래 App 단일파일 → atoms/models/hooks/components 분리)을 통해 도메인/뷰/액션을 명확히 나눈 점과 순수함수 중심의 설계를 적극 적용한 점이 인상적입니다. 아래 피드백은 PR의 파일 변경사항(.patch)과 PR 본문(셀프회고, 질문)을 바탕으로 작성한 Github PR 리뷰용 피드백입니다. 필요하면 코멘트 단위로 쪼개어 PR에 붙여넣어 사용하셔도 좋습니다.
현재 코멘트의 흐름(요청하신 방식)
- 기술 요구사항 변화 시나리오 제시
- 각 시나리오에 대해 현 코드가 대응하면 어떤 변화가 생길지 (AS-IS → TO-BE)
- 이를 바탕으로 응집도/결합도 관점에서 코드가 잘 작성되었는지 판단 및 개선안
간단 안내: 아래에서 AS-IS / TO-BE 코드 예시는 핵심만 간추려 설명용으로 제시합니다.
질문에 대한 답변 — "검색창 로직이 컴포넌트에 있는 안티패턴"에 대해
요약: 컴포넌트 내부에 검색 로직이 직접 포함되는 것이 왜 안티패턴인지, 그리고 지금 리팩토링이 적절한지 설명드립니다.
-
왜 안티패턴인가?
- 책임 범위가 명확하지 않아 재사용·테스트·유지보수가 어려워집니다. (UI: 입력을 받아 표시, 도메인: 검색/filter 처리, side-effect: debouncing 등을 분리해야 함)
- 컴포넌트가 상태와 로직 모두를 담당하면 파일 단위 변경이 많아져 삭제/이관/테스트 시 비용이 커집니다.
- 특히 debounce, 로컬 저장소 동작, 검색 알고리즘(필터 기준)은 재사용 가능한 훅/모델로 분리하는 편이 좋습니다.
-
지금 PR에서의 처리(현상)
- App에서 searchTermAtom을 쓰도록 변경했고 ProductList는 debouncedSearchTerm을 사용하여 필터링합니다.
- 검색 입력은 presenter(App 헤더)에서 setSearchTerm으로 처리 — 적절한 분리입니다.
-
권장 개선
- Debounce는 presenter(헤더) 대신 domain hook(useSearch) 또는 view hook(useDebounce + useAtom)에 둘 것을 권장합니다. 이유: presenter가 debounce 타이밍을 결정하면 테스트/재사용성 저하.
- 검색 조건(어떤 필드를 검사할지)이나 필터 전략은 모델 계층(search model)에 두어 테스트 가능한 순수 함수로 유지하세요.
- 요약: 현재 리팩토링 방향(검색어를 atom으로 옮긴 것)은 옳습니다. debounce를 담당하는 부분의 위치(훅 vs presenter)를 명확히 규정하면 더 좋습니다.
질문에 대한 구체 예시 (AS-IS vs TO-BE)
-
AS-IS (앱 내에서 직접 처리)
- App.tsx: <input onChange={e => setSearchTerm(e.target.value)} />
- ProductList: useDebounce(searchTerm, 500) → filterProducts(...)
-
TO-BE (권장)
- useSearch hook:
- exports: searchTerm, setSearchTerm, debouncedSearchTerm
- 내부: setAtom(searchTermAtom) + local debounce effect
- App 헤더: onChange -> setSearchTerm (hook 제공)
- ProductList: useSearch().debouncedSearchTerm -> filterProducts
- useSearch hook:
이렇게 하면 debounce 구현이 한 곳에 모여 테스트/조정이 쉬워집니다.
종합 피드백 (핵심 키워드)
- 상태관리 전역화: jotai 도입 (atoms + action atoms)
- 도메인 분리: models/* (cart, product, coupon) — 순수 함수 중심
- 훅/액션: hooks/useCart/useProducts/useNotifications — UI와 도메인 분리
- 컴포넌트 분리: AdminPage / CartPage / admin/* / cart/*
- UI 컴포넌트: Toast, Icon, etc.
- 테스트 변경: Provider로 렌더 감쌈
- 코드량 증가 & 파일 분산: 장점(모듈화)과 단점(탐색 비용) 공존
- 개선 대상: atoms 간 의존성, 공개 API(패키지화 시의 경계), 일부 훅/액션의 과다 노출
PR 본문(셀프회고)에 대한 피드백 (인사이트 중심)
-
좋은 시도
- 계산(순수함수)과 액션(부수효과)을 분리하려는 의지와 구체적 함수 분해(calculateItemTotal 등)는 매우 훌륭합니다.
- 핸들러 전략(비즈니스 로직은 훅, UI 핸들러는 컴포넌트)은 실무적으로도 바람직합니다.
- props drilling에 대한 고민(삭제 복잡성, 테스트 모킹 비용)은 아주 실전적인 관찰입니다.
-
더 생각해볼 질문 (다음 인사이트로 이어지는 질문)
- "핸들러는 어디까지 훅이 책임져야 하는가?" — 트랜잭션 경계(로깅/추적/원자성)까지 훅에 둘 것인지?
- "도메인 모델을 패키지화할 때 public API는 무엇인가?" — 순수함수(계산)만 export하고 상태/atom은 내부에 감추는 방식이 안전합니다.
- "지금의 분리로 인해 오히려 파일 수/아키텍처 복잡성이 증가한 지점은 어디인가?" — 추적 비용을 줄이는 폴더 레이아웃/README가 필요합니다.
- "액션(알림, 로컬스토리지 등) 테스트는 어떻게 설계할 것인가?" — adapter/port pattern을 고려해 보세요.
-
전체 코멘트 요약: 방향성과 선택이 명확하고 대부분 합리적입니다. 다음 단계는 '경계(interfaces)'를 명확히 하고 액션/외부 의존을 어댑터로 추상화하는 것입니다.
상세 피드백 — 개념 정의 & 문제 제시 → AS-IS / TO-BE
먼저 핵심 개념 정의(요청하신 대로)
-
응집도(cohesion)
- 정의(요청하신 규칙을 반영): 한 파일/모듈이 변경되어야 할 때 관련된 수정(파일 추가/수정/삭제)의 동선이 얼마나 짧은지, 그리고 해당 모듈을 라이브러리로 잘 떼어낼 수 있는지를 나타내는 척도.
- 높은 응집도: 단일 책임을 가진 모듈, 변경 시 관련 코드가 같은 모듈 또는 명확한 경계 내부에 존재.
- 낮은 응집도: 관련 책임이 흩어져 있어 변경 시 여러 파일/폴더를 건드려야 함.
-
결합도(coupling)
- 정의: 두 모듈(함수/컴포넌트/훅)이 얼마나 직접적으로 서로 내부 구현에 의존하는가. 낮을수록 좋음.
- 낮은 결합도는 "인터페이스/계약"을 통해 상호작용 하는 것(예: onSuccess/onError 콜백, 서비스 인터페이스)으로 달성.
이제 PR 코드에 대해 문제 정의 → AS-IS → TO-BE 방식으로 피드백합니다.
1) 상태관리 라이브러리 교체 시나리오 (예: Jotai -> Zustand / Redux / TanStack Query / Context)
핵심: 상태 접근 패턴(직접 atom 사용 vs 훅 래핑)에 따라 이식 비용이 크게 달라집니다.
-
문제(AS-IS)
- current: atoms가 직접적으로 모델/컴포넌트/훅에 퍼져 있음. 훅(useCart/useProducts/useCoupons 등)은 내부에서 atoms를 직접 사용하지만 동시에 atom의 일부(setters)도 반환하거나 노출함.
- 결과: 다른 상태관리 라이브러리로 바꾸려면 atoms를 사용하는 파일(대부분 훅과 액션 파일)을 전부 바꿔야 할 가능성이 큼.
-
영향 시나리오별 변화 예측
-
Jotai → React Context + useReducer (간단)
- 바뀌는 부분: atoms 정의를 Provider + reducer로 변환. useSetAtom / useAtom 호출을 useContext/useDispatch로 바꾸는 작업 필요.
- 수정 범위: atoms/atomsAction/*.ts + hooks에서 atom 호출을 사용하는 부분.
- 난이도: 중 (원칙적으로는 중앙화된 reducer/Context로 재구성 가능)
-
Jotai → Zustand
- 바뀌는 부분: 상태를 create()로 옮기고 액션을 store 내 함수로 변환. 훅은 useStore로 대체.
- 장점: Zustand는 API가 간단해서 hook 적응이 쉬움.
- 난이도: 낮~중. 그러나 atom 단위 의존성이 많으면 변환 지점이 복잡.
-
Jotai → Redux (Toolkit)
- 바뀌는 부분: slice/action/reducer로 전환, dispatch 호출로 변경.
- 난이도: 중~상 (중앙화와 미들웨어 도입 고려)
-
Jotai → TanStack Query
- 적합성: 캐싱/비동기 서버 state에 적합. 로컬 UI state(검색어, 폼 등) 전부를 대체하기엔 부적절.
- 난이도: 낮 (서버 상태 전용), 그러나 전체 전환은 권장X
-
-
권장적 준비(TO-BE: 이식성 높이는 구조)
- 훅 레벨의 Adapter 패턴 사용: 모든 컴포넌트는 atoms를 직접 사용하지 않고 훅(useCart/useProducts 등)만 호출.
- atoms를 훅 내부 구현으로 숨김 → 향후 상태관리 교체 시 훅 내부만 수정하면 됨.
- 예시(AS-IS vs TO-BE)
AS-IS (hooks가 atoms를 직접 노출)
// src/advanced/hooks/useCart.ts (AS-IS 단편)
const [cart, setCart] = useAtom(cartAtom);
return { cart, setCart, addToCart, ... };TO-BE (추상화된 인터페이스만 노출)
// src/advanced/hooks/useCart.ts (TO-BE 단편)
export const useCart = () => {
// 내부는 어떤 상태관리든 사용 가능 (atom / zustand / redux)
const cart = useCartStore((s) => s.cart);
const addToCart = useCartStore((s) => s.addToCart);
return { cart, addToCart /* 읽기 전용, 행동만 노출 */ };
};- 이렇게 바꿔두면 Zustand/Redux로 전환할 때 useCart 내부 구현만 바꾸면 됨.
2) 패키지화(모듈화) 시나리오 — "패키지로 잘 떼어낼 수 있는가?"
핵심 검토 포인트: 응집도(수정 동선), 공개 API(무엇을 노출할지), 외부 의존성(React/atom/DOM 등) 분리.
-
현재 구조(AS-IS에서 관찰되는 장단점)
- 장점
- models/* 에 순수함수(계산)가 모여 있어 잘 추출 가능 (high cohesion for models).
- components/* 는 UI에 집중 (Presenter / Container 구분 시도가 보임).
- hooks/* 은 도메인 액션을 묶어놔서 재사용 가능.
- 단점
- atoms 폴더(appAtoms.ts)에는 UI/도메인/notification 등 다양한 상태가 섞여 있음 → 응집성 저하(여러 책임).
- action atoms(예: cartActions.ts)와 hooks가 상호 참조하는 부분이 많음(결합도 증가).
- models에 localStorage 같은 side-effect가 있으면 추출 어려움(현재 atomWithStorage로 저장됨 — 좋긴 하지만 패키지화 전 명확화 필요).
- 장점
-
패키지화 TO-BE 권장
- Domain 패키지(예: @your-org/cart-domain)
- 포함: models/cart.ts (순수 함수), types, domain-level hooks (순수 비즈니스 로직, 상태 독립적) — 상태는 외부에서 주입(inject) 가능
- 공개 API: calculateCartTotal, getRemainingStock, addItemToCart (pure functions)
- 금지: DOM/React 의존성, UI 컴포넌트, atom 직접 노출
- State adapter 패키지(예: @your-org/cart-jotai-adapter)
- 포함: atoms, atom-actions, jotai-specific hooks(useCart that uses atoms)
- 공개 API: useCart (React hook)
- 책임: domain 패키지의 기능을 상태관리 라이브러리(Jotai)에 바인딩
- UI 패키지(예: @your-org/cart-ui)
- 포함: Cart, CartItemView, Toast 등
- 의존: domain 패키지(계산 함수), state adapter(훅)
- benefits: 각각의 패키지는 응집도가 높고, adapter만 바꾸면 다른 상태관리 라이브러리로 대체 가능.
- Domain 패키지(예: @your-org/cart-domain)
-
예시: 패키지로 떼어낼 때의 TO-BE index 파일
// domain/index.ts (패키지로 배포할 API)
export { calculateCartTotal, calculateItemTotal } from './models/cart';
export type { CartItem, Product } from './types';// adapter-jotai/index.ts
export { useCart } from './hooks/useCart'; // 내부에 atom 사용3) 응집도/결합도 관점에서 현재 코드 평가 & 개선 포인트
-
응집도 평가 (요청하신 기준 활용)
- models (product, cart, coupon): 높은 응집도 — 계산 로직이 중앙에 모여 있고 순수 함수로 작성됨 → 추출 용이
- components/ui & components/admin : 높은 응집도 — UI 전용 컴포넌트로 분리됨
- atoms/actions: 응집도 혼재 — 하나의 atoms 파일(appAtoms.ts)에 다양한 상태가 들어있어 책임 분리가 필요
- 종합: 모델과 UI의 응집도는 좋으나 상태/액션의 응집도가 약간 떨어짐. 바꾸고자 하는 범위(예: 상태저장 방식) 변경 시 수정 동선이 atoms/atomsAction/hook들에 걸쳐 길게 퍼질 가능 있음.
-
결합도 평가
- 현재 구조의 강점: UI는 대부분 hooks(useCart/useProducts/useCoupons/useNotifications)를 통해 도메인에 접근 — 즉, 컴포넌트는 atoms를 직접 보지 않음 → 낮은 결합도 (컴포넌트 ↔ 훅은 명확한 인터페이스)
- 약점: hooks 내부가 atoms/actions를 직접 사용하면서 atoms 변경 시 hooks 전부 수정 필요 → hooks ↔ atoms 사이의 결합이 강함. 또한 action atoms가 messages/constants를 직접 사용(결합) — 메시지 교체/로컬라이징 시 파급 범위 큼.
-
개선 제안 (구체)
- 훅이 "상태관리 구현 세부사항"을 외부에 노출하지 않도록 개선
- 지금: useCart가 setCart 등 내부 setter를 반환. → TO-BE: 읽기 전용 값 + 행동 함수만 반환.
- atoms 파일 분해: appAtoms.ts(큰 파일)를 domain별로 분리
- e.g., atoms/cartAtoms.ts, atoms/productAtoms.ts, atoms/uiAtoms.ts
- 액션은 "서비스/유틸"로 추상화
- 현재: addToCartActionAtom 같은 atom이 내부 로직과 메시지까지 처리. → TO-BE: action은 domain 모델을 호출하고 NotificationService(또는 알림 훅)을 통해 알림을 발생.
- Notification 처리 인터페이스 도입 (의존성 역전)
- AS-IS:
set(addErrorNotificationActionAtom, '재고가 부족합니다');
- TO-BE:
// NotificationService 인터페이스 notificationService.error('재고가 부족합니다'); // hook 내부에서 주입하거나 useNotifications()로 래핑
- AS-IS:
- 훅이 "상태관리 구현 세부사항"을 외부에 노출하지 않도록 개선
AS-IS vs TO-BE 예시 — 알림 처리
- AS-IS (현재: 액션에서 직접 메시지 세팅)
// cartActions.ts (발췌)
if (remainingStock <= 0) {
set(addErrorNotificationActionAtom, ERROR_MESSAGES.STOCK_INSUFFICIENT);
return;
}- TO-BE (NotificationService 사용)
// notificationService.ts (인터페이스)
export const notificationService = {
error: (msg: string) => set(addNotificationActionAtom, { message: msg, type: 'error' }),
success: (msg: string) => set(addNotificationActionAtom, { message: msg, type: 'success' }),
};
// cartActions.ts
if (remainingStock <= 0) {
notificationService.error(ERROR_MESSAGES.STOCK_INSUFFICIENT);
return;
}- 이 방식은 메시지 전달 경로를 단일화하고, 나중에 메시징 구현을 바꾸거나 테스트할 때 mocking이 쉬워집니다.
구체적 코드 개선 제안(몇 가지 핵심 AS-IS / TO-BE)
- useCart 인터페이스 정제
- AS-IS (현재 일부 노출)
export const useCart = () => {
const [cart, setCart] = useAtom(cartAtom);
// setCart 노출됨
return { cart, setCart, addToCart, removeFromCart, ... };
}- TO-BE (권장)
export const useCart = () => {
const cart = useCartStore((s) => s.cart); // 내부는 어떤 스토어든 가능
const addToCart = useCartStore((s) => s.addToCart);
const removeFromCart = useCartStore((s) => s.removeFromCart);
return { cart, addToCart, removeFromCart }; // setCart는 내부로 숨김
}- actions을 Hook에서 노출하는 패턴 통일
- AS-IS: Hooks와 action-atoms가 혼재되어 있음. 어떤 훅은 actionAtom을 노출, 어떤 훅은 setState를 노출.
- TO-BE: 훅은 도메인 API(행동함수, 읽기값)만 공개. 내부에서 selector/atom를 활용.
- 테스트 편의성
- 좋은 점: tests에 Provider wrapping 추가한 건 적절합니다.
- 더 개선: useRender 헬퍼를 만들어 공통 Provider/Router/Theme 등을 주입하면 테스트마다 중복을 줄일 수 있습니다 (현재 변경사항에도 사용됨).
마무리 권장 작업 목록 (우선순위 포함)
- (우선) Hooks 추상화: useCart/useProducts/useCoupons가 상태관리 세부사항을 외부에 노출하지 않도록 리팩토링 — 교체 비용 대폭 감소.
- atoms 분리: appAtoms.ts → domain별 atoms 파일로 분리 (cartAtoms, productAtoms, uiAtoms).
- NotificationService 추상화: 메시지 소비/발행을 한 곳으로 모아 의존성 역전 적용.
- Debounce/search: useSearch 훅으로 debounce 로직 중앙화 및 테스트 가능성 확보.
- 패키지화 준비: domain(models, types, pure functions) vs adapter(atoms/hooks) vs ui(components)로 레이어 분리 후 public API 문서화.
- 문서화: 각 folder(모델, atom, hook, component)의 책임을 README로 정리 — 팀원/기여자 탐색 비용 감소.
PR 본문의 "리뷰 받고 싶은 것" — 검색창 안티패턴에 대한 직접 답변 요약
- 네, 검색 로직이 컴포넌트에 직접 포함되어 있으면 재사용/테스트/삭제 시 비용이 큽니다.
- 현재 PR은 검색어를 atom으로 옮기고 ProductList에서 debounced 검색어를 사용하도록 바꾼 상태로, 안티패턴을 해소하려는 좋은 방향입니다.
- 다만 debounce 로직을 presenter(헤더) 대신 useSearch 훅으로 이동시키고, 컴포넌트는 입력/표시만 담당하게 하면 더 깔끔합니다.
마지막으로 전반적 평:
- 아키텍처 전환(단일 파일 → 모듈화, Jotai 도입)을 통해 얻은 장점이 크고, 도메인 모델을 순수함수로 분리한 점은 매우 훌륭합니다.
- 다음 단계는 "경계(boundary)"를 더 명확히 하고, 상태관리 어댑터를 마련하여 향후 라이브러리 변경이나 패키지 배포 시 최소한의 수정으로 교체되도록 준비하는 것입니다.
원하시면:
- useCart/useProducts 등 핵심 훅을 어떻게 인터페이스만 남기고 구현을 숨길지 구체적으로 리팩토링한 코드 예시(파일 단위)를 제공해 드리겠습니다.
- 또는 Jotai → Zustand(혹은 Redux) 전환을 위한 구체적 변환 스텝/스크립트 예시를 만들어 드릴 수 있습니다.
원하시는 다음 작업을 알려주세요.
배포 주소
https://ldhldh07.github.io/front_6th_chapter2-2/
과제의 핵심취지
과제에서 꼭 알아가길 바라는 점
기본과제
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는 잘 제거했나요?
전체적으로 분리와 재조립이 더 수월해진 결합도가 낮아진 코드가 되었나요?
과제 셀프회고
이번 과제는 보다 폭넓게 클린코딩을 해야했던 지난과제와 달리 명확한 방향성을 알려주었습니다.
그 방향성에 철저하게 맞춰서 개발을 하는 것을 목표로 했습니다.
특정 스타일, 팀의 컨벤션에 맞춰서 개발을 해야하는 경험 또한 좋은 경험이라 생각합니다.
그런 관점에서 과제 자료에 있는 요청사항이나, refactoring(hint)폴더의 구조도 그대로 따르고자 했습니다.
과제를 하면서 내가 알게된 점, 좋았던 점은 무엇인가요?
과제에 대한 설명을 해주시면서 반복해서 강조한 지향점이 있었습니다.
함수형 코딩의 장점을 강조하면서도,
'프론트엔드 개발에서 지나치게 함수형 코딩에 과몰입하는 것은 부작용이 있다'라는 경계를 가지고 있었습니다.
실제로 잘못됐다고 알려진 패턴들을 의도했든 의도치 않았든 하고 났을 때 배운 게 많았습니다.
좋은 쪽으로든 나쁜 쪽으로든 실제로 해보고 직접 느껴야 한다 생각하고 이번에도 이런 것을 느끼고자 했습니다.
기본 딘어 개념
먼저 관련된 단어의 개념을 확실히 하고 싶었습니다.
관련해서 몇가지 단어들이 혼란스럽게 쓰였습니다
계산 (Calculation) vs 액션 (Action)
모델 (Model) vs 엔티티 (Entity)
도메인 (Domain)
순수 함수 - 예측 가능한 함수
부수 효과 = 외부 세계 변화
이번 과제에서 내가 제일 신경 쓴 부분은 무엇인가요?
순수 함수 영역 늘리기
계산과 액션, 엔티티를 다루는 함수와 그렇지 않은 함수를 구분하는 것에 신경을 많이 썼습니다.
발제 자료도 반복해서 읽어보고 적용해보려는 시도를 했습니다.
그래서 다른 형식의 리팩토링에는 드는 수고와 시간을 줄이고 위 내용에 대한 고민을 하는 데에 기력을 집중했습니다.
순수 함수를 최대한 쪼개고 도메인 요소, 부수 효과가 일어나는 동작을 최대한 논리적으로 후반부 영역에서 일괄적으로 처리하고자 했습니다.
명쾌하게 답을 냈다는 느낌은 못받았습니다. 하지만 과정을 반복하면서 느낀 점이 있습니다
순수 함수를 독립했을 때 책임이 명확해지고 더 추적이 명료해진다는 것입니다.
코드를 이해하거나 디버깅을 해야할 때 함수형 코딩이 필요하다 이야기되는 이유를 체감할 수 있었습니다.
핸들러 함수 전략
핸들러 함수를 어디에 위치할지 여러 경우의 수가 떠올랐습니다.
선택- UI 컴포넌트
최대한 분리하자는 과제의 취지에 맞춰서 훅으로 분리할까 싶었습니다.
일단 분리는 함수쪽에서 집중적으로 하고 다른 영역에서는 기존에 추구하던 방향으로 개발을 해서 컴포넌트에 핸들러를 구현했습니다.
UI 이벤트를 처리하는 핸들러는 UI 컴포넌트의 책임입니다.
그렇기 떄문에 컴포넌트와 물리적 거리가 멀어져서는 안된다 생각합니다.
다만 내부에서 동작하는 비즈니스 로직들이 데이터를 조작하는 경우에는 그 동작들을 훅으로 빼어서 핸들러 내부에서 동작하게끔 설계했습니다.
대신 렌더링과 최적화의 관점에서 핸들러가 매번 생성되지 않도록 조절하기 위한 고민은 필요하다 생각됩니다.
props drilling
프롤 드릴링 지지협회의 일원으로서 기본과제의 주제는 흥미로웠습니다.
사실 아직 props drilling의 단점을 제대로 못느껴봐서 문제라고 생각 못하는 것이라고 생각이 있었습니다.
단순히 가독성면, 귀찮은 면에서는 이번 과제를 하면서도 여전히 문제점보다는 장점이 많다 생각이 들었습니다.
손이 많이 가긴 하지만 인지 부하가 들지 않는 단순한 타이핑이라서 데이터 흐름을 명시하고 작성하면서 그걸 파악할 수 있는 점은 좋았습니다.
다만 새롭게 고려해본 관점들이 있었습니다.
이는 새롭고 실효적이다 싶은 문제점들이었습니다.
동시에 아직까지는 많이 겪어보지 못한 일이었습니다.
어느 기능을 삭제해야할 때 수월하게 삭제할 수 있어야 한다.
이 이야기는 새롭게 클린코드를 바라볼 수 있는 관점이었습니다.
작성/해석의 관점에서의 편의성만 보던 입장에서와는 또 다른 요소를 따져봐야했습니다.
만약 전역상태관리를 적용하기 전에 addNotification이 관련된 로직을 제거해야 한다고 했으면
컴포넌트 분리도에 따라 다르지만 거의 모든 컴포넌트에 접근해서
전부 접근해서 수정해야 합니다.
테스트 가능성에 대한 이야기도 와닿았습니다.
props drilling이 있을 경우
mock의 경우에는 최대한 간단하게 최소한의 구현만으로 수행하는 것이 관건이라고 생각합니다.
그런 점에서 위 경우처럼 불필요한 과정이 소모된다는 것은 치명적이라 느꼈습니다
jotai 적용시
반면 jotai는 불필요한 모킹데이터를 prop으로 주입해주지 않아도 테스트가 가능하다.
이런 문제점들을 과제를 하면서 느꼈습니다.
실제 개발을 하면서는 테스트 경험도 많이 없고 이미 있는 기능을 삭제해야하는 경험이 없었습니다.
이런 경험들을 더 큰 규모, 더 복잡한 상황에서 해보고 싶다는 욕심이 생겼습니다. 실제 서비스에서 이런 차이가 어떤 구체적인 생산성 향상으로 이어지는지 경험해보고 싶습니다.
이번 과제를 통해 앞으로 해보고 싶은게 있다면 알려주세요!
디자인 패턴 중 Decorator 패턴을 간단하게나마 경험해봤습니다.
멘토링 중 코치님이 작성한 코드를 통해서도 접했습니다.
이 패턴을 통한 코드 작성에 익숙해진다면 더 좋은 코드를 작성할 수 있을 것 같아서 활용해보고 싶다 느꼈습니다.
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
코드 내부에 검색창의 로직이 컴포넌트에 있는 안티패턴
이런 주석이 달려있어서 단순히 인라인에 있는 것을 분리했습니다.
해당 안티패턴에 대해 정확히 이해한 느낌이 아니여서 관련해서 리뷰받아봤으면 합니다.