리팩토링하며 신경썼던 것들에 대해

혜린·2022년 12월 18일
8

Project

목록 보기
7/8
post-thumbnail

들어가며

프로젝트할 때 기능 구현에만 급급해
좋은 코드를 작성하지 못했다는 생각이 들었다.

9월에 진행했던 프로젝트 코드를 다시 들여다보니
컴포넌트가 분리되어 있지 않아 가독성이 떨어졌으며,
동일한 로직을 반복하여 작성한 경우도 많았고,
함수명도 분명하지 않은 등..고쳐야할 부분이 많이 보였다.

리팩토링에 더해 TypeScript와 Redux를 공부해 적용해보기도 했던 지난2주!
리팩토링을 하며 내가 신경쓰며 진행했던 부분에 대해 정리해놓고자 한다.

👩🏻‍🔧 리팩토링 (Refactoring)
프로그램의 외부 동작은 그대로 둔 채, 내부의 코드를 정리하면서 개선하는 것


1. 컴포넌트의 분리🧩

왼쪽의 코드가 리팩토링 이전의 코드다.
한 파일, 한 컴포넌트에 한 페이지에 대한 거의 모든 내용을 담아냈었다.
내가 작성한 코드였고, 기능 구현에만 급급했기에
가독성에 대해 생각하지 못했었다.

그로부터 2-3달 정도가 지났기에
내가 작성한 코드임에도 파악하는 것이 쉽지 않았다.
어디서부터 어디까지가 어떤 기능을 하는지 하나하나 확인을 해야했다.

나조차도 이런데, 다른 사람이 이 코드를 보면 어떨까란 생각이 들었다.
그래서 컴포넌트를 최대한 분리하기 시작했다.
그러자 가독성도 좋아졌으며, 구조를 파악하기가 훨씬 좋았다.


2. 이미지 용량 줄이기📸

lighthouse로 해당 프로젝트에 대한 성능을 점수로 확인할 수 있었다.
LCP(Largest Contentful Paint)에 영향을 미치는 요소 중 하나인 <img>. 이미지 로딩에 차지하는 시간이 큰 듯했다.

widthheight를 명시적으로 지정해주거나
다양한 버전의 크기를 지정해놓는 등 여러 방법이 있었는데,
우선 jpeg 파일 형식 자체가 용량이 크다고 판단했다. (png는 더 크고..╚(•⌂•)╝)
그래서 우선 메인 페이지의 이미지 슬라이드(캐러셀)에 들어가는
이미지 확장자를 avif로 변환해 바꿔주었다.

웹 성능이 20점이 넘게나 높아지는 걸 확인할 수 있었다.😱
(메인페이지에 들어가는 이미지가 많은데 이미지 슬라이드에 해당되는 이미지만 변환시켜주어서 아직 성능이 썩 좋진 않다..)


3. 로직 분리🍛

장바구니 페이지나, 찜목록 페이지나 전체 데이터를 받아오는
api호출 내용이 동일한데, 불필요하게 반복되고 있다는 생각이 들었다.

Custom Hook을 사용해 각 페이지에서 useFetch를 가져다가 사용할 수 있었다.
하지만, 각 페이지에서 받아온 데이터는 store에서 전역적으로 관리되고 있었다.
두 데이터를 구분지어 받아오는 것이 필요하다고 생각해
장바구니인지 찜목록인지 구분할 수 있는 인자를 추가적으로 넣었다.

지금까지 고안해낸 방법은 이러한 방식인데,
최선의 방법은 아니란 생각이 들어서 차차 보완해나갈 생각이다.

// useFetch.tsx
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
import { getData, getLikeData } from '../store/slices';

function useFetch(url: string, title: string) {
  const dispatch = useDispatch();
  const requestHeaders: HeadersInit = new Headers();
  const accessToken = localStorage.getItem('accessToken');
  requestHeaders.set('authorization', accessToken || 'Token not found');

  useEffect(() => {
    fetch(url, {
      headers: requestHeaders,
    })
      .then(response => {
        if (response.ok) {
          return response.json();
        }
        throw new Error('에러 발생!');
      })
      .catch(error => {
        alert(error);
      })
      .then(data => {
        if (title === 'cart') dispatch(getData(data));
        if (title === 'like') dispatch(getLikeData(data));
      });
  }, []);
}

export default useFetch;

4. 상수데이터 관리📂

Footer와 같은 경우, 상수데이터가 정말 많았다.
상수데이터를 따로 관리해 사용하지 않다보니,
나중에 유지보수하기가 정말 힘들겠단 생각이 들었다.

지금이야 작은 팀프로젝트이니 크게 문제가 되지 않겠지만
만약 정말 많은 상수값이 코드에 녹여져있는데
수정을 해야하는 상황이 온다면..?
상수데이터가 분리되어 있지 않다면 얼마나 불편할까.

'고객센터'를 'CS Center'라는 문구로 바꾼다고 가정해본다면,
상수데이터화 시켜놓지 않은 코드는 '고객센터'라는 문구를
전부 찾아 일일이 바꿔줘야할 것이다.🤧
그런상황이 오지않게 미리미리 연습해두자!

// FooterConstant.jsx
export default {
  // 생략
  CS_CENTER: {
    CENTER: [
      {
        TITLE: '고객센터',
        NUMBER: '1644-9825',
        EMAIL: 'eogh773@Naver.com',
      },
      {
        TITLE: '기업선물',
        NUMBER: '010-3633-3190',
        EMAIL: 'order@hush.co.kr',
      },
    ],
    CONTACT: [
      {
        TITLE: '상담전화',
        HOUR: '13:00 16:00(평일)',
      },
      {
        TITLE: '상담톡',
        HOUR: '10:00 16:00(평일)',
      },
    ],
  },
}

마치며

약 2주에 걸쳐 리팩토링을 진행하며
리팩토링에 끝이 존재하긴 할까..란 생각이 가장 많이 들었다.
손을 대면 댈수록 손을 대야할 부분이 계속 눈에 보였고,
고치고 고쳐도 더 나은 코드로 만들 수 있을 것만 같았다.

보수공사는 계속해서 필요한거니까!👩🏻‍🔧
이대로 1차 프로젝트에 대한 리팩토링을 종료할 생각은 없다.
2차 프로젝트 리팩토링을 하며
또 깨닫는 점이 있다면 1차 프로젝트에도 이어서 적용시켜서
더 나은 코드로 점점 발전시키고 싶다.🛬🛫

profile
FE Developer

0개의 댓글