과제 체크포인트
배포링크
https://yunwoo-yu.github.io/front_6th_chapter2-1/
기본과제
- 코드가 Prettier를 통해 일관된 포맷팅이 적용되어 있는가?
- 적절한 줄바꿈과 주석을 사용하여 코드의 논리적 단위를 명확히 구분했는가?
- 변수명과 함수명이 그 역할을 명확히 나타내며, 일관된 네이밍 규칙을 따르는가?
- 매직 넘버와 문자열을 의미 있는 상수로 추출했는가?
- 중복 코드를 제거하고 재사용 가능한 형태로 리팩토링했는가?
- 함수가 단일 책임 원칙을 따르며, 한 가지 작업만 수행하는가?
- 조건문과 반복문이 간결하고 명확한가? 복잡한 조건을 함수로 추출했는가?
- 코드의 배치가 의존성과 실행 흐름에 따라 논리적으로 구성되어 있는가?
- 연관된 코드를 의미 있는 함수나 모듈로 그룹화했는가?
- ES6+ 문법을 활용하여 코드를 더 간결하고 명확하게 작성했는가?
- 전역 상태와 부수 효과(side effects)를 최소화했는가?
- 에러 처리와 예외 상황을 명확히 고려하고 처리했는가?
- 코드 자체가 자기 문서화되어 있어, 주석 없이도 의도를 파악할 수 있는가?
- 비즈니스 로직과 UI 로직이 적절히 분리되어 있는가?
- 코드의 각 부분이 테스트 가능하도록 구조화되어 있는가?
- 성능 개선을 위해 불필요한 연산이나 렌더링을 제거했는가?
- 새로운 기능 추가나 변경이 기존 코드에 미치는 영향을 최소화했는가?
- 코드 리뷰를 통해 다른 개발자들의 피드백을 반영하고 개선했는가?
- (핵심!) 리팩토링 시 기존 기능을 그대로 유지하면서 점진적으로 개선했는가?
심화과제
- 변경한 구조와 코드가 기존의 코드보다 가독성이 높고 이해하기 쉬운가?
- 변경한 구조와 코드가 기존의 코드보다 기능을 수정하거나 확장하기에 용이한가?
- 변경한 구조와 코드가 기존의 코드보다 테스트를 하기에 더 용이한가?
- 변경한 구조와 코드가 기존의 모든 기능은 그대로 유지했는가?
- (핵심!) 변경한 구조와 코드를 새로운 한번에 새로만들지 않고 점진적으로 개선했는가?
과제 셀프회고
폴더 구조
src/basic/
├── 📄 main.basic.js # 🚀 애플리케이션 진입점 (Entry Point)
├── 🔧 services/ # 💼 비즈니스 로직 계층 (Business Layer)
│ ├── index.js # 서비스 통합 export
│ ├── cartService.js # 🛒 장바구니 + 상태 관리 서비스
│ ├── productService.js # 📦 상품 관리 서비스
│ ├── uiUpdateService.js # 🔄 UI 업데이트 조율 서비스
│ └── saleEventService.js # 🎉 세일 이벤트 관리 서비스
├── 🎨 views/ # 🖼️ 프레젠테이션 계층 (Presentation Layer)
│ ├── index.js # 뷰 컴포넌트 통합 export
│ ├── header.js # 📋 헤더 UI 컴포넌트
│ ├── layout.js # 📐 레이아웃 UI 컴포넌트
│ ├── loyaltyPoints.js # ⭐ 포인트 표시 UI 컴포넌트
│ ├── manual.js # 📖 도움말 모달 UI 컴포넌트
│ ├── orderSummary.js # 🧾 주문 요약 UI 컴포넌트
│ └── productSelection.js # 🛍️ 상품 선택 UI 컴포넌트
├── 🛠️ utils/ # ⚙️ 유틸리티 계층 (Utility Layer)
│ ├── index.js # 유틸리티 통합 export
│ ├── constants.js # 📊 상수 정의
│ ├── formatUtils.js # 📝 포맷팅 유틸리티
│ ├── cartItemUtils.js # 🛒 장바구니 아이템 유틸리티
│ ├── discountCalculationUtils.js # 💰 할인 계산 유틸리티
│ └── pointCalculationUtils.js # ⭐ 포인트 계산 유틸리티
├── 📊 data/ # 💾 데이터 계층 (Data Layer)
│ ├── index.js # 데이터 통합 export
│ └── products.js # 📦 상품 데이터
└── 🧪 __tests__/ # ✅ 테스트 계층 (Test Layer)
└── basic.test.js # 통합 테스트
처음에는 아키텍처 패턴을 고려했습니다. MVC 패턴을 적용해볼까? 혹은 React로 마이그레이션이 예정되어있으니 Hooks 패턴처럼 만들어볼까? 그렇게 여러가지 시도를 해보려해도 해당 패턴을 적용하기 위해 하나의 덩어리를 건드려보려하면 수많은 에러를 마주했습니다.
1주차 과제를 진행하며 "하나만 건드려도 문제가 다발적으로 퍼지는 함수를 어떻게 리팩토링 해야할까요?" 라고 질문을 했던적이 있습니다. 그때 코치님이 정말 정말 작은 문제들로 나누어 하나씩 해결하는 법을 추천해주신게 기억에 남았습니다.
그래서 우선 기능이랑 연관이 없는 DOM을 생성하는 부분부터 분리를 시작했습니다. 이때 기존 코드와의 호환을 위해 하나를 변경하고 테스트를 돌려보는 방식으로 진행했는데,
정말 이 DOM 생성 이라는 문제를 분리하기 위해 다른곳에서 사이드이펙트가 생길만한 부분은 건드리지 않았습니다. 예를 들어 leftColumn이라는 DOM은 그냥 그 이름 그대로 처음엔 옮겨졌습니다ㅋㅋㅋ.. 이름을 변경하는 순간 해당 DOM을 이용하는 기능, 함수 모든 변경을 해줘야 했기에 정말 단편적인 문제들만 해결하려고 노력했던 것 같습니다.
이전에 SPA를 구성하기 위해 사용해봤던 옵저버 패턴 혹은 Class를 이용해 Component 모듈화 하는 방식은 고려하지 않았습니다. 이후 리액트 마이그레이션 이라는 다음 문제를 인지하고 있기에 최대한 순수함수들로만 구성해 나누어 보려고 노력했던 것 같습니다.
정말 많은 관심사들이 엮여있는 계산 함수는 결국 AI에게 분석을 요청해 약 main을 400줄로 줄였지만 폴더는 services, modules 등 어떤 개념으로 만들었는지 저조차도 헷갈리는 방향으로 분리가 되어있는걸 보았습니다.
단일책임은 어디까지 허용되는걸까 새로운 카트 아이템 템플릿을 생성하는 함수, 카트에 아이템을 넣는 함수 이 두개의 역할을 카트 아이템 템플릿을 카트에 넣는 함수로 추상화 시키면 틀린걸까? 과연 이 클린코드라는 주제에 끝이 있을까? 답은 있는걸까? 많은 생각이 났지만 우선 멈추고 심화과제를 진행했습니다.
도은님과 함께 페어팀에서 사용할 심화과제용 React 시작 템플릿을 페어프로그래밍을 진행하며 구성하였습니다. 완성한 자료 컨벤션에 대한 다양한 의견에 대해 받은 후 너무 많은 사견이 들어가면 진도가 나가지 않을 것 같아 기본 베이스를 만들어두고 이 베이스로 각각의 클린코드 관점에서 기능을 완성한 후 코드리뷰를 하기로 진행했습니다. (하지만 못했습니다ㅋㅋㅋ 시간이슈..)
여러모로 클린코드라는 챕터가 거의 1주차 과제에 버금갈 정도로 어려웠던 것 같습니다. 저는 이런 주관적인 관점에 의한 주제들에 어려움을 많이 느끼는 것 같습니다. 제가 정말 클린코드를 만들었는지 제2의 더티코드를 만든건지는 모르겠지만 그래도 더 나은 개발자가 되기위해 퇴근 후 아등바등 또 열심히 보낸 한주인 것 같습니다.
과제를 하면서 내가 제일 신경 쓴 부분은 무엇인가요?
점진적 리팩토링과 테스트 안전성을 가장 중요하게 생각했습니다.
원본 코드(src/main.original.js)를 분석해보니 786줄의 단일 파일에 모든 로직이 혼재되어 있었습니다. 특히 문제가 되었던 부분들:
- 전역 변수의 남용
- 일관성 없는 네이밍 (PRODUCT_ONE vs p2 vs product_3)
- 전역 상태로 인한 사이드 이펙트 위험
- 거대한 함수 handleCalculateCartStuff() (297-787줄, 약 490줄)
- 이 함수는 다음 모든 책임을 동시에 처리했습니다:
- 장바구니 아이템 순회 및 계산
- 개별 상품 할인 로직 (if (curItem.id === PRODUCT_ONE) 중첩 if문)
- 대량구매 할인 (30개 이상 25% 할인)
- 화요일 할인 (10% 추가)
- DOM 조작 (summary-details innerHTML 직접 수정)
- 포인트 계산 및 표시
- 복잡한 중첩 구조와 반복 코드
이런 거대한 함수를 한 번에 분리하면 회귀 오류가 발생할 위험이 높았기 때문에, 86개의 테스트가 모두 통과하는 상태를 유지하면서 단계별로 리팩토링했습니다:
과제를 다시 해보면 더 잘 할 수 있었겠다 아쉬운 점이 있다면 무엇인가요?
리팩토링을 진행하면서 hooks -> modules → services → 통합 등의 구조 변경이 여러 번 발생했습니다.
- handleCalculateCartStuff() 함수의 책임 분리 계획
- 전역 변수들의 상태 관리 패턴 설계
- DOM 조작과 비즈니스 로직의 분리 전략
작은 문제로 잡고 개선을 진행해보려 했지만 비대한 함수에서 작은 문제를 수정하려할때 엮여있는 코드에서 다발적 에러가 나오는걸 보며 개선 방향성을 시작할 때 제대로 잡지 못한부분이 아쉬웠습니다.
하나의 패턴을 잡고 가려할수록 해결해야할 문제들이 커져갔기에 거창한 디자인 패턴이나 아키텍처를 적용하려 고려하지 않고 정말 의미없는 작은 코드들부터 줄여가면 좀 더 수월하지 않았을까? 라는 아쉬움이 남습니다.
그리고 과제를 하며 깊이 고민해보지 못한 부분들과 클린코드에 대해 확실히 이해하지 못한 것 같아 아쉬움이 많이 남습니다..🥲
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
-
HTML 관련 로직은 views 로 분리하고 순수함수는 utils, 상태나 렌더링에 관련된건 services로 분리해보려 했는데 약간 역할이 혼재되는 함수들이 있습니다. 예를 들면 카트에 아이템을 넣는 함수면 Services에 존재해야 한다고 생각했는데 새로운 상품을 만드는 부분은 views에 있어야 할 것 같고 이런 역할이 혼재된다고 할때 어떻게든 순수함수를 고려하며 분리해야할까요?
-
다른곳에서 재사용이 되지않는 순수함수들도 별도 파일에 분리하는게 좋을까요? 코치님이라면 어떠한 디자인패턴 or 아키텍처를 적용하셨을 것 같나요?
-
심화과제에서도 동일하게 utils를 순수함수로 두려고 생각했고 react와 연관이 있다면 컴포넌트 내부 혹은 hooks에 두고 컨트롤하려고 했습니다. priceUtils에 renderPriceWithDiscountStyle 함수는 성질이 컴포넌트에 조금 더 가깝다고 느껴지는데 현재 utils 함수에 두는게 맞을까요?
-
클린코드에서 지향하는 방향성이나 지침들이 분명히 있지만 저는 판단이 주관적인 부분도 많이 들어가게 되는 것 같습니다. 이렇게 리팩토링을 진행하며 명확하게 판단이 서지 않을 때 어떤 기준으로 코드의 방향성을 정하시나요?
-
비대한 함수에서 (handleCalculateCartStuff) 개선을 시작할 때 이 부분은 순수함수로 빼고 이 부분은 ~~로 처리하고 같은 판단이 잘 서지않는건 클린코드에 대한 아티클이나 레퍼런스같은걸 모르는걸까요? 명령형으로 작성된 코드를 파악해서 기능의 돌아가는 원리는 파악이 되지만 이건 순수함수로 개선이 가능하다! 같은 판단이 어렵습니다..
과제 피드백
윤우님 고생하셨습니다! 과제가 굉장히 방대했는데, 꼼꼼하게 그리고 시간을 많이 들이신 것 처럼 보이네요. 잘 하셨습니다 ㅎㅎ 작업을 잘게잘게 나눠 접근하는 방식도 좋았어요 :+1 복잡한 문제나 양이 많은 문제들 특히 지금과 같은 과제들처럼 여러 개선점을 한번에 적용해야 하는 경우에서는 좋은 접근법이였습니다.
추가로 중간 회고에서 '약 main을 400줄로 줄였지만 폴더는 services, modules 등 어떤 개념으로 만들었는지 저조차도 헷갈리는 방향으로 분리가 되어있는걸 보았습니다' 라고 해주셨는데, 결국 AI에게 구체적인 작업 지침을 주지 않으면, 검수를 하는 그 과정 조차도 어려워지더라구요. 가능하면 작업 단위도 주제별로 전달하거나, 그것이 어렵다면 AI에게 계획을 세우고 그 작업의 기준과 지침을 보여달라고 한 다음 확인한 뒤에 작업을 시키면 이런 문제는 줄어들 것 같아요.
그럼 질문 주신 부분 답변 남겨볼게요!
HTML 관련 로직은 views 로 분리하고 순수함수는 utils, 상태나 렌더링에 관련된건 services로 분리해보려 했는데 약간 역할이 혼재되는 함수들이 있습니다. 예를 들면 카트에 아이템을 넣는 함수면 Services에 존재해야 한다고 생각했는데 새로운 상품을 만드는 부분은 views에 있어야 할 것 같고 이런 역할이 혼재된다고 할때 어떻게든 순수함수를 고려하며 분리해야할까요?
답변은 지금의 레이어 구조를 기준으로만 말해볼게요. 일단 이런 분리는 명확한 규칙이 수립되어야 하는게 기본인 것 같아요. 애매한 부분이 생기면 그 부분에 대한 규칙을 명확하게 만들고 앞으로 작성하는 코드들은 모두 그 위치에 작성하는거죠. 그것만으로도 중간은 가는 것 같아요.
일단 지금의 구조에서 규칙을 만든다면
- 이 함수가 DOM을 직접 조작하나? → Views
- 비즈니스 규칙이나 도메인 지식이 필요한가? → Services
- 순수하게 데이터만 변환하나? → Utils
- 여러 곳에서 재사용되는가? → Utils (순수함수라면) 뭐 이런식으로 규칙을 만들어보는거죠. 프로젝트에서는 분리 기준도 중요하지만 일관성이 가장 중요한 것 같아요. 이런식으로 하다보면 질문 주신 부분에 대해서는 일단 명확해지지 않을까요! 추가로 어떻게든 순수함수를 고려한다기보다는 여러 군데에서 사용할 수 있는 로직들을 재사용성을 높이는 관점에서 역할을 분리한다는 관점에서 순수함수로 분리해야 하기 때문에 어떻게서든지 분리한다 관점으로 접근하지는 않았으면 좋겠어요 ㅎㅎ
다른곳에서 재사용이 되지않는 순수함수들도 별도 파일에 분리하는게 좋을까요? 코치님이라면 어떠한 디자인패턴 or 아키텍처를 적용하셨을 것 같나요?
저라면 분리를 안했을 거 같긴한데 이것도 결국 규칙을 만들고 지키기만 하면 되는 문제같아요. 함께 둔다면 사용하는 곳에 가깝게 두는 맥락인거고 분리를 한다면 목적에 맞게 폴더를 구획한다는 관점인거니까요!
지금에 있어서 디자인 패턴이나 아키텍처를 적용한다고 하면 저도 막 엄청 대단한 걸 적용하지는 않았을 것 같아요. 실무 관점이라면 최대한 지금의 구조를 확장성 있게 개선하는 관점, 그리고 제대로 동작하면서 기존 실 서비스에 영향을 주지 않아야 하기 때문에 점진적으로 개선할 수 있는 관점의 아키텍처들을 고민해봤을 것 같아요. 당장 시간이 여유롭지 않다면 윤우님이 작성해주신 패턴을 보면 역할 기반으로 폴더가 나눠지고 단순화 되어있는 구조이기도 하고 서비스 레이어에서 담당하는 일이 많아진 거 같아요. 그러다 보니 비즈니스 로직이나 네트워크 통신, 도메인 규칙 등등이 담기게 될 것 같은데요. 이런 부분을 세분화하고 더 나아가는 형태로 고민해보지 않았을까 싶네요.
심화과제에서도 동일하게 utils를 순수함수로 두려고 생각했고 react와 연관이 있다면 컴포넌트 내부 혹은 hooks에 두고 컨트롤하려고 했습니다. priceUtils에 renderPriceWithDiscountStyle 함수는 성질이 컴포넌트에 조금 더 가깝다고 느껴지는데 현재 utils 함수에 두는게 맞을까요?
요것도 위에 작성한 것처럼 규칙을 만들고 그대로 지키면 되지 않을까요! ㅎㅎ
클린코드에서 지향하는 방향성이나 지침들이 분명히 있지만 저는 판단이 주관적인 부분도 많이 들어가게 되는 것 같습니다. 이렇게 리팩토링을 진행하며 명확하게 판단이 서지 않을 때 어떤 기준으로 코드의 방향성을 정하시나요?
맞아요. 사실 선배들이 말하는 '이렇게 코드를 짜면 이런 장점이 있다'가 있는 것이지 절대적인 법칙에 해당되는 내용이 아니니까 그런것 같아요. 대신 그 선배들이 말하는 기준들을 왜 그렇게 하라고 했는지 읽어보고 공감하는 내용이 있다면 (또는, 지키는데 크게 어렵지도 않고 노력대비 쉽게 얻을 수 있는 효과도 있고) 그걸 명확하게 해나가면 나만의 클린 코드 규칙이 되지 않을까 싶어요. (대신 대다수가 싫어하는 규칙이 있으니 그런 부분들이 공감이 안된다고 팀 내에서 고집을 부리면 안되겠죠 ㅎㅎㅎ )
비대한 함수에서 (handleCalculateCartStuff) 개선을 시작할 때 이 부분은 순수함수로 빼고 이 부분은 ~~로 처리하고 같은 판단이 잘 서지않는건 클린코드에 대한 아티클이나 레퍼런스같은걸 모르는걸까요? 명령형으로 작성된 코드를 파악해서 기능의 돌아가는 원리는 파악이 되지만 이건 순수함수로 개선이 가능하다! 같은 판단이 어렵습니다..
음 일단 클린코드 책에서 말하기에는 함수는 한 가지 책임만 져야 한다. 의존성을 최소로 져야 한다. 사이드 이펙트를 최소화 해야한다 이런 관점으로 많이 이야기가 될 텐데요. 고민이 된다면 함수에서 몇 가지 역할을 하고 있는지 고민을 해보고 그 역할별로 함수를 나누는게 첫번째 기준일 것 같고 아니면, 해당 부분에 있어서 (함수로 분리가 고민되는 부분에 있어서) 항상 같은 입출력을 내는 부분이 있는가? 외부와 상호작용이 있나? 사이드 이펙트가 발생하지는 않을까? 이런 부분들에 대해 질문을 해보고 항상 같은 입출력을 낸다. 사이드 이펙트 없다. 이런 부분들에 대해서 순수함수로 분리할 수 있을 것 같아요!
이번 주도 고생하셨고 많은 고민하셨던 만큼 다음주도 화이팅입니다!