Open
Conversation
제거 후 테스트 진행 > 통과
- 점진적 리팩토링을 위한 관심사 분리 준비 - 기존 코드 유지하며 구조 파악 및 개선 방향 설정
- 'var' 선언을 'const' 또는 'let'으로 변경하여 스코프 명확화 - 미사용 변수 제거 및 주석 처리
일관성 없는 상수 명명 방식 표준화 - PRODUCT_ONE, p2, product_3 → PRODUCT_KEYBOARD, PRODUCT_MOUSE 형태로 변경 - 모든 상품 ID 상수를 SCREAMING_SNAKE_CASE로 통일 - 상수명에 의미있는 이름 적용하여 가독성 향상
- 제품 ID와 제품 목록을 main.basic.js에서 data/products.js로 이동 - main.basic.js에서 새 모듈의 제품 상수들을 import하도록 수정
- 헤더 생성 로직을 Header.js의 재사용 가능한 createHeader 컴포넌트로 이동
- 그리드 컨테이너 생성 로직을 createGridContainer 컴포넌트로 추출 - main.basic.js에서 새로운 컴포넌트를 사용하도록 수정
- 좌측 컬럼 UI 생성 로직을 LeftColumn.js의 createLeftColumn 컴포넌트로 추출
- 주문 요약 UI를 main.basic.js에서 재사용 가능한 RightColumn 컴포넌트로 추출
매뉴얼 오버레이 UI와 로직을 main.basic.js에서 ManualOverlay.js 컴포넌트로 추출
- 상품 선택 및 옵션 업데이트 로직을 ProductSelector.js 컴포넌트로 이동
장바구니 아이템 DOM 생성 및 가격 업데이트 로직을 CartItem 컴포넌트로 추출 - main.basic.js에서 createCartItem, updateCartItemPrice 함수 사용하도록 수정
AddToCartButton과 StockInfo를 별도 컴포넌트 모듈로 추출
장바구니 디스플레이 관련 함수들을 새로운 CartDisplay 컴포넌트로 추출 - main.basic.js에서 CartDisplay API를 사용하여 장바구니 아이템 추가/제거/조회
사용하지 않는 createCartItem import 및 선택기 컨테이너 관련 코드 제거
- RightColumn에서 SummaryDetails 컴포넌트 사용하도록 수정 - main.basic.js에서 updateSummaryDetails 함수로 처리
- RightColumn과 main.basic.js에서 새로운 컴포넌트를 사용하도록 수정 - 기존의 인라인 계산 및 렌더링 로직 제거
- RightColumn.js에서 DiscountInfo 컴포넌트를 사용하도록 변경 - main.basic.js에서 updateDiscountInfo 함수 호출 방식으로 리팩토링
실시간 계산으로 인해 발생하는 테스트 오류를 방지하기 위해 useFakeTimers 대신 setSystemTime을 사용하여 날짜를 고정함
- main.basic.js에서 bonusPts 관련 전역 변수 및 로직 제거 - CartDisplay에서 사용되지 않는 hasCartItems import 제거
♻️ refactor(cart): CartTotal 컴포넌트로 장바구니 합계 로직 분리
main.basic.js에서 사용되지 않는 주석, 변수, 함수 코드를 제거
Header.js의 상품 개수 표시 로직을 ItemCount.js로 분리
'header' → 'Header'로 import 경로를 수정함
main.basic.js의 타이머 기반 추천/할인 로직을 TimerService 클래스로 이동하여 책임 분리 및 유지보수성을 개선
더 이상 사용되지 않는 lastSel 변수와 관련 할당 코드를 main.basic.js에서 제거
장바구니 아이템 가격 갱신 로직을 CartPriceUpdater 서비스로 이동하여 관심사 분리 및 유지보수성을 개선 - 제품 정보 조회 및 가격 갱신 로직을 서비스 내부로 캡슐화 - main.basic.js는 CartPriceUpdater만 호출하도록 단순화
- CartProvider와 useCartContext 생성 - 장바구니와 제품 상태 전역 공유 - Context API를 통한 상태 관리
- 전체 앱을 CartProvider로 감싸기 - 전역 상태 관리 활성화 - 컴포넌트 간 상태 공유 가능
- 개별 hooks 대신 통합 context 사용 - 상태 공유 문제 해결 - 장바구니 추가 기능 활성화
- 개별 hooks 대신 통합 context 사용 - 수량 변경 및 삭제 기능 연결 - 상태 일관성 보장
- Header에 useCartContext 적용으로 실시간 아이템 개수 표시 - ProductPicker에 재고 확인 로직 추가 - 품절 상품 옵션 비활성화 및 시각적 표시 - 재고 부족 경고 메시지 동적 생성 - 장바구니 추가 시 재고 한도 검증
- discountCalculator 유틸리티로 복잡한 할인 로직 분리 - 개별 상품 할인 (10개↑), 대량 구매 할인 (30개↑) 적용 - 화요일 추가 할인 로직 구현 - OrderSummary 실시간 업데이트 (장바구니 아이템, 할인, 포인트) - 할인 상세 정보 표시 및 총 할인율 계산
- useDiscountTimers hook으로 자동 할인 시스템 구현 - 번개세일 (30초마다, 20% 할인) 및 추천할인 (60초마다, 5% 할인) - 할인 상태별 시각적 구분 (⚡번개세일, 💝추천할인, ⚡💝슈퍼세일) - CartContext에 마지막 선택 상품 추적 기능 추가 - 상품 선택 옵션 및 장바구니에서 할인 표시 구현
- CartContext에서 실제 재고 검증 및 차감 로직 구현 - pointsCalculator로 상세 포인트 적립 로직 분리 - 키보드+마우스 세트, 풀세트, 대량구매 보너스 구현 - 화요일 포인트 2배 적용 및 포인트 상세 표시 - 재고 부족 시 select 테두리 색상 변경 (orange)
- discountCalculator에서 번개세일/추천할인 반영한 할인 계산 - ShoppingCart에서 할인 상품 시각적 표시 완성
- useProducts에 decreaseStock, increaseStock 함수 export - CartContext에서 장바구니 추가/수량변경/삭제 시 실제 재고 차감/복구 - 수량 증가 시 재고 부족 검증 및 차감 - 수량 감소/삭제 시 재고 복구 로직
- 장바구니에서 수량 10개 이상인 상품명 font-bold 적용 - 가격 표시도 동일하게 굵은 글씨 처리 - PRD 요구사항: "할인된 상품은 굵은 글씨로 표시" 구현
- 번개세일: 재고 있는 모든 상품 중 랜덤 선택 (originalPrice 기준 20% 할인) - 추천할인: 현재 price 기준 5% 할인으로 누적 할인 구현 - 마지막 선택 상품과 다른 상품만 추천하도록 유지 - 올바른 할인 로직으로 PRD 요구사항 준수
- 재고 5개 미만 상품 빨간색 텍스트 표시 - 재고 부족 시⚠️ 아이콘, 품절 시 🚫 아이콘 추가 - ProductPicker 옵션에서도 재고 상태 시각적 구분 - 장바구니에서 재고 수량 정보 표시 - PRD 요구사항: 재고 부족 시각적 경고 구현
- 재고 경고 아이콘(⚠️ )을 최우선으로 앞에 배치 - 재고 부족 시 font-medium으로 추가 강조 - 아이콘 표시 순서 정리 (재고 → 할인 → 상품명)
- 실제 재고 차감을 반영하여 product.stock 기준으로 계산 - getTotalStock에서 중복 계산 제거 (실제 남은 재고만) - 품절 조건을 실제 재고 0 기준으로 변경 - handleAddToCart 로직 단순화 - 재고 메시지도 실제 재고 기준으로 표시
- 번개세일(⚡), 추천할인(💝), 슈퍼세일(⚡💝) 할인 내역 추가 - 상품별 번개세일/추천할인 적용 시 할인율 계산 및 표시 - 할인 내역에 아이콘과 상품명으로 명확한 구분 - originalPrice 대비 실제 할인율 정확히 계산
- ShoppingGuide에 onClose props 추가 - X 버튼 클릭으로 가이드 닫기 - 오버레이 배경 클릭으로 가이드 닫기 - PRD 요구사항: "배경 클릭 또는 X 버튼으로 닫기" 구현
- setInterval을 재귀적 setTimeout으로 변경 - 원본 바닐라 JS와 동일한 타이머 로직 적용 - 한 번 실행 후 다음 타이머 설정하는 방식으로 수정 - 무한 alert 스팸 문제 해결
- eslint-disable no-unused-vars 주석 추가로 타입 정의 린터 에러 해결 - 함수 타입 정의에서 parameter 이름 사용하지 않음 경고 무시
- CartItem 컴포넌트를 별도 파일로 분리 - 복잡한 렌더링 로직을 작은 함수들로 분해 - ShoppingCart 컴포넌트 크기를 127줄에서 40줄로 단축 - 단일 책임 원칙 적용으로 가독성과 유지보수성 향상
- 'no-unused-vars' 룰을 off 처리 - '@typescript-eslint/no-unused-vars'를 error로 설정하여 TypeScript 기준으로 검사 - 타입 시스템에 맞는 불필요한 변수 감지 정확도 향상
…e 함수로 로직 분리 - 장바구니 로직의 책임을 명확히 분리 - 상품 및 카트 아이템 조회 로직을 findProductAndCartItem 함수로 추출 - 수량 증가/감소 로직을 handleStockIncrease, handleStockDecrease로 분리 - 가독성 및 재사용성 향상을 위한 구조 개선
- calculateOriginalTotal: 원가 총합 계산 - calculateDiscountedPriceTotal: 할인 적용 총합 계산 - calculateSaleDiscounts: 번개세일/추천상품 할인 총액 계산 - getItemDiscountRate: 상품별 개별 할인율 추출 - calculateItemDiscounts: 수량 기반 개별 할인 계산 - calculateBulkDiscount: 30개 이상 대량 구매 할인 계산 - calculateTuesdayDiscount: 화요일 할인 계산 - 각 함수는 단일 책임 원칙을 따르며 테스트와 재사용이 쉬운 구조로 개선
- src/advanced/types/index.ts 생성하여 타입 정의 중앙화 - Product, CartItem, DiscountInfo, DiscountResult, PointsResult 등 핵심 타입 통합 - CartItemProps, ShoppingGuideProps, UseDiscountTimersProps 등 컴포넌트 Props 타입 정의 이동 - 각 파일에서 중앙 타입 모듈을 import하도록 수정 - 타입 중복 제거 및 일관성 있는 관리 구조로 유지보수성 향상
- 114줄짜리 OrderSummary 컴포넌트를 4개의 작은 컴포넌트로 분리 - OrderItem: 개별 주문 아이템 렌더링 - DiscountSummary: 할인 요약 정보 표시 - PointsDisplay: 포인트 적립 정보 표시 - TuesdayBanner: 화요일 특별 할인 배너 - OrderSummary 본체는 65줄로 간결화 - 단일 책임 원칙(SRP)을 적용해 각 컴포넌트가 명확한 역할만 담당 - 가독성, 재사용성, 테스트 용이성 향상
- calculateDiscount 함수 테스트 추가 (빈 장바구니, 개별 할인, 대량 할인) - calculatePoints 함수 테스트 추가 (빈 장바구니, 기본 포인트, 세트 보너스, 대량 보너스) - PRODUCT_LIST 데이터 무결성 테스트 추가 - 세일 로직 특정 테스트 추가 (슈퍼 세일, 화요일 할인) - 모든 핵심 비즈니스 로직이 적절히 테스트되고 검증되도록 보장
- gh-pages 패키지 추가로 GitHub Pages 자동 배포 가능 - 프로덕션 환경에 맞춘 base path 설정 완료 - 빌드 최적화 및 HTML 파일명 처리 로직 적용 - 배포 스크립트(pnpm gh-pages) 추
|
도은님의 클린코드 룰 덕에 덕 좀 봤습니다 감사합니다 |
Member
|
저도 도은님 룰 너무 잘썻어요👍👍👍 |
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://nemobim.github.io/front_6th_chapter2-1/
기본과제
심화과제
과제 셀프회고
이번 과제는 1주차 과제와 비교해도 될 만큼 시간이 오래 걸렸습니다... 흔히 개발자들끼리 "이 코드를 이해하는 것보다 다시 만드는 게 빠를 것 같다"는 농담을 하곤 하는데 이번 과제에서 정말 그 말이 와닿았습니다. 가독성도 낮고 변수도 난해하고 줄바꿈도 없고 ,, ‘나쁜 코드란 무엇인가’를 바로 체감할 수 있었습니다.
처음에는 단일 페이지로 구현되어 있길래 금방 할 수 있을줄 알았으나,, 착각이였고. 바닐라 js로 작성되어있는 700줄 가까이 되는 코드를 분석하고 분리하는 시간이 상당히 오래걸렸습니다..적당히 basic만 끝내고 advanced로 넘어가려고 했지만 ‘basic을 제대로 해두는 게 나중에 React로 전환할 때 더 수월하지 않을까?’,‘기본을 잘 다져놔야 마이그레이션도 빨라지지 않을까?’ 하는 생각이 들어서 결국 basic에 더 많은 시간을 쏟게 되었습니다.(이 과정에서 AI 도움을 굉장히 많이 받음)
심화 과제는 팀 협업으로 진행할 것을 권장하셨기에 간단한 컨벤션을 팀원들과 함께 정하였습니다. 프리티어, 린트 설정 같은 개발 환경 설정부터 폴더 구조를 어떻게 구성할지까지 figjam을 활용해 함께 정리하고 공유하였습니다. (협업할때는 문서화가 정말 중요하다!)
eslint + prettier + husky 설정
우리팀 컨벤션 >_<
advanced 폴더 구조 및 리액트 셋팅 방법
AI는 Cursor를 주로 사용했으며 직접 작성한 Rules 입니다.
refactor-for-clean-code
alwaysApply: true
AI Code Generation Guidelines
Complete guidelines that AI must follow when generating any code.
🚨 CRITICAL: All code output must comply 100% with these guidelines. NO EXCEPTIONS.
1. MANDATORY CODE GENERATION RULES
1.1 Core Design Principles (MUST APPLY)
1.2 Code Organization (Apply 4 Principles)
1.3 ENFORCED Naming Rules
Function Naming Patterns (MUST USE)
Variable Naming Patterns (MUST USE)
1.4 Naming 5 Principles (ALL MUST BE FOLLOWED)
2. THEORETICAL PRINCIPLES FOR AI CODE GENERATION
2.1 Refactoring Principles (Martin Fowler)
Detect Code Smells and Fix Immediately
Apply Refactoring Catalog
2.2 Variable Role Patterns (Sajaniemi)
Choose appropriate variable roles when generating code:
2.3 SOLID Principles (Robert Martin)
2.4 TDD Patterns (Kent Beck)
When generating test code:
3. AI CODE GENERATION CHECKLIST
MANDATORY Verification Before Code Output
FORBIDDEN PRACTICES (NEVER DO)
4. API DESIGN GUIDELINES (Olaf Zimmermann)
4.1 Foundation Patterns
4.2 Quality Patterns
4.3 Evolution Patterns
5. AI-SPECIFIC GENERATION RULES
5.1 Function Generation
5.2 Class Generation
5.3 Variable Declaration
6. FINAL COMPLIANCE DIRECTIVES
🚨 AI COMPLIANCE COMMANDS:
Code Generation Process:
Quality Assurance:
7. IMPLEMENTATION COMMANDS FOR AI
7.1 Before Writing Any Code
7.2 During Code Generation
7.3 After Code Generation
8. ERROR PREVENTION PROTOCOLS
8.1 Common Violation Patterns to Avoid
8.2 Immediate Correction Triggers
These guidelines are the absolute standards for AI to generate consistent, high-quality code.
refactor-guide
alwaysApply: false
Vanilla JS Clean Code Rules (React-inspired)
Core Principles
Code Formatting & Style
Naming Conventions
getUserData,isActiveUserManager,DataProcessorAPI_BASE_URL,MAX_RETRY_COUNThandleUserClicknotonClickis,has,should:isLoading,hasPermissionConstants & Magic Values
Function Design
Modern JavaScript Features
constby default,letwhen reassignment needed, avoidvar?.) and nullish coalescing (??)map,filter,reduce) over traditional loopsState Management (React-inspired)
Component-like Structure
Error Handling
Module Organization
Performance Considerations
Testing Structure
Refactoring Guidelines
Code Review Checklist
Anti-Patterns to Avoid
varor implicit globalsAI를 활용한 리팩토링 과정에서 느낀 점
한 번에 전체 파일(800줄 이상)을 처리하도록 요청했을 때 일관성 있는 결과를 얻기 어려웠습니다. AI가 앞부분에서 적용한 패턴을 뒷부분에서 잊어버리거나 다른 방식으로 처리하는 경우가 빈번했습니다. 복잡한 상호 의존성을 가진 함수들을 동시에 리팩토링할 때 예상치 못한 사이드 이펙트가 발생하기도 했습니다.
중복 로직 생성 문제
전체 프로젝트 구조를 설명하고 기존 유틸리티 함수들을 알려줬음에도 불구하고, 비슷한 기능을 하는 새로운 함수를 만들어내는 경우가 있었습니다. 예를 들어, 이미 formatPrice 함수가 있는데 priceFormatter라는 유사한 함수를 추가로 생성하는 식이었습니다.
과도한 추상화 경향
간단한 기능에 대해서도 불필요하게 복잡한 디자인 패턴을 적용하려는 경향이 있었습니다. 예를 들어, 단순한 함수에서 과한 에러처리를 작성하거나 불필요하게 함수를 분리하기도 했습니다.
기능 유지의 어려움
"기존 기능을 유지하면서 리팩토링해달라"고 명확히 지시했음에도 불구하고 미묘한 동작 방식이 변경되는 경우가 있었습니다. 작업이 하나 끝나면 테스트를 진행하여 일관성을 확인했습니다.
방대한 작업을 한번에 입력하면 성능이 크게 떨어지기때문에 우선순위를 먼저 분석한후 작은 범위부터 시작해 처리해달라고 명령하였습니다.
한번에 너무 많은 작업을 처리하지 말것, 한 스텝씩 점진적으로 진행할것, 기능 단위로 작업할 것그리고 전체적인 리팩토링이 끝나도 마무리 하는게 아닌, 지침을 활용해서 반복적으로 검토하는 작업을 걸쳤습니다.. 이러한 경험을 통해 AI는 막연한 더티코드를 리팩토링할때는 지침을 주는 강력한 도구이지만, 적절한 가이드와 인간의 판단이 결합되어야 최선의 결과를 얻을 수 있다는 것을 깨달았습니다.과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
이번 과제에서 가장 중요하게 생각한 부분은 기존 기능을 유지하면서 점진적으로 리팩토링하는 것이었습니다.
한 번에 전체 코드를 바꾸기보다는 작고 명확한 단위로 나누어 개선하는 방식으로 접근했습니다.
리팩토링 우선순위 지정
무작정 고치는 것이 아니라 리스크가 낮은 부분부터 점진적으로 복잡한 영역까지 체계적으로 우선순위를 정한 뒤 단계적으로 리팩토링을 진행했습니다.
마지막으로 전체적인 코드를 점검할때는 읽는 사람이 읽기 쉬운지, 가독성이 어떤지를 고려하며 주석을 작성하였습니다.
이러한 단계별 접근으로 점진적인 리팩토링을 진행할 수 있었습니다.
마이그레이션을 염두에 둔 리팩토링 방향
이후 advanced 단계에서 React로 마이그레이션할 것을 고려하여 리액트와 친화적인 구조가 되도록 리팩토링하는게 신경을 썼습니다.
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
변수명 설계의 중요성
리팩토링을 시작할 때 구조 분리에만 집중하고 변수명에 대해서는 충분히 고민하지 않았던 것이 가장 큰 실수였습니다. 전체 구조를 다시 살펴보는 과정에서 변수명이 모호하다는 점을 뒤늦게 깨달았고 결국 하나하나 수정해야 했습니다. 특히 클래스명이나 아이디가 컴포넌트명이나 변수명에 많이 의존하고 있었기 때문에 하나의 네이밍을 수정하면 연관된 모든 부분을 찾아서 함께 바꿔야 했습니다. 이 작업에서 변수명을 변경 > 테스트 진행 > 변경 > 테스트 진행하며 제대로 변경되었는지 확인하느라 예상보다 많은 시간이 걸렸습니다...
한 파일로 구성되어 있던 초기 상태에서 네이밍 규칙을 정하고 구조를 조금 더 체계적으로 정리해뒀더라면 이후 모듈 분리나 import 작업이 훨씬 수월했을 것이라 생각합니다. 급하게 파일을 나누고 리팩토링을 시작하기보다는 전체 구조를 먼저 설계하고 정리한 뒤 작업을 진행하는 것이 오히려 더 효율적인 접근법이라는 점을 이번 경험을 통해 다시 한 번 느꼈습니다.
시간 관리
basic에 시간을 많이 투자하게 되면서 advanced 단계 구현에 충분한 시간을 투자하지 못한 점도 아쉽습니다. 지금보다 함수 로직을 더 간결하게 리팩토링하고 반복되는 패턴을 체계적으로 분석하여 개선할 수 있었을 것 같은데..구현에 급급하여 최종 검토 부분이 미흡한거 같습니다.
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)