Skip to content

[4팀 이유진] Chapter 2-1. 클린코드와 리팩토링#53

Open
Elli-Lee wants to merge 40 commits intohanghae-plus:mainfrom
Elli-Lee:second-try
Open

[4팀 이유진] Chapter 2-1. 클린코드와 리팩토링#53
Elli-Lee wants to merge 40 commits intohanghae-plus:mainfrom
Elli-Lee:second-try

Conversation

@Elli-Lee
Copy link

@Elli-Lee Elli-Lee commented Jul 31, 2025

과제 체크포인트

https://elli-lee.github.io/front_6th_chapter2-1/

기본과제

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

심화과제

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

과제 셀프회고

저는 이번 과제가 유독 어려웠습니다.. 어게인 1주차 느낌입니다.
왜 이렇게 어려웠을까를 지금와서 생각해보니, 우선 여전히 바닐라 자바스크립트로 DOM을 직접 다루는건 너무 어렵습니다.
DOM을 어떻게 다뤄야 원하는 결과를 만들 수 있는지가 제 머리속에 명확하지 않았는데, 거대한 더티코드 어디선가 뭔가 DOM 조작을 하고 있는 것 같은데 그 흐름을 찾기가 어려웠습니다.

또 어디서부터 손을 대야할 지 감이 잘 안왔습니다.
제일 마음에 안드는 부분부터 조금씩 건드려 보다가, QNA를 듣고" 조금 더 시야를 크게 넓혀서 리액트 처럼 리팩토링하자!" 라는 생각이 들어서
처음부터 다시 과제를 진행했는데요... 두번째 리팩토링 과정도 처음과 크게 다르지 않았던 것 같습니다.

basic 과제는 그래도 AI를 최대한 덜 사용하려고 노력했고, 고치면서도 이렇게 리팩토링하는게 맞나? 하는 생각을 수없이 했는데요, 그 과정이 힘들었지만 재밌기도 했습니다.

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

  1. 팀 컨벤션 맞추고 맞춘 컨벤션에 맞게 코드 작성하기
    basic 과제를 시작하기 전에 팀 코어타임에 모여서 팀 코드 컨벤션을 정했습니다.
    4,7팀 팀원분들이랑 의견을 나누면서 컨벤션을 정하는 시간이 정말 재밌었고,
    의견이 충돌했을 때 저와 다른 의견을 가지신 분들의 합리적인 이유를 듣는것도 좋았습니다.
    팀장님이신 하늘님께서 팀 컨벤션을 바탕으로 eslint와 prettier 설정 파일을 공유해주셔서 해당 설정을 프로젝트에 적용했고, 과제를 수행하면서도 컨벤션에 맞게 코드를 작성하기 위해 신경썼습니다.

  2. 리액트스럽게 리팩토링하는건 대체 무엇인가!
    심화과제에서 활용할 수 있게 기본과제를 최대한 리액트스럽게 리팩토링 해야한다고 힌트를 주셨고,
    리액트스러운게 무엇일까? 리액트처럼 리팩토링 한다는 건 뭘까를 많이 고민했습니다.

많이 고민해서

  • JSX를 흉내 내기 위해 템플릿 문자열 + map + join을 적극 활용, html 리턴하도록 구성
  • 가능한 한 불변성 유지하기 (state.cart = [...state.cart, newItem] 등)
  • DOM 참조 의존도 최소화: document.querySelector 최소화, id/class 대신 구조로 제어
  • 전체 DOM을 리렌더링하므로 최소 DOM diffing 구조로 설계 (React처럼은 못하더라도)
  • 이벤트 위임 방식 적용
  • use~ hook으로 로직 분리하기

정도로 이해했는데요,
리액트처럼 리팩토링 한다는게 어떤건지 언어로는 이해를 했어도 그렇게 실제로 구현하는 건 또 다른 문제였습니다.
분명 저 부분들을 계속 신경쓰면서 리팩토링을 했는데 결과를 돌아보니 지켜진게 거의 없는 것 같습니다.

그래도 심화과제를 진행하면서 리액트로 코드를 짜다 보니 제가 기본 과제 수행 중 어느 부분을 잘못 설계했고, 덜 쪼갰는지 등등을 알 수 있었습니다.

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

basic 과제를 진행 할때는 사실 DOM API 조작에 대한 이해도 부족했고, 어디서 어떤 일이 일어나는 건지 코드 자체를 잘 이해하지 못해서
리팩토링을 계획적이고 구조적으로 큰 틀을 잡고 진행하지 못했고, 그냥 그때그때 보이는 걸 조금씩 고쳤습니다.
조금씩 고치다가 마지막에 결과물을 돌아보니, 불규칙한 모양의 돌을 반질반질한 하트 모양으로 조각하고 싶었으나 거칠거칠한 삼각형으로 조각한 느낌입니다.
헤매는 시간도 많았고, 심화과제로 리액트로 바꿔보기도 했고, 솔루션 코드도 본 지금은 그래도 조금 더 감이 오는 것 같습니다.
다시한번 과제를 진행해서 큰 틀을 잡고 구조적으로 리팩토링을 해보면 조금 더 나은 결과가 나올 것 같습니다.
또, 클린코드 챕터에 걸맞게 이번 과제하면서 놓쳤던 많은 부분들을 (매직넘버 남아있음, ui 덜 쪼갰음, DOM API 많이 씀, for문을 map으로 못바꿈, 전역변수 적절하게 처리하지 못함 등등) 더 챙기면서 할 수 있을 것 같습니다.

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

DOM API 대신 리액트 컴포넌트처럼 html을 반환하라는 함수를 만들라고 하셨던게 이런 방식이 맞을까요...?
리액트로 바꾸려다 보니까 그대로 못쓰고 직접 div 태그 만들고 className 붙여야 하던데... 제가 잘 이해하지 못한건지 궁금함니다..!

function ProductSelector() {
const container = document.createElement('div');
  container.className = 'mb-6 pb-6 border-b border-gray-200';
  container.innerHTML = `
    <select id="product-select" class="w-full p-3 border border-gray-300 rounded-lg text-base mb-3"></select>
    <button id="add-to-cart" class="w-full py-3 bg-black text-white text-sm font-medium uppercase tracking-wider hover:bg-gray-800 transition-all">Add to Cart</button>
    <div id="stock-status" class="text-xs text-red-500 mt-3 whitespace-pre-line"></div>
  `;
  return container;
}

@eveneul
Copy link

eveneul commented Jul 31, 2025

유진 공주님 파이팅~~

@Elli-Lee
Copy link
Author

Elli-Lee commented Aug 2, 2025

** [페어4팀 과제리뷰 - 코드 중심] **
부족한점 이실직고!

  • 매직넘버를 아직 다 바꾸지 못함
  • ui 덜 쪼갰음
  • for문을 map으로 바꿨어야 하는데.....
  • 상태 바뀔 때 최소한만 렌더링 하는게 아니고 전체 리렌더할거에요....
    등등... 아직 너무 많아요!

궁금한점

  • DOM API 대신 리액트 컴포넌트처럼 html을 반환하라는 함수를 만들라고 하셨던게 아래 방식이 맞을까요...? 리액트로 바꾸려다 보니까 그대로 못쓰고 직접 div 태그 만들고 className 붙여야 하던데... 제가 잘 이해하지 못한건지 궁금함니다..!

<button id="add-to-cart" class="w-full py-3 bg-black text-white text-sm font-medium uppercase tracking-wider hover:bg-gray-800 transition-all">Add to Cart</button>
<div id="stock-status" class="text-xs text-red-500 mt-3 whitespace-pre-line"></div>
`;
return container;
Copy link
Author

Choose a reason for hiding this comment

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

(위에 궁금한점에 대한 부분!) 요런식으로 하는게 맞을까요....?

Copy link

Choose a reason for hiding this comment

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

안녕하세요 공주님~ 저는 일단 리액트처럼

function Select({ id, className, options }) {
  return `
    <select id="${id}" class="${className}">
      ${options.map((option) => option).join('')}
    </select>
  `;
}

이런 방식을 채택했습니다.
처음 저는 클래스지만 유진님처럼 const container = document.createElement('div')를 하려고 했으나
불필요한 div가 생기는 것도 싫었고, select 같은 것도 컴포넌트를 나눠야 하는데
select 부모로 또 div를 만든다? 흠좀무... 인 것 같아서요. (일단 저는 div 많은 거 싫어합니다. 시맨틱 마크업 주의자 ✨)

Copy link

Choose a reason for hiding this comment

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

렌더링을 담당하는 부분을 따로 구현했다면 html을 반환하는 식으로 만드셔도 될 것 같은데,
그렇지 않다면 어쩔 수 없는 방법 아닐까요 ?!!

Copy link

Choose a reason for hiding this comment

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

음.. 위 코드에서는 여전히 DOM API를 사용하고 있는데요!
DOM API 대신 template literal로 문자열을 리턴하고, 호출하는 쪽(부모 엘리먼트)에서 innerHTML로 할당하는 것도 괜찮을 것 같아요!

Choose a reason for hiding this comment

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

/**
 * 헤더 요소 생성
 * @returns {HTMLElement} 생성된 헤더 요소
 */
function createHeader() {
  const header = document.createElement('div');
  header.className = 'mb-8';
  header.innerHTML = `
    <h1 class="text-xs font-medium tracking-extra-wide uppercase mb-2">🛒 Hanghae Online Store</h1>
    <div class="text-5xl tracking-tight leading-none">Shopping Cart</div>
    <p id="item-count" class="text-sm text-gray-500 font-normal mt-3">🛍️ 0 items in cart</p>
  `;
  return header;
}

저의 AI는 이런식으로 구현을 해주셨네요.
저도 가능하면 시맨틱 마크업을 지키는게 더 낫다고 보입니다~!

@BangDori
Copy link

BangDori commented Aug 3, 2025

@Elli-Lee

유진님 이번 과제하신다구 정말 고생 많으셨습니다~~!! PR 내용을 읽으면서 어떤 마음가짐으로 임하셨는지를 상상해보니, 과제를 위해 정말 고민과 시도를 하셨다는 게 느껴졌어요. 그리고 리팩토링 후 기대했던 모습과 실제 완성된 결과를 비교해주신 표현도 너무 인상 깊었어요 ㅋㅋㅋ

리팩토링을 계획적이고 구조적으로 큰 틀을 잡고 진행하지 못했고, 그냥 그때그때 보이는 걸 조금씩 고쳤습니다. 조금씩 고치다가 마지막에 결과물을 돌아보니, 불규칙한 모양의 돌을 반질반질한 하트 모양으로 조각하고 싶었으나 거칠거칠한 삼각형으로 조각한 느낌입니다.

유진님이 이 부분을 약간 아쉽게 느끼신 것 같지만, 저는 오히려 이게 클린 코드를 향한 리팩토링의 가장 현실적이고 자연스러운 시작이라고 생각했어요. 저희는 어떻게 보면 React나 Vue 프레임워크가 개발하도록 편리하게 제공해주는 라이프 사이클이나 내부 코어 로직안에서 개발을 하고 있었기에, 처음부터 아키텍처를 설계하고 update, effect, state처럼 내부 코어 로직을 계획적으로 나누는 건 사실상 쉽지 않잖아요.

그럼에도 이번 과제를 통해, 어디서 어려움을 느꼈는지, 어떻게 나아가야 하는지 그리고 무엇을 배우고 다시 도전해볼 수 있을지 스스로 명확하게 정리하신 것 같아요. 그 과정을 겪었기 때문에 지금은 “다시 한다면 더 잘할 수 있을 것 같다”는 확신도 생긴 거고, 그게 이번 과제의 가장 큰 수확 아닐까요? 👏👏

이번 회고 글을 통해 저도 많이 배우고 갑니다! 정말 멋있어요!

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