[6팀 이지현] Chapter 2-1. 클린코드와 리팩토링 #48
Open
j2h30728 wants to merge 80 commits intohanghae-plus:mainfrom
Open
Conversation
- createElement + appendChild → 선언적 템플릿 리터럴 - select 옵션 생성을 함수형 프로그래밍으로 개선 - 장바구니 아이템 생성을 헬퍼 함수로 분리 - let을 const로 변경하여 불변성 증대 - 주석을 일관성 있게 정리
- /*html*/ 주석으로 IDE에서 HTML 구문 강조 지원
- main 함수의 거대한 HTML을 작은 컴포넌트들로 분리 - createHeader, createProductSelector, createCartItems 등 추가 - createMainContent, createRightColumn으로 레이아웃 구조화 - createManualToggleButton, createManualOverlay로 모달 분리 - createApp으로 전체 앱 구조 조합 - 템플릿 리터럴 방식으로 React 컴포넌트와 유사한 구조 구현
- 5단계 중첩 if문을 객체 매핑으로 대체하여 할인율 계산 간소화 - 불필요한 즉시실행함수(IIFE) 제거로 코드 복잡성 감소 - for 루프 find 패턴을 Array.find()로 모던 JavaScript 방식 적용 - 변수명 개선: q→quantity, disc→discount, itemTot→itemTotal - 화요일 할인 중첩 if문을 단순한 논리연산자로 개선 - 주석 추가로 각 로직 블록의 목적 명확화 - 기능 동일 유지, 가독성과 유지보수성 대폭 향상
- calculateItemDiscounts 함수를 독립적인 순수 함수로 추출 - 장바구니 아이템들의 할인 정보를 계산하는 로직을 분리하여 재사용성 향상 - 기존 handleCalculateCartStuff 함수에서 중복된 할인 계산 로직 제거 - 부작용 없는 계산 로직으로 테스트 및 유지보수 용이성 증대 - 단일 책임 원칙 적용으로 코드 구조 개선
- createStockMessage 헬퍼 함수 추가로 재고 메시지 생성 로직 분리 - handleStockInfoUpdate를 filter→map→filter→join 체이닝으로 개선 - string concatenation 방식을 배열 조작으로 대체하여 성능 향상 - 중첩 if문 제거로 가독성 대폭 개선 - forEach side effect를 순수 함수형 접근으로 변경 - 코드 라인 수 50% 단축으로 간결성 증대
- createSummaryItemHTML, createSummarySubtotalHTML, createBulkDiscountHTML - createItemDiscountHTML, createTuesdayDiscountHTML, createShippingHTML - 6개 헬퍼 함수로 handleCalculateCartStuff 함수 내 HTML 생성 로직 분리 - React스러운 컴포넌트 기반 구조로 재사용성과 가독성 향상
- calculateBonusPoints 순수 함수로 포인트 계산 로직 분리 - createBonusPointsHTML 헬퍼 함수로 HTML 생성 로직 분리 - 79줄 → 16줄로 80% 축소, 단일 책임 원칙 적용 - 중복된 if-else 체인을 명확한 구조로 개선
- updateCartItemPrice 헬퍼 함수로 중복된 HTML 생성 로직 27줄 제거 - 기존 getSaleIcon, getPriceHTML 헬퍼 함수 재활용으로 코드 중복 해결 - for 루프를 forEach 함수형 스타일로 개선 - 단일 책임 원칙 적용으로 가독성과 유지보수성 향상
- 전역 변수(itemCnt, lastSel, totalAmt) 제거 - cartStore 생성 및 reducer 패턴 적용 - ADD_TO_ITEM_COUNT, SET_TOTAL_AMOUNT 등 액션 추가 - 상태 변경 로직을 dispatch로 통일
- prodList 전역 변수를 productStore로 이동 - 재고 변경을 DECREASE_STOCK/INCREASE_STOCK 액션으로 통일 - 번개세일, 추천할인 로직을 SET_PRODUCT_SALE 액션으로 변경
- SET_PRODUCT_PRICE, RESET_PRODUCT_PRICE 액션 추가 - 번개세일, 추천할인 로직을 store 액션으로 변경
- SET_SALE_STATUS, RESET_SALE_STATUS 액션 추가 - 가격 변경과 상태 변경을 독립적으로 처리
- uiStore 생성 및 UI 상태 중앙화 - 모달, 할인 표시, 재고 메시지 등을 store로 관리 - UI 상태 변경을 dispatch 액션으로 통일
- DOM 준비 후 observer 활성화 - cartObserver, productObserver, uiObserver 생성 - 상태 변경 시 자동으로 UI 업데이트 - 수동 UI 업데이트 호출 제거
- 할인 계산 함수들 분리 (calculateItemDiscount, calculateBulkDiscount, calculateTuesdayDiscount, calculateTotalDiscount) - 포인트 계산 함수들 분리 (calculateBasePoints, calculateTuesdayBonus, calculateSetBonus, calculateQuantityBonus, calculateTotalPoints) - handleCalculateCartStuff 함수 리팩토링하여 새로운 계산 함수들 사용
- 상품 ID 상수들을 일관된 네이밍으로 통일 (PRODUCT_IDS) - 할인율, 포인트 정책을 설정 객체로 분리 (DISCOUNT_POLICIES, POINT_POLICIES) - 하드코딩된 매직 넘버들을 의미있는 상수로 변경
- 함수 선언 방식을 const로 통일 - 하드코딩된 값들을 DAYS_OF_WEEK, UI_STYLES 상수로 분리 - handleCalculateCartStuff 함수를 calculateCartData와 updateAllUI로 분리 - 중복된 포인트 계산 로직 제거 및 함수 분리 - DOM 요소 null 체크를 통한 에러 처리 개선 - 불필요한 Array.from() 호출 최소화로 성능 최적화
- 계산, UI, 포인트, 가격 업데이트 로직을 각각 별도 파일로 분리 - 단일 책임 원칙 적용으로 코드 구조 개선 - main.basic.js 간소화 및 모듈화 완료
- handleAddToCart 함수의 중첩 if문을 로직 분리로 개선 - handleCartItemClick 함수의 중첩 if문을 별도 함수로 분리 - 얼리 리턴 패턴 적용으로 가독성 향상 - handleExistingCartItem, handleNewCartItem, handleQuantityChange, handleRemoveItem 함수 추가
- renderTuesdaySpecial 함수의 중첩 if문을 얼리 리턴으로 개선 - renderDiscountInfo 함수의 중첩 if문을 얼리 리턴으로 개선 - renderCartDisplay 함수의 중첩 if문을 얼리 리턴으로 개선 - DOM 요소 존재 여부를 먼저 확인하는 패턴 적용
- uiObserver.js의 createUIObserver 함수 중첩 if문을 얼리 리턴으로 개선 - cartObserver.js의 createCartObserver 함수 중첩 if문을 얼리 리턴으로 개선 - DOM 요소 존재 여부를 먼저 확인하는 패턴 적용
- productUtils.js의 createStockMessage 함수 중첩 if문을 얼리 리턴으로 개선 - priceUpdaters.js의 updateCartItemPrice 함수 중첩 if문을 얼리 리턴으로 개선 - 조건문을 순차적으로 처리하는 패턴 적용
- startRecommendedSale 함수의 복잡한 중첩 if문을 로직 분리로 개선 - findRecommendedProduct와 applyRecommendedSale 함수로 분리 - 얼리 리턴 패턴 적용으로 가독성 향상 - 함수 export 추가로 테스트 접근성 향상
- POINT_CALCULATION, TIMER_CALCULATION, STOCK_CALCULATION 상수 추가 - cartObserver.js에서 매직 넘버를 상수로 교체 - productUtils.js에서 매직 넘버를 상수로 교체 - 코드의 가독성 및 유지보수성 향상
- optionService.updateSelectOptions 함수를 7개 함수로 분리 - calculateTotalStock, createAllOptionsHTML, createOptionHTML 등으로 분리 - 각 함수의 단일 책임 원칙 적용 - 가독성 및 유지보수성 향상
- eventHandlers.js의 중첩 if문을 early return으로 변경 - handleAddToCart, handleCartItemClick 함수 리팩토링 - 코드 가독성 및 유지보수성 향상 - 복잡한 로직을 작은 함수들로 분리
- productActions를 cartStore.js에서 productStore.js로 이동 - uiActions를 cartStore.js에서 uiStore.js로 이동 - cartActions는 cartStore.js에 유지 - 각 도메인별 import 경로 수정 (eventHandlers.js, uiUpdaters.js) - 도메인별 응집성 향상 및 의존성 명확화
- React 19.1.1 및 React DOM 추가 - TypeScript 5.7.2 설정 및 tsconfig.json 구성 - 개발 도구 설정 (ESLint, Prettier, Vitest) - pnpm을 통한 패키지 관리 설정
- 기존 바닐라 JS 비즈니스 로직을 TypeScript로 변환 - 데이터 서비스, 상품 관리, 할인 서비스 등 핵심 로직 분리 - 타입 안정성 확보 및 인터페이스 정의 - 상태 관리 로직을 React 패턴에 맞게 재구성
- 기존 DOM 조작 기반 UI를 React 컴포넌트로 변환 - 컴포넌트 계층 구조 설계 (Layout, Cart, Guide, Order) - Props와 State를 통한 데이터 흐름 구현 - 재사용 가능한 컴포넌트 설계
- 기존 Jest 기반 테스트를 React Testing Library로 변경 - TypeScript 타입 안정성을 테스트에 반영 - 컴포넌트 기반 테스트로 전환 - 사용자 인터랙션 중심의 테스트 케이스 작성
- 구조분해할당 사용으로 코드 가독성 향상 - 템플릿 리터럴 사용으로 문자열 연결 개선 - 함수 축약 형태 적용 - 네이밍 컨벤션 일관성 유지
- 계산 로직을 calculationService로 분리 - UI 유틸리티를 uiUtils로 분리 - Custom Hooks로 상태 관리 로직 분리 - 컴포넌트에서 비즈니스 로직 제거하여 관심사 분리
- OrderSummary에서 서브토탈 계산 로직을 calculationService로 분리 - ProductPicker에서 장바구니 추가 로직을 useCart hook으로 분리 - ShoppingCart에서 가격 표시 로직을 uiUtils로 분리 - 컴포넌트가 순수한 UI 렌더링 역할만 담당하도록 개선
- useSaleService: 세일 서비스 로직 분리 - useModal: 모달 상태 관리 로직 분리 - useCartInfo: 장바구니 정보 로직 분리 - 컴포넌트에서 비즈니스 로직 완전 제거하여 순수 UI 컴포넌트로 개선
|
고생하겼습니다 지현님!!!!! |
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.
과제 체크포인트
기본과제
심화과제
과제 셀프회고
과제 코드를 보자마자 너무 놀라 까무라쳤습니다. 정말 더러운 코드라고 걱정해줬던 테오가 바로 생각 나더라구요.
더럽다는 기준은 주관적이라고 생각합니다.
그렇기 때문에 '어쩌면 내 코드가 누군가에게는 이렇게 더러운 코드이지 않을까?' 라는 산뜻한 마음으로 과제를 시작했습니다.
물론 생각보다 양이 많고 방향 잡기가 어려웠지만, AI에게 내가 원하는 방향을 지시하는 경험을 해보니 그 또한 새롭고 즐거웠습니다.
과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
1. 리팩토링 우선순위
var를 let와 const로, 재할당하지 않는 변수를 const로 리팩토링하면서 문득 1주차 과제가 생각났습니다.
1주차에서 더티코드를 작성하고 리팩토링을 해야겠다는 다짐을 했었습니다.
그러면서 코치분들께 리팩토링 순서에 대해서 조언 받았었습니다.
상태관리 → 라이프사이클 → 이벤트시스템였으며, 이번과제를 진행하면서 해당순서대로 시도했습니다.(Element) WeakMap > (Event Type) Set > (handler) Map의 자료구조와 이벤트 위임을 가지는 이벤트 시스템또한, 1챕터에서 배웠던 내용을 가져와 AI에 지시하여 리팩토링을 진행했습니다.
정말 깔끔하고 멋진 코드를 만들지는 못했지만, 이미 완성된 코드를 이전 챕터의 내용을 복습하면서 리팩토링 해보는 경험은 무지 즐거웠습니다.
2. 편리한 컨벤션 통일
페어2팀은 과제 시작전에 함께 팀의 컨벤션과 pretttier, eslint 설정을 맞추고 시작했습니다.
좋은 팀원들 덕분에 pretteir와 eslint 설정을 편하게 할 수 있었습니다.
하지만, 익스텐션에 의존하기보다는 프리커밋훅을 사용하여 커밋시에 린트와 타입체킹을 하여 컨벤션 뿐만 아니라 안정성을 지키는 것을 제안하고 설정을 공유했습니다.
과제 진행에 벅차, 해당 프리커밋 훅을 모든 팀원들이 적용하지는 못한 아쉬움은 있지만 의도에 맞게 역할을 한 것같아 기뻤습니다.
3. 테스트 코드
테스트 코드의 중요성을 체감했습니다. 리팩토링을 진행하면서 basic.test.js 테스트 코드로 기능 유지를 안정성을 보장할 수 있었습니다.
리액트로 마이그레이션을 진행하는 심화과제에서는 AI의 도움을 받아서 basic.test.js와 유사한 (당시 질문할때 88%이상) advanced.test.tsx 테스트코드를 작성하였습니다.
덕분에 기본 기능을 유지한채로 원하는 방향으로 리팩토링할 수 있었습니다.
리팩토링 및 기능 추가/수정 시에 사이드 이펙트를 막기위해 테스트 코드가 중요한 것을 이론으로만 알고있었습니다. 기본과제와 심화과제를 통해 해당 부분을 더 체감할 수 있어 즐거웠습니다.
4. 폴더구조
Vanilla JS에서의 고민:
항상 리액트에서만 코드를 작성하고 폴더구조를 고민하다보니 바닐라 자바스크립트에서의 좋은 폴더구조는 무엇인지 감이 오지않았습니다.
선택한 구조와 이유:
features/중심 구조를 선택한 이유: 도메인별 응집도를 높이고, 관련 기능끼리 모아두어 찾기 쉽게 하기 위함calculationService.js)과 UI 로직(uiUtils.js)을 분리하여 관심사 분리 원칙 적용React에서의 구조:
팀컨벤션 기준으로 네이밍을 지정하였으며, 익숙한 구조로 정리했습니다.
lib/: 순수 비즈니스 로직 (React와 독립적)hooks/: 상태 관리 로직 (React 종속적)components/: UI 컴포넌트 (도메인별 분리)과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
1. 기준
기본과제는 어디까지 리팩토링을 해야하는 지 기준을 잡지 못해 아쉬운 점이 많습니다.
AI를 적극 활용하면서 진행했지만, 세부적으로 마음에들지 않는 부분이 있습니다.
다시 해본다면 큰틀을 먼저 잡고 클린코드 및 깔끔한 설계를 위해 좀더 고민하고 세부적으로 조정해 볼 것같습니다.
2. 페어 프로그래밍
시작은 페어 팀의 팀원분들과 페어프로그래미을 해보는 것이 목표였습니다.
하지만, 서로 시간과 진도가 맞지않아서 팀에서의 최선의 방법을 선택했습니다.
동일한 리액트 보일러플레이트, eslint, prettier, husky를 설정한뒤에 원하는 방식으로 리팩토링을 하고난 뒤, 코드리뷰를 진행하는 것입니다.
아직, 시간여유가 없어서 코드리뷰를 원활하게 하지는 못했지만 팀원분들과 함께 서로 코드리뷰를 할 계획입니다.
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
테오라면 이 과제의 리팩토링에서 제일 중점적으로 볼 것 같은 요소가 있을까요?
물론, 변수 선언과 중첩 if 문 등 많은 것들이 중요하다고 생각합니다.
컨벤션, 설계, 구조 등 어떤 부분을 제일 중요하게 여기고 리팩토링시에 집중하실 것인 가요?