heojungseok 님의 상세페이지[5팀 허정석] Chapter 2-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과 라이브러리 훅과의 계층의 성격이 다르다는 것을 이해하고 적용했는가?

  • 엔티티 순수함수와 유틸리티 함수의 계층의 성격이 다르다는 것을 이해하고 적용했는가?

과제 셀프회고

과제 배포

이번 5주차 과제는 지난 회고 에서 언급했던 Try 부분과 지난 주차에서도 사용했던 history 를 남기는 방식을 함께 진행해봤습니다.

image

과제 진행 요약

  • 전체 방향
    • SRP 기반 계층 분리: 계산/검증은 utils/*, 도메인 로직은 services/*, 상태·흐름은 hooks/*, 렌더링은 components/*
    • 점진 리팩터링과 테스트/트러블슈팅 병행

타임라인

  • 08/04 기본 리팩터링

    • 계산 분리: utils/calculators.ts(아이템 합계, 최대 할인, 카트 합계)
    • 검색 분리: utils/filters.ts
    • 타입 정리: types.ts(뷰/엔티티 타입 구분)
    • 함수 합성, 상수화, 순수함수 원칙 정립
    • 테스트 에러 해결 및 통과
  • 08/05 훅/서비스 분리

    • 공용 훅: useLocalStorage, useNotifications, useDebounce
    • 도메인 훅+서비스: useCoupon+couponService, useProducts+productService, useCart+cartService/validators
    • 의존성 주입, 단일 책임 강화
    • UI 상태 훅: useUIState, useCouponForm(소유권 충돌 해결)
    • 버그 해결: 편집 핸들러, 쿠폰 합계 반영
  • 08/06 컴포넌트 분리(Middle-Out)

    • CouponManagementCouponForm/CouponCard/AddCouponButton
    • ProductManagementProductForm/ProductTable/AddProductButton
    • 디렉터리 도메인화: components/pages/admin/*, components/pages/shopping/*
    • App.tsx 간소화 계획 수립
  • 08/08 고급 단계(Jotai)

    • 전역 상태 일원화: atoms/*(cart/product/coupon/ui/notification)
    • 파생 atom 도입(예: cartTotalsAtom), 액션 atom 적용
    • Props Drilling 대폭 감소, 포맷/검색 관련 버그 수정

AI시대 개발자가 인간 클립보드 되지 않는 법

내가 설정한 커서 룰

description: 'AI 강사 역할 및 프로그래밍 가이드라인 - React, TypeScript, 클린코드 교육을 위한 7가지 원칙' globs: ['src//*.tsx', 'src//*.ts'] alwaysApply: true

AI Instructor Role and Programming Guidelines

Role

  • You are an instructor who systematically teaches React, TypeScript, and Clean Code to students.
  • Prioritize student learning and growth, providing clear and easy-to-understand explanations step by step.

7 Principles of AI Programming

  1. Verification and Understanding: Don't blindly trust AI results. Always verify them. Ask yourself: "Why does this solution work? What are its limitations?"

  2. Maintain Fundamentals: Don't lose basic coding skills. Set aside one "No-AI Day" per week for manual coding mode.

  3. Self-Directed Learning: Try on your own before depending on AI. Spend 15-30 minutes researching and planning solutions before seeking AI help.

  4. Quality Management: Review AI code like human code. Foster a culture where "AI creates drafts, but ownership belongs to us."

  5. Active Learning: Don't just receive answers, understand them. Explain complex concepts in simple terms or ask "Why don't other approaches work?"

  6. Knowledge Management: Record and improve areas where AI helped. Follow the principle that "AI should be the last resort."

  7. Collaborative Relationship: Treat AI as a partner while maintaining control. Use AI as a pair programming partner, not just a query tool.

Educational Principles

React Education

  • Teach component-based thinking systematically
  • Clearly explain the importance and patterns of state management
  • Focus on performance optimization and best practices in real-world scenarios

TypeScript Education

  • Explain the importance of type safety with concrete examples
  • Teach gradual type application methods step by step
  • Present methods for improving development productivity using the type system

Clean Code Education

  • Explain the Single Responsibility Principle (SRP) with practical examples
  • Emphasize functional programming and the importance of pure functions
  • Systematically teach the necessity and methods of refactoring

Conversation/Explanation/Feedback/Code Review Standards

  • Emphasize step-by-step approach, practical examples, visual explanations, and interaction
  • Provide specific and constructive feedback with positive reinforcement and growth motivation
  • Focus code reviews on readability, maintainability, type safety, performance, and testability
  • Delivers information following the principles of functional programming

My Coding Style

My coding style favors simplicity and clarity.
I prefer not to over-abstract functionality—keeping abstractions meaningful but not excessively granular.
I also prefer to modularize code that is reused across multiple parts of the application.

과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?

파일, 함수, 컴포넌트가 딱 한 가지 역할만 하도록 나누자!!!

UI(컴포넌트) ↔ 상태/이벤트(훅) ↔ 도메인 로직(서비스/유틸)의 경계를 명확히 하고, 전역 상태는 Jotai로 일원화해 Props Drilling을 제거

  • 순수함수/유틸 분리: 계산, 검증, 포맷을 utils/* 하위로 생성하여 테스트와 재사용성에 용이하게 만들었습니다.
  • 도메인 서비스 추출: productService, cartService, couponService 로 비즈니스 로직을 컴포넌트 밖으로 이동 시켰습니다.
  • Custom Hook 설계: useProduct, useCart 등으로 상태.절차 캡슐화를 하고 의존성 주입으로 결합도를 축소했습니다.
  • Middle-Out 컴포넌트 분리: CouponManagement, ProductManagement 처럼 복잡한 영역부터 점진적으로 분리했습니다.
  • Jotai 전환: atmos/* 와 파생 atom 으로 전역 상태 단일 소스화를 하여 Props Drilling 을 제거하고 Hook 독립성을 강화시켰습니다.
  • 테스트/트러블슈팅 중심: 실패 케이스의 원인 분석을 하여 요구사항에 맞는 프로젝트를 구현했습니다.
SRP: “한 파일/함수 = 한 역할”
재사용성: “한 번 만들면 여러 곳에서”
레이어: entities(순수함수/서비스) → features(훅) → UI(컴포넌트)

과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?

다음에는 services를 행동(use-case) 기준으로 재구성하고, 중복되는 도메인 규칙은 정책(policy)으로 상향 분리해 훅/컴포넌트의 책임을 줄여보는 방향으로 해보고 싶습니다.

사용자 행동(담기, 적용, 수정) 같은 use-case 단위로 묶으면 여러 컴포넌트·모듈·서비스가 협력하도록 조정하는 과정이 단순해지고, 테스트 부담도 줄어듭니다. 행동 레이어는 입출력과 흐름만 담당하고 로직은 도메인에 집중하므로, 책임 위치가 명확해져 유지보수가 더 용이해집니다.

그리고 아래는 공통 로직을 상위로 만들었을 때의 예시 구조입니다. (AI 활용)

src/
├─ application/
│  ├─ cart/
│  │  ├─ addItemToCart.ts
│  │  ├─ removeItem.ts
│  │  └─ updateQuantity.ts
│  ├─ product/
│  │  ├─ createProduct.ts
│  │  └─ updateProduct.ts
│  └─ coupon/
│     ├─ applyCoupon.ts
│     └─ removeCoupon.ts
├─ domain/
│  ├─ policies/
│  │  ├─ cart.ts       # canAddItem, calculateTotals
│  │  ├─ discount.ts   # getMaxApplicableDiscount
│  │  └─ validation.ts # validatePrice/Stock/Coupon
│  └─ models/          # 타입/엔티티
└─ shared/
   ├─ money.ts
   ├─ id.ts
   └─ date.ts

예시 기준

  • 2곳 이상 재사용 + 순수함수 + 도메인 언어로 설명 가능 → domain/policies/*

특정 도메인(예: 유저, 주문)에 관련된 로직이지만 여러 군데에서 공유될 수 있는 정책들

  • 완전 범용(도메인 무관) → shared/*

유틸함수 모음

  • 입출력이나 사이드이펙트 포함 → application/*에 유지

실제 외부와 연결되는 행동 코드들

주의점

  • 과도한 일반화 금지
  • 사이드이펙트 경계

리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)

리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문

  1. 구조/네이밍 위 예시 구조의 application/cart/addItemToCart.ts처럼 “도메인/동사+목적어” 네이밍과 디렉터리 구조가 적절한지 또는 다른 컨벤션 예시가 궁금합니다. “한 파일 = 한 행동” 원칙에서 복잡한 행동(검증·계산·여러 정책 조합)의 분기 처리는 어디까지 application/* 에 두는 게 좋을지 의견이 궁금합니다.
  2. 정책 상향 기준 “재사용 ≥ 2, 순수성, 화면 무관 설명 가능”이면 domain/policies/*로 승격한다는 기준이 충분할까요? 더 추가/수정할 항목이 있을까요?

과제 피드백

안녕하세요 정석님! 이번 과제도 너무 잘 진행해주셨네요 ㅎㅎ 고생하셨습니다!!

위 예시 구조의 application/cart/addItemToCart.ts처럼 “도메인/동사+목적어” 네이밍과 디렉터리 구조가 적절한지 또는 다른 컨벤션 예시가 궁금합니다.

지금 모습도 적절하다고 느껴져요 ㅎㅎ 저의 경우 별도의 파일로 분리하기보다 그냥 한 파일에 묶어서 cartUseCase.ts 처럼 표현할 것 같아요!

const cart = useCartUseCase();
const cart.add();

요로코롬!?

아니면 CQRS Pattern 이라고 해서, 조회와 추가/수정/삭제 를 아예 분리하는 방법도 있답니다.

const cartData = useCartQuery();
const cartCommand = useCartCommands();

cart.add();

이렇게 분리하는 이유는 "렌더링" 때문인데요, 커맨드는 데이터를 의존하지 않도록 만들 수 있기 때문에 커맨드를 아무데서나 사용해도 리렌더링의 여파가 없어요.

그런데 데이터의 경우 변이되는 순간 렌더링이 전파되어야 하기 때문에, 이 데이터를 쓰는 곳을 명확하게 분리하는거죠.

“한 파일 = 한 행동” 원칙에서 복잡한 행동(검증·계산·여러 정책 조합)의 분기 처리는 어디까지 application/* 에 두는 게 좋을지 의견이 궁금합니다.

어디까지라기보단... 한 파일 = 한 행동 이라는 규칙을 만들었다면 그냥 다 한 파일로 만들어서 분리해야한다고 생각해요 ㅎㅎ 그래야 일관성있지 않을까요? 여기에 조건들 두면 더 복잡해진다고 생각해요

“재사용 ≥ 2, 순수성, 화면 무관 설명 가능”이면 domain/policies/*로 승격한다는 기준이 충분할까요? 더 추가/수정할 항목이 있을까요?

이정도면 충분하다고 생각해요! 저는 "다른 프레임워크에서 혹은 서버와 공유할 수 있음" 이라는 조건을 하나 더 붙일 것 같아요 ㅎㅎ 순수한 ECMAScript Spec 으로 작성이 되어있다면 충분히 가능하답니다!