클린코드

[DAY 10] 클린 코드 TIL - 미션. 코드 리팩토링

lado 2022. 1. 31. 22:57

미션! 더러운 코드를 고쳐라!

const merry = document.querySelector(".js-clock");

function getClock() {
const christmas = new Date("2021, 12, 25");
const date = new Date();
const timeGap = christmas - date;

const xDay = Math.floor(timeGap / (1000 * 60 * 60 * 24));
const xHours = Math.floor(
(timeGap - xDay * 1000 * 60 * 60 * 24) / (1000 * 60 * 60)
);
const xMinutes = Math.floor((timeGap % (60 * 60 * 1000)) / (60 * 1000));
const xSeconds = Math.floor((timeGap % (60 * 1000)) / 1000);

const day = String(xDay).padStart(2, "0");
const hours = String(xHours).padStart(2, "0");
const minutes = String(xMinutes).padStart(2, "0");
const seconds = String(xSeconds).padStart(2, "0");

merry.innerText = `${day}d ${hours}h ${minutes}m ${seconds}s`;
}

getClock();
setInterval(getClock, 1000);

고친 코드

const $dDayClock = document.querySelector(".js-clock");

const printTimeLeftUntilChristmas = () => {
  const datePhrase = getDatePhraseOfTimeLeftUntilChristmas();
  $dDayClock.textContent = datePhrase;
};

const getDatePhraseOfTimeLeftUntilChristmas = () => {
  const currentDate = new Date();
  const christmasDate = getNextChristmasDateFrom(currentDate);
  return getDatePhraseOfTimeGapFromDateUntilDate(currentDate, christmasDate);
};

const getNextChristmasDateFrom = (currentDate) => {
  const currentYear = currentDate.getFullYear();
  return new Date(`${currentYear}, 12, 25`);
};

const getDatePhraseOfTimeGapFromDateUntilDate = (fromDate, untilDate) => {
  const timeGapUntilChristmas = getMillisecondsFromDateUntilDate(
    fromDate,
    untilDate
  );
  const rawDateObjectOfTimeGap = convertMillisecondsToDateObject(
    timeGapUntilChristmas
  );
  const { days, hours, minutes, seconds } = getDateObjectMatchedDigits(
    rawDateObjectOfTimeGap
  );

  return `${days}일 ${hours}시 ${minutes}분 ${seconds}초`;
};

const getMillisecondsFromDateUntilDate = (fromDate, untilDate) => {
  return untilDate - fromDate;
};

const convertMillisecondsToDateObject = (milliseconds) => {
  const date = {};

  const oneSecond = 1000;
  const oneMinute = oneSecond * 60;
  const oneHour = oneMinute * 60;
  const oneDay = oneHour * 24;

  const remainderAfterDivisionBy = {
    days: milliseconds % oneDay,
    hours: milliseconds % oneHour,
    minutes: milliseconds % oneMinute,
  };

  date.days = Math.floor(milliseconds / oneDay);
  date.hours = Math.floor(remainderAfterDivisionBy.days / oneHour);
  date.minutes = Math.floor(remainderAfterDivisionBy.hours / oneMinute);
  date.seconds = Math.floor(remainderAfterDivisionBy.minutes / oneSecond);

  return date;
};

const getDateObjectMatchedDigits = (rawDateObject) => {
  const date = {};

  for (const [key, value] of Object.entries(rawDateObject)) {
    key === "days"
      ? (date[key] = pad0ForMatchingDigit(value, 3))
      : (date[key] = pad0ForMatchingDigit(value, 2));
  }

  return date;
};

const pad0ForMatchingDigit = (number, digit) => {
  return String(number).padStart(digit, "0");
};

const init = () => {
  printTimeLeftUntilChristmas();
  setInterval(printTimeLeftUntilChristmas, 1000);
};

init();

🧐 리팩토링 포인트

  • 기능 별로 여러 개의 함수로 쪼갰다.
  • 확장성을 높이기 위해 보편적으로 사용 가능한 부분과 특정 상황에서만 사용 가능한 부분을 분리해 각각 함수로 만들었다.
  • 코드의 의미 파악을 돕기 위해 수식과 상수에 변수명을 붙였다.
  • 중복되는 작업을 for문으로 처리하기 위해 자료 구조를 객체로 반환했다.

📌 소감 3줄 요약

  • 정확한 함수의 의도를 함수명에 담으려고 하니까 함수명이 많이 길어져서 가독성이 더 나아졌는지 헷갈린다.
  • 함수를 호출한 순서대로 적는 게 좋을지 지금 코드 독해 맥락에서 가장 중요한 부분부터 적는 게 좋을지 고민이 됐다.
  • 인수의 숫자를 줄여보려고 했지만 어쩔 수 없이 쓰게 되는 부분들이 있는데 함수명에서 인수의 존재를 암시해야 하는 부분이 어려웠다.