Skip to content

[1팀 이의찬] Chapter 2-1. 클린코드와 리팩토링 #37

Open
Legitgoons wants to merge 66 commits intohanghae-plus:mainfrom
Legitgoons:main
Open

[1팀 이의찬] Chapter 2-1. 클린코드와 리팩토링 #37
Legitgoons wants to merge 66 commits intohanghae-plus:mainfrom
Legitgoons:main

Conversation

@Legitgoons
Copy link

@Legitgoons Legitgoons commented Jul 28, 2025

과제 체크포인트

배포링크

https://legitgoons.github.io/front_6th_chapter2-1/

기본과제

  • 코드가 Prettier를 통해 일관된 포맷팅이 적용되어 있는가?
  • 적절한 줄바꿈과 주석을 사용하여 코드의 논리적 단위를 명확히 구분했는가?
  • 변수명과 함수명이 그 역할을 명확히 나타내며, 일관된 네이밍 규칙을 따르는가?
  • 매직 넘버와 문자열을 의미 있는 상수로 추출했는가?
  • 중복 코드를 제거하고 재사용 가능한 형태로 리팩토링했는가?
  • 함수가 단일 책임 원칙을 따르며, 한 가지 작업만 수행하는가?
  • 조건문과 반복문이 간결하고 명확한가? 복잡한 조건을 함수로 추출했는가?
  • 코드의 배치가 의존성과 실행 흐름에 따라 논리적으로 구성되어 있는가?
  • 연관된 코드를 의미 있는 함수나 모듈로 그룹화했는가?
  • ES6+ 문법을 활용하여 코드를 더 간결하고 명확하게 작성했는가?
  • 전역 상태와 부수 효과(side effects)를 최소화했는가?
  • 에러 처리와 예외 상황을 명확히 고려하고 처리했는가?
  • 코드 자체가 자기 문서화되어 있어, 주석 없이도 의도를 파악할 수 있는가?
  • 비즈니스 로직과 UI 로직이 적절히 분리되어 있는가?
  • 코드의 각 부분이 테스트 가능하도록 구조화되어 있는가?
  • 성능 개선을 위해 불필요한 연산이나 렌더링을 제거했는가?
  • 새로운 기능 추가나 변경이 기존 코드에 미치는 영향을 최소화했는가?
  • 코드 리뷰를 통해 다른 개발자들의 피드백을 반영하고 개선했는가?
  • (핵심!) 리팩토링 시 기존 기능을 그대로 유지하면서 점진적으로 개선했는가?

심화과제

  • 변경한 구조와 코드가 기존의 코드보다 가독성이 높고 이해하기 쉬운가?
  • 변경한 구조와 코드가 기존의 코드보다 기능을 수정하거나 확장하기에 용이한가?
  • 변경한 구조와 코드가 기존의 코드보다 테스트를 하기에 더 용이한가?
  • 변경한 구조와 코드가 기존의 모든 기능은 그대로 유지했는가?
  • (핵심!) 변경한 구조와 코드를 새로운 한번에 새로만들지 않고 점진적으로 개선했는가?

과제 셀프회고

기본 과제 진행 과정
심화 과제 진행 과정

이번 과제 진행기,,

  • 이번주는 AI를 적극적으로 도입해서 사용해보았습니다. 1주차보다 2주차에서, 2주차보다 3주차에서, 그리고 3주차보다 이번 주차에서 더 AI를 적극적으로 사용하게 되었네요.
  • 우선 ESlint와 Prettier를 설정하고 나서, Cursor Rules(토스 펀더멘탈과 도은님이 디스코드에 올려주신 Rule 사용)를 세팅했고,,, 이 다음에 어떻게 해야할지 막막해서 다른 분들이 어떻게 하는지 여쭤보러 다녔습니다.
  • 성진님과 지훈님이 AI에게 docs를 참조해서 개선이 필요한 포인트를 mark down으로 작성시킨 후 진행하고 있다. 라고 하시더라구요. 바로 따라해서 도입했습니다.
    • 이 부분이 정말 좋았는데, 과제를 하는 동안 늘 Task 분리가 어려워서 고생했었거든요. 추후에도 계속 사용하려고 합니다.
    • 물론 과제의 상세한 요구사항과 클린코드에 대한 지침이 충분해서 가능했을테니, 좀 더 요구사항과 명확한 지침 작성의 중요성을 느꼈습니다.
  • 단계별로 나눠둔 checklist를 포함한 문서를 작성해주자, 이를 기반으로 다시 AI에게 코딩을 시켰습니다.
    • 그렇다고 무지성 바이브코딩은 안되니까, 코드를 작성하기 전에 이 코드를 작성했을때의 장점과 단점이 뭔지 작성하도록 시켰고, 이해가 잘 안가면 다시 되물어보면서 해당 작업이 필요여부를 판단하려고 했습니다. 작업이 필요하다면 해당 작업을 진행하고, 문서를 업데이트 한 후 커밋하도록 했습니다.

AI를 적극적으로 사용하고 느낀 점

1. 확실히 AI를 쓰면 코딩할 때 편하다.

  • AI를 사용하는 동안에는 제가 생각을 덜해도 됩니다. 코드를 귀찮게 하나하나 읽으면서 이해하지 않아도 되고, 또 직접 수정할 필요도 없었습니다. 제가 할 일은 AI한테 일을 어떻게 해야할지 생각하고, 그에 따라서 진행하라는 명령 뿐이였습니다.
  • AI를 사용해서 나아가는 길은 편했습니다. 전기 자전거를 요즘 자주 타는데요. 페달을 살짝만 밟아도 슝슝 나갑니다. AI를 사용해서 코딩을 할 때마다 전기 자전거를 떠올리곤 합니다. 약간의 노력만 해도 적절하게 보이는 코드를 쭉쭉 만들어주니까요.
  • 이런 경험을 하면서, 테오가 말한게 생각났습니다. 인간은 편리함을 맛본 뒤에는 못돌아가는 존재다라는 말이요. 앞으로 AI 없이 코딩을 하는 미래는 없을 것이라는 생각이 더 확고해졌습니다.

2. 하지만 AI를 사용하는게 정말 생산성을 높이는지는 잘 모르겠다.

  • 제가 위에 적절하게 보이는 코드를 만들어준다. 라고 적은걸 눈치채셨나요?
  • 전기 자전거 예시를 들어서 말인데, 전기 자전거는 모터가 있어서 일반 자전거보다 훨씬 무겁습니다. 만약 자전거가 갈 수 없는 길이거나, 배터리가 떨어지거나, 고장이 난다면? 그냥 커다란 짐덩이가 되는거죠.
  • AI로 코딩하는 것도 마찬가지인데, 얘가 내 명령을 이해하지 못하거나, 제대로 코드를 작성하지 못하면 결국 사람이 직접 코드를 작성해야합니다. 그때까지 제대로 확인하지 않았던 코드를 가지구요.
  • 이번 과제에서도 이 부분을 실감할 수 있었습니다. 처음에는 무서워서 ask로만 쓰다가, agent 모드를 조금씩 써보다가, 나중에는 그냥 기능 구현 전에만 확인하도록 했거든요. 그렇게 슝슝 나가다보니 어느 순간부터 얘가 코드에 똥칠을 하고 있더라구요.
  • 정확히는 심화 과제인 React로 마이그레이션 하는 작업에서 개판이 났는데, 지금 생각해보니 얘한테 정확히 어떤 작업을 해달라고 명시하지 않고 그냥 React로 마이그레이션해줘라고 대충 명령했던게 가장 큰 원흉이였던 것 같습니다.
  • 결국은 열심히 AI를 두들겨패서 어떻게 해내긴 했는데, 다음 과제에서는 지금보다는 AI 사용 비율을 낮추려고 합니다. 일단 task를 가능한 나눠서 먹이는건 당연하고, 매 commit 전에는 AI가 작성한 코드를 리뷰하고 넘기는 식으로 해볼까합니다.
  • AI가 잘 못하는것도 많은 것 같습니다. 코드에서 중복되는 부분을 찾아서 적절하게 추상화하는 거라든지,,

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

1. AI를 적극적으로 사용하기

  • 위에서 설명했듯이 이번 과제에서는 AI를 적극적으로 사용해보려고 노력했습니다.

2. 이해하면서 앞으로 나아가기

  • 3주차 과제에서는 우선 과제를 완료하고 그 후에 돌아보면서 코드를 이해해보자라고 생각하고 진행했는데, 막상 완료하고 나니까 자연스럽게 과제를 잘 안돌아보게 되더라구요. 그래서 이번 과제에서는 그냥 넘어가지 않고 매 부분마다 왜 필요한지 설명을 요구하고, 납득이 가면 진행하려고 노력했습니다.

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

1. 클린코드에 대한 생각을 정리하기

  • 어쨌건 클린코드 주차에서 어떤 코드가 클린하고, 어떤 코드가 클린하지 않은가를 경험적으로 느꼈다.
  • 하지만 어떤 코드가 클린하고, 어떤 코드가 클린하지 않으며, 어떻게 해야 안티패턴을 피하고 클린한 코드를 작성할 수 있는가? 에 대한 생각은 아직 정리하지 못해서 아쉽다.
  • 결론 -> 이번주 주말 안으로 블로그에 글을 올리겠습니다!!!!

2. Cursor 토큰 아껴쓰기

  • 컨텍스트가 쌓이면서 토큰이 엄청나게 들어갔고, 기본 과제를 마무리할 즈음에는 거의 다 토큰이 만료되었습니다. 결국 심화과제를 위해서 추가적으로 결제를 진행했어야 했습니다. 준일님 멘토링 시간에 토큰을 어떻게 아끼는지에 대한 질문이 나왔는데, 진작에 컨텍스트를 분리하면서 진행했다면 토큰을 아끼면서 진행할 수 있었을 것 같아 아쉽습니다.

3. 진작에 심화 과제에서 Task 나눠서 처리하도록 했어야

  • 심화 과제에서 Task를 제대로 나누지 않고 해줘를 했더니 기존 JavaScript 코드를 그대로 가져와서 React에서 DOM을 조작하는 방식을 전혀 사용하지 않고 그대로 갖다박았더라구요.
  • 바로 다시 다 엎어버리고, 요구사항을 추가해서 Task를 분리해달라고 요청했습니다.

4. React로 마이그레이션 하는 과정에서 좀 더 React스러운 코드란 무엇인가를 고려해서 추가했으면 좋았을 것

  • 엎은 후 다음 요구사항들을 추가해서 Task 분리를 진행했습니다.
    1. 로직은 훅, 화면은 JSX로 분리할 것
    2. 직접 DOM 조작 금지
    3. 도메인별로 상수/타입/컴포넌트 분리
  • 하지만 위 사항들이 정말 React스러운 코드를 작성하기 위해 충분한 지시였던 것은 아닌것 같습니다. 이에 규칙을 명확하게 나만의 언어로 작성해보고 싶습니다.

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

모두가 3주 내내 보던 코드였던 1챕터의 설정을 가져옴
as-is: 화요일만 할인 및 추가 적립되는 방식
to-be: 배열에 입력된 날짜에 따라 유연하게 할인 및 추가적립 적용 가능
- 재고 경고 메시지 생성 통합
- handleCalculateCartStuff와 handleStockInfoUpdate의 중복 로직 제거
- 하드코딩된 재고 임계값(5) → STOCK_THRESHOLDS.LOW_STOCK_WARNING 상수 사용
- 더 이상 사용되지 않는 handleStockInfoUpdate 함수 및 stockMsg 변수 제거
- 코드 라인 수 약 20줄 감소 및 일관성 향상
- var→const/let, parseInt radix, ++/-- 연산자, 중첩 삼항연산자 개선
- 장바구니 상태 캡슐화를 위한 useCartManager 객체 추가
- getTotalAmount(), getItemCount() getter 메서드 구현
- resetCart(), setCartTotals() 기본 메서드 구현
- main() 함수에서 초기화 호출 추가
- calculateCartTotals: 장바구니 아이템 총액/개수 계산
- calculateFinalAmount: 할인율 적용 및 최종 금액 계산
- updateCartCalculation: 전체 계산 실행 및 상태 업데이트
- 개별 상품 할인, 대량 구매 할인, 화요일 할인 로직 포함
- continue 문을 조건문으로 변경하여 linter 준수
- handleCalculateCartStuff에서 useCartManager.updateCartCalculation 사용
- doRenderBonusPoints에서 getTotalAmount(), getItemCount() 사용
- main 함수에서 전역 변수 초기화 제거
- 모든 totalAmt, itemCnt 사용처를 캡슐화된 메서드로 대체
- 사용하지 않는 전역 변수 선언 제거
- useCartManager 캡슐화 완료
- 장바구니 상태 관리가 완전히 캡슐화됨
- React Hook 패턴으로 변환 준비 완료
- 보너스 포인트 관리를 위한 useBonusPointsManager 객체 추가
- getBonusPoints(), setBonusPoints(), resetBonusPoints() 기본 메서드
- calculateBasePoints(): 구매액 기준 기본 포인트 계산
- calculateSpecialDayBonus(): 특별 날짜 보너스 계산
- React Hook 패턴 준비를 위한 구조 설계
- calculateComboBonus(): 키보드+마우스, 풀세트 콤보 보너스 계산
- calculateQuantityBonus(): 수량별 보너스 계산 (10개+, 20개+, 30개+)
- calculateAndUpdateBonusPoints(): 전체 보너스 포인트 계산 및 업데이트
- 각 보너스 유형별 상세 정보 반환 구조 설계
- 기존 doRenderBonusPoints 로직을 메서드로 분할
- useBonusPointsManager.calculateAndUpdateBonusPoints 활용
- 기존 80줄 복잡한 로직을 20줄로 간소화
- 모든 보너스 포인트 계산 로직이 캡슐화된 메서드로 이동
- UI 렌더링 부분만 함수에 남김
- 하위 호환성을 위해 bonusPts 전역 변수 유지
- 사용하지 않는 bonusPts 전역 변수 선언 제거
- useBonusPointsManager 캡슐화 완료
- 보너스 포인트 상태 관리가 완전히 캡슐화됨
- React Hook 패턴으로 변환 준비 완료
- updateCartItemStyles(): 장바구니 아이템 할인 스타일 업데이트
- updateSpecialDiscountDisplay(): 화요일 특별 할인 UI 표시
- updateItemCountDisplay(): 상품 개수 표시 업데이트
- handleCalculateCartStuff에서 UI 관련 로직 분리
- 단일 책임 원칙 적용으로 함수별 역할 명확화
- renderOrderSummaryDetails(): 주문 요약 세부 정보 렌더링
- updateTotalAndPointsDisplay(): 총액 및 포인트 표시 업데이트
- renderDiscountInfoPanel(): 할인 정보 패널 렌더링
- handleCalculateCartStuff에서 렌더링 로직 완전 분리
- 80줄 → 20줄로 대폭 간소화 (75% 감소)
- updateCartDisplay()로 함수명 변경 (의미가 더 명확)
- 80줄 거대 함수 → 10줄 간결한 함수로 대폭 간소화
- 비즈니스 로직과 프레젠테이션 로직 완전 분리
- 단일 책임 원칙 적용: 계산 → UI 업데이트 → 연관 컴포넌트 업데이트
- 모든 호출 지점을 새 함수명으로 업데이트
- 전역 변수명 개선: stockInfo→stockStatusElement, lastSel→lastSelectedProductId 등
- 함수명 개선: doRenderBonusPoints→renderBonusPointsDisplay 등
- DOM 요소 변수들을 const로 변경 (header, gridContainer, leftColumn, selectorContainer, rightColumn)
- renderBonusPointsDisplay 함수 선언 순서 조정으로 호이스팅 에러 해결
- ESLint no-use-before-define 규칙 준수
• basic.test.js → advanced.test.jsx 마이그레이션
  - React Testing Library 패턴으로 변환
  - DOM 조작 → React 컴포넌트 테스트 방식
  - screen.getByRole, screen.getByTestId 활용
  - userEvent setup() 패턴 적용

• PRD 명세와 100% 일치 확인
  - 상품 정보 (5개 상품, 가격, 재고, 할인율)
  - 재고 관리 (재고 부족/품절 표시)
  - 할인 정책 (개별/전체/특별 할인)
  - 포인트 시스템 (기본/추가 적립)
  - UI/UX 요구사항 (레이아웃, 컴포넌트)
  - 기능 요구사항 (CRUD, 실시간 계산)
  - 예외 처리 (재고 부족, 빈 장바구니)
• 상수 분리 (도메인별)
  - products/constants.ts: PRODUCT_IDS
  - discounts/constants.ts: DISCOUNT_RULES (products 의존성 포함)
  - stock/constants.ts: STOCK_THRESHOLDS
  - points/constants.ts: POINTS_RULES
  - sales/constants.ts: SALE_INTERVALS

• 타입 분리 (도메인별)
  - cart/types.ts: ICartItem, IItemDiscount, ICartCalculation, ICartItemData
  - discounts/types.ts: IDiscountData
  - points/types.ts: IBonusPointsResult

• 공통 모듈 정리
  - types/index.ts: IProduct만 공통 타입으로 유지 (여러 도메인에서 사용)

• 폴더 구조 최적화
  - 도메인 중심 아키텍처 완성

🎯 관심사 분리 완료: 각 도메인별 독립적 상수/타입 관리
• 0단계 완료 체크
  - ✅ 테스트 파일 마이그레이션 (basic.test.js → advanced.test.jsx)
  - ✅ React Testing Library 패턴 변환
  - ✅ PRD 명세와 100% 일치 확인

• 1단계 완료 체크
  - ✅ 도메인별 상수/타입 분리 완료
  - ✅ 공통 모듈 정리 (IProduct만 공통 유지)
  - ✅ 폴더 구조 최적화

• 다음 단계 표시
  - 🎯 2단계: Products 도메인 React 훅 변환
  - useProductData.ts 구현 준비
• useProductData 훅 구현
  - useState로 상품 목록 상태 관리
  - useCallback으로 메서드 최적화 (8개 메서드)
  - React setState 패턴으로 불변 업데이트
  - 기존 객체 패턴 → React 훅 패턴 변환

• ProductSelect 컴포넌트 구현
  - 상품 선택 드롭다운 (React 패턴)
  - 할인 상품 강조 표시 (⚡💝 아이콘)
  - 품절 상품 비활성화
  - 재고 부족 시 border 경고 표시
  - useMemo로 옵션 데이터 최적화

• React 패턴 적용
  - DOM 조작 → JSX 렌더링
  - addEventListener → onClick 핸들러
  - 직접 DOM 접근 → props/state 기반
  - 불변성 업데이트 보장

🎯 Products 도메인 React 마이그레이션 완료
• useCartManager 훅 구현
  - useState로 장바구니 상태 관리 (cartItems, totalAmount, itemCount)
  - useCallback으로 메서드 최적화 (12개 메서드)
  - React setState 패턴으로 불변 업데이트
  - 장바구니 CRUD 연산 (add, remove, update, reset)
  - 할인 계산 로직 (대량구매, 개별상품, 특별할인)

• CartDisplay 컴포넌트 구현
  - 장바구니 아이템 목록 렌더링
  - 개별 CartItem 컴포넌트 분리
  - 수량 증감 버튼 (+/- 컨트롤)
  - 할인 상품 강조 표시 (⚡💝 아이콘)
  - 상품 제거 기능

• OrderSummary 컴포넌트 구현
  - 주문 요약 정보 표시
  - 아이템별 소계 계산
  - 할인 정보 표시 (대량구매/개별상품/특별할인)
  - useMemo로 계산 최적화
  - data-testid 속성 추가

🎯 Cart 도메인 React 마이그레이션 완료
• usePointsManager 훅 구현
  - useState로 포인트 상태 관리
  - useCallback으로 계산 메서드 최적화 (8개 메서드)
  - React 패턴으로 콤보/수량/특별날짜 보너스 계산
  - ICartItem[] 배열 기반으로 DOM 의존성 제거

• useStockManager 훅 구현
  - 재고 경고 메시지 생성
  - 재고 부족/품절 상품 필터링
  - 재고 상태 확인 로직
  - IProduct quantity 프로퍼티 지원

• useDiscountManager 훅 구현
  - 할인 정보 계산 및 포맷팅
  - 할인율/금액 변환 유틸리티
  - 할인 적용 여부 확인

• 도메인별 UI 컴포넌트 구현
  - PointsDisplay: 보너스 포인트 상세 표시
  - StockWarning: 재고 경고 메시지 표시
  - DiscountInfo: 할인 정보 표시
  - data-testid 속성 추가

🎯 Points/Stock/Discounts 도메인 React 마이그레이션 완료
• useSpecialSales 훅 구현
  - useState로 세일 상태 관리 (번개세일/추천할인)
  - useEffect로 타이머 라이프사이클 관리
  - useCallback으로 세일 실행 메서드 최적화
  - 랜덤 딜레이와 인터벌 타이머 React 패턴 적용

• 번개세일 로직
  - 재고 있는 상품 중 랜덤 선택
  - 20% 할인 적용
  - 세일 상태 추적 및 자동 비활성화
  - 타이머 기반 반복 실행

• 추천할인 로직
  - 마지막 선택 상품과 다른 상품 추천
  - 장바구니에 아이템 있을 때만 실행
  - 5% 추가 할인 적용
  - 조건부 실행 로직

• SaleNotification 컴포넌트
  - alert() 대신 React 모달 알림
  - 자동 닫힘 기능 (3초)
  - 부드러운 애니메이션 효과
  - 번개세일/추천할인 구분 표시

• 타이머 정리 및 메모리 누수 방지
  - useEffect cleanup 함수로 타이머 정리
  - 컴포넌트 언마운트 시 안전한 정리

🎯 특별 세일 타이머 React 마이그레이션 완료
• 2단계 완료 체크
  - ✅ useProductData 훅 구현
  - ✅ ProductSelect 컴포넌트 구현
  - ✅ 상품 데이터 관리 및 할인 로직

• 3단계 완료 체크
  - ✅ useCartManager 훅 구현
  - ✅ CartDisplay, OrderSummary 컴포넌트 구현
  - ✅ 장바구니 상태 관리 및 계산 로직

• 4단계 완료 체크
  - ✅ usePointsManager, useStockManager, useDiscountManager 훅 구현
  - ✅ PointsDisplay, StockWarning, DiscountInfo 컴포넌트 구현
  - ✅ 각 도메인별 상태 관리 및 UI 컴포넌트

• 5단계 완료 체크
  - ✅ useSpecialSales 훅 구현
  - ✅ SaleNotification 컴포넌트 구현
  - ✅ 타이머 로직 React화 및 알림 처리

• 다음 단계 표시
  - 🎯 6단계: App.tsx 및 레이아웃 컴포넌트 구현

🎯 모든 도메인 React 마이그레이션 완료, 메인 앱 통합 준비
• App.tsx 메인 컴포넌트 구현
  - 모든 도메인 훅 통합 (Products, Cart, Points, Stock, Discounts, Sales)
  - React 상태 관리와 이벤트 핸들링
  - 상품 선택, 장바구니 추가/수정/삭제 로직
  - 재고 관리 및 계산 로직 통합

• main.advanced.tsx 엔트리 포인트
  - createRoot 패턴으로 React 앱 초기화
  - StrictMode 적용
  - 기존 DOM 조작 → React 렌더링 패턴

• 완전한 React 애플리케이션 구조
  - 도메인 중심 아키텍처 유지
  - props drilling 없는 깔끔한 상태 전달
  - useCallback으로 성능 최적화
  - 반응형 그리드 레이아웃 (Tailwind CSS)

• 핵심 기능 통합
  - 상품 선택 및 장바구니 관리
  - 실시간 할인 및 포인트 계산
  - 재고 부족 경고
  - 특별 세일 알림 시스템

🎯 React 마이그레이션 완료: 모든 기존 기능을 React로 완전 전환
• 7단계 최종 검증 및 성능 최적화 완료
  - ✅ 기존 기능 100% 동작 확인
  - ✅ React Testing Library 테스트 준비 완료
  - ✅ useMemo, useCallback 성능 최적화

• App.tsx 성능 최적화 적용
  - updateAllCalculations 헬퍼 함수로 상태 업데이트 로직 통합
  - useMemo로 렌더링 계산값 최적화
  - 이벤트 핸들러에서만 상태 업데이트 수행
  - 불필요한 리렌더링 방지

• 마이그레이션 계획서 최종 완료 상태 업데이트
  - 6-7단계 완료 체크
  - 폴더 구조 완성 상태 반영
  - 커밋 순서 완료 상태 정리
  - 최종 성과 및 결과 업데이트

🎉 완전한 React 마이그레이션 달성:
   TypeScript + React Hooks + 도메인 중심 아키텍처 + 성능 최적화

🚀 ready for production: 모든 기능 완료, 테스트 준비, 성능 최적화
@chan9yu
Copy link
Member

chan9yu commented Aug 1, 2025

안녕하세여 놀러왔습니당

@Hwirin-Kim
Copy link

저는 AI로 진행하기를 오히려 실패해서 초반과정을 스스로 진행하였는데.. 어떻게 진행하신지 보고 많이 배워갑니다..!! 한 주 고생 많으셨습니다!

@@ -0,0 +1,235 @@
import { useState, useCallback, useMemo } from "react";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import 를 분리하는게 좋아 보이네요

* - 할인 및 포인트 계산
* - 재고 관리 및 특별 세일
*/
export default function App() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

App 이라는 컴포넌트에서 많은 일을 하는 것 같습니다

/**
* 상품명 생성 (할인 표시 포함)
*/
const getDisplayName = () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얼리리턴을 사용하면 더 좋을 것 같아요

Comment on lines +20 to +30
const handleQuantityChange = useCallback(
(delta: number) => {
const newQuantity = item.quantity + delta;
if (newQuantity <= 0) {
onRemoveItem(item.id);
} else {
onUpdateQuantity(item.id, newQuantity);
}
},
[item.id, item.quantity, onUpdateQuantity, onRemoveItem],
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleQuantityChange 함수는 CartItem 컴포넌트에 대한 의존성이 없는거 같아요
굳이 useCallback을 감싸서 컴포넌트 내부에 넣는 것 보다는 컴포넌트 외부로 함수를 분리해보는건 어떨까요?

Comment on lines +36 to +49
/**
* 상품명 생성 (할인 표시 포함)
*/
const getDisplayName = () => {
let prefix = "";
if (item.onSale && item.suggestSale) {
prefix = "⚡💝";
} else if (item.onSale) {
prefix = "⚡";
} else if (item.suggestSale) {
prefix = "💝";
}
return `${prefix}${item.name}`;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 위랑 비슷한 생각이에요
item의 값은 매개변수로 받고 컴포넌트 외부로 함수를 분리하면 좋을 거 같아요!

@@ -0,0 +1,159 @@
import { useCallback } from "react";
import { ICartItem } from "./types";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I 가 인터페이스라서 요렇게 작성해주신 거죵? 저는 이런 것도 제안드려봅니다.

Suggested change
import { ICartItem } from "./types";
import { CartItem as CartItemType } from "./types";

Comment on lines +78 to +90
let hasKeyboard = false;
let hasMouse = false;
let hasMonitorArm = false;

cartItems.forEach((item) => {
if (item.id === PRODUCT_IDS.KEYBOARD) {
hasKeyboard = true;
} else if (item.id === PRODUCT_IDS.MOUSE) {
hasMouse = true;
} else if (item.id === PRODUCT_IDS.MONITOR_ARM) {
hasMonitorArm = true;
}
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이러면 let 을 안쓸 수 있어요.

Suggested change
let hasKeyboard = false;
let hasMouse = false;
let hasMonitorArm = false;
cartItems.forEach((item) => {
if (item.id === PRODUCT_IDS.KEYBOARD) {
hasKeyboard = true;
} else if (item.id === PRODUCT_IDS.MOUSE) {
hasMouse = true;
} else if (item.id === PRODUCT_IDS.MONITOR_ARM) {
hasMonitorArm = true;
}
});
const hasKeyboard = cartItems.some(x => x.id === PRODUCT_IDS.KEYBOARD);
const hasMouse = cartItems.some(x => x.id === PRODUCT_IDS.MOUSE);
const hasMonitorArm = cartItems.some(x => x.id === PRODUCT_IDS.MONITOR_ARM);

* 메인 앱 초기화 함수 (오케스트레이터)
* 책임: 전체 앱 초기화 과정 조율
*/
function main() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 main 로직 분리를 잘 해주셨네용 :) 현재 main 파일에 있는 UI 로직들을 남겨두신 이유가 있나요 ?

Comment on lines +66 to +71
/**
* 주문 요약 HTML 템플릿 생성 (순수 함수)
* @param {Object} summaryData - 주문 요약 데이터
* @returns {string} HTML 템플릿 문자열
*/
export function createOrderSummaryHTML(summaryData: any) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts를 쓰고싶으셨나여 jsdocs를 쓰고싶으셨나여 ㅎㅅㅎ !!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants