[우아한테크코스 6기 프리코스] 3주차 회고

jkpapa·2023년 11월 8일
0

우아한테크코스

목록 보기
3/3

코드 저장소 링크

벌써 3주차라니! 프리코스도 끝나가는군요. 이번 주 미션에서는 난이도가 높아졌다는게 체감되는 미션이었습니다.

뭔가 객체지향스럽게 코딩을 한 것 같기도하고 아닌 것 같기도 한 요상한 느낌이 들었습니다. 이번 주에는 굉장히 바빠서 미션을 월요일에서야 시작했네요 🥲

급하게 우다다닥 구현하느라 놓친부분이 많겠지만 그럼에도 역시 깊은 고민을 해볼 수 있는 미션이었습니다.

고민한 내용

🤔 함수를 어떤 기준으로 분리할까?

2주차에도 여러가지 공통 피드백이 있었는데요. 굉장히 뜨끔 했던 피드백이 있었습니다.

한 함수가 한 가지 기능만 담당하게 한다.

사실 저는 1주차부터 사용자에게 입력을 받고, 유효성 검사까지를 하나의 함수에 묶어서 구현을 진행했습니다.

const getUserInput = async (prompt, checkValid) => {
  const inputValue = await Console.readLineAsync(prompt);
  const isValidInput = checkValid(inputValue);

  if (!isValidInput) {
    throw Error(ERROR_MESSAGE.INVALID_INPUT);
  }

  return inputValue;
};

매개변수로 유효성 검사함수를 받아서 중복 작업을 없애고 싶었기 때문입니다. 스스로 구현하고 재사용성이 뛰어나서 만족하는 함수였는데... 클린코드 관점에서는 좋지 못한 코드였습니다.

그럼 함수에서 하나의 일을 하는지 어떻게 판단할 수 있을까요?
저는 함수 네이밍을 바탕으로 기준을 잡았습니다.

함수의 이름이 명시하는 일만하도록 만들자

예를 들어 getUserInput이라는 함수는 이름 그대로 사용자의 입력을 반환하는 역할만을 해야할 것입니다. 그렇다면 입력값에 대한 유효성을 검사하는 함수는 따로 빼두는 것이 맞겠죠.

const input = async (inputPrompt) => {
  const inputValue = await Console.readLineAsync(inputPrompt);
  return inputValue;
};

input함수는 입력만받고 그 값을 반환하는 역할만 하는겁니다.

🤔 if문을 최대한 줄여보자

이번 주 미션을 진행하면서 가장 고민했던 부분입니다. 요구사항에는 다양한 조건이 명시되어 있는데, 들여쓰기를 최대 2회만 허용하는 미션이었기 때문입니다.

if문이 많으면 많을 수록 깊이가 깊어질수록 어떤 조건에서 어떤 일이 발생하는지 확인하기 정말 힘들어집니다. 마침 저 역시 우아하게 분기처리하는 것에 대해서 관심이 많았는데 이번 기회에 도전해보기로 했습니다.

  1. 입력값 유효성 검사에 if문 하나만 사용하기

이번 미션에는 총 3종류의 입력을 받았습니다. 게다가 이번 주에는 공통 피드백 사항으로 여러가지 예외상황을 생각하라는 내용이 있었습니다. 입력 값 하나에서 상상할 수 있는 예외 상황은 정말 다양했고 이 많은 유효성 검사를 해야하는 상황에서 조건문을 최소한으로 사용하고 싶었습니다.

예를 들어서 첫 번째 입력으로 로또 구입 금액을 입력받는데, 상상해 볼 수 있는 경우를 몇 가지만 들어보겠습니다.

  • 입력한 값이 1000원으로 나누어 떨어지지 않는 경우
  • 숫자만으로 이루어지지 않은 경우

저는 저번 주 미션까지는 이런 예외 상황을 판단하는 함수를 하나씩 만들어서 모두 검사하는 방식으로 구현했습니다.

const isValidCost = (inputValue) => {
  const isNumber = isNumberString(inputValue);
  const isDivideUp = NUmber(inputValue) % 1000 === 0;
  const isValid = isNumber && isDivideUp;
  
  if (!isValid) {
    throw new Error('[ERROR] 에러 메시지');
  }
  
  return isValid;
}

이 방식은 단점이 몇 가지 존재합니다.
첫째, 새로운 유효성 검사함수를 구현한다면 isValidCost함수도 수정해야 한다.
둘째, 유효성을 만족하지 못하는 경우는 다양하지만 에러 메시지를 하나 밖에 사용하지 못한다.

두번째 문제 같은 경우에는 에러 메시지를 따로 매개변수로 받아 해결 할 수는 있을 것입니다. 하지만 첫 번째 문제인 유지보수가 비교적 힘들다는 문제는 해결되지 않은 상태로 남아있게 됩니다.

그럼 첫 번째 문제를 해결하기 위해서는 조건이 추가되거나 변경되더라도 isValidCost의 함수는 변경되지 않아야 하겠죠. 유효성 검사를 하는 함수들은 모두 공통적으로 다음과 같은 작업을 진행합니다.

  • 설계한 모든 상황을 반드시 검증해야 한다.
  • 만약 유효하지 않은 입력이라면 에러를 throw한다.

결국 달라지는 것은 검증하는 예외 상황들, 에러 메시지이므로 이 데이터들을 매개변수로 받으면 해결되는 문제였습니다. 이를 근거로 저는 다음과 같은 객체 하나를 설계하게 되었습니다.

const checkObject = {
  check: 유효성_검사_함수(),
  errorMessage: '에러_메시지' // 유효하지 않은 입력의 유형을 나타낼 수 있음
}

이 객체를 배열로 checkList를 만들어 모든 유효성을 검사하는 것입니다. 함수 내에서 여러개의 if문을 사용할 필요도 없고, 만약 조건이 변경되더라도 제가 만든 배열만 수정하면 유효성 검사함수가 알아서 판단을 진행하게 됩니다.

좋았던 점

강제 push 0회!

지난 주에 아쉬운 점으로 남았던 강제 푸시를 이번 주 미션에서 하지 않았습니다. 로컬에서는 커밋 메시지를 쉽게 변경할 수 있지만 원격 저장소로 push 된다면 변경하기 어렵고 이게 만약 팀 프로젝트였다면 강제 푸시로 인해 팀원이 번거러워 질 가능성이 많아지겠죠.

원격 저장소로 push하기 전에 git log를 통해 메시지가 제대로 작성되었는지 확인한는 아주 좋은 습관을 기른 것 같아서 뿌듯합니다.

요구사항 다시 확인하기

지난 주 미션에서 제가 요구사항을 잘못해석했습니다. 테스트는 통과 되지만 기능적으로 알맞는 구현이 아니었습니다.

이번 주에는 지난 미션과는 다르게 입력과정에서 새로운 요구사항이 있었는데, 그 부분을 놓치지 않고 잘 구현했습니다. 조금은 성장했을까? 하는 생각을 가지게 해서 좋았습니다.

분기처리 고민하기

요구사항에 들여쓰기에 대한 제한이 있다는 것을 확인하고 분기 처리를 어떻게 해야할지 고민을 많이했습니다. 인터넷에 여러 자료들을 찾아봤는데, 객체를 이용한 분기처리 패턴이 인상깊어 이번 미션에 적용해봤습니다.

과거 프로젝트나 코딩 과제를 진행할 때, 정말많은 if문, 중첩된 if문을 사용했었는데 코드자체가 스파케티처럼 꼬여서 제가 만들었지만 무슨 목적으로 만들어졌는지 이해못하는 경우가 많았습니다.

분기되는 조건을 key, 그리고 행동을 value로 정의하고 객체로서 정리하니 유지보수가 괜찮은 코드가 만들어진 것 같습니다. 저만의 코딩 스타일을 하나 더 만들어 낸 것 같은 느낌입니다.

아쉬운점

클래스마다 역할을 잘 부여한 것이 맞나?

저는 이번 미션에서 총 세개의 클래스를 관리했습니다. 전체적인 애플리케이션의 흐름을 담당하는 App, Lotto, 그리고 당첨 결과를 연산하는 Computer였습니다. App, Computer는 굉장히 덩치가 큽니다.

메소드마다 15줄 이내로 작성하려고 노력했고, 분리를 지향했지만 클래스마다 구현된 메소드의 양이 많다는 판단이 들었습니다. 좀 더 명확한 역할을 부여할 수 있는 클래스를 만들 수 있었을 것 같은데 이 부분이 아쉬운 점입니다.

4주차 때는 !...

프리코스의 마지막인 만큼 정성스럽게 코드를 작성하려고 합니다. 명확한 역할을 부여하고 나만의 기준으로 분리하고 조합하는 과정을 거치면서 자신 만의 코드 스타일을 발전시키고 싶습니다.

0개의 댓글