[우테코] 1주 차 미션 풀이(+코드 리뷰), 회고

비얌·2022년 11월 2일
6
post-thumbnail

개요

저번 주에 블로그에 [우테코] 지원 이야기 + 프리코스 준비를 쓴지가 엊그제같은데, 벌써 일주일이 흘렀다.

그동안 온보딩(새로운 직원이 조직에 잘 적응할 수 있도록 지식이나 기술을 교육하는 과정)이라고 불리는 1주 차 미션이 진행되었는데(22.10.26 ~ 22.11.1), 웹 프론트엔드, 웹 백엔드, 안드로이드 트랙 모두 온보딩 문제로 같은 7개의 문제를 풀었다.

일단 문제들을 어떻게 풀었는지 알아보자. 공지에 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행한다.라고 적혀있으므로, 문제마다 구현할 기능 목록을 작성하고 이를 구현할 때마다 커밋을 했다.

1주 차 미션 코드를 제출한 나의 Pull Request 주소(굳이 들어가서 볼 필요는 없는 코드이다,,)


미션에 들어가기에 앞서 공부한 것

코드를 작성하기 전에 공부한 것이 두 가지 있는데, 바로 자바스크립트 컨벤션커밋 메시지 컨벤션이다. 미션이 끝난 후 코치님들 혹은 다른 지원자들이 나의 코드를 읽을 수 있으므로 아무도 알아볼 수 없는 평소의 코드처럼 작성할 수는 없다고 느꼈다.


공부에 참고한 URL은 다음과 같다.

<자바스크립트 컨벤션>
자바스크립트 코딩 컨벤션에 대한 글
자바스크립트 네이밍 컨벤션에 대한 글
NHN FE개발랩

<커밋 메시지 컨벤션>
Conventional Commits


그리고 고민..

지금껏 파이썬으로만 알고리즘 문제를 풀었지, 자바스크립트로 문제를 풀어본 적은 없다. 그래서 자바스크립트의 내장 함수를 적절하게 사용하지 못해 2줄이면 끝날 코드를 20줄을 쓰곤 했던 것 같다.


코드 수정할 때 참고한 코드

이번 포스팅에서는 코드 리뷰 스터디 팀원 중 한 분인 민재 님의 코드와 리뷰를 바탕으로 개선점을 알아볼 것이다. 여러 명의 코드를 모두 분석하기는 힘들 것 같아 멋진 코드를 작성하신 민재 님의 코드를 분석하였다.(민재 님께는 출처를 밝히고 블로그에 써도 된다고 허락받았다.) (+ 이제는 다른 분들의 피어 리뷰도 추가했다)


<이번 포스팅 목차>
1. 1~7번 문제 풀이(+ 코드 리뷰)
2. 1주 차 공통 피드백
3. 1주 차 회고



1. 1~7번 문제 풀이(+ 코드 리뷰)

1번

문제 설명

1번 문제는 포비와 크롱이 편 페이지를 입력으로 받아 각 페이지 번호를 더하거나 곱하여 각각의 가장 큰 수를 구하고, 이를 서로와 비교하였을 때 더 큰 수를 가진 사람이 누구인지 반환하는 문제이다.


구현 기능 목록

구현해야 할 기능 목록은 다음과 같다.

  • 제시된 입력 받기 ⭕
    • pobi와 crong의 [왼쪽 페이지, 오른쪽 페이지]를 컴퓨터로부터 입력받기 ⭕
    • (예외 1) 왼쪽 페이지와 오른쪽 페이지가 불연속되면 안 됨 ⭕
    • (예외 2) 왼쪽 페이지는 홀수, 오른쪽 페이지는 짝수여야 함 ⭕
    • (예외 3) 오른쪽 페이지는 왼쪽 페이지보다 한 쪽수 많아야 함 ⭕
    • (예외 4) 시작 면이나 마지막 면이 나오면 안 됨 ⭕
  • 각각의 점수 계산하기 ⭕
    • 왼쪽 페이지 계산 시 가장 큰 수 구하기 ⭕
    • 오른쪽 페이지 계산 시 가장 큰 수 구하기 ⭕
    • 위 둘 중 큰 수를 구하여 내 점수로 하기 ⭕
    • 승패 나누기 ⭕
    • 각각의 점수를 비교 ⭕
    • 높은 사람이 이김 ⭕
  • 결과 출력하기
    • pobi가 이기면 1 출력 ⭕
    • crong이 이기면 2 출력 ⭕
    • (예외)는 -1 출력 ⭕

나의 코드와 개선점(with 피어 리뷰)

1) 에러처리만을 하는 함수를 만들자

위의 구현 기능 목록에는 예외 처리해야 할 것이 4개나 있다. 나는 이를 모두 풀어서 작성하였는데, 이를 '에러처리'라는 함수로 묶는 것이 좋을 것 같다는 리뷰를 받았다.

예외 처리에 관한 나의 코드는 다음과 같다.

// 내 코드
function problem1(pobi, crong) {
  // 예외 처리
  if (pobi[1] !== (pobi[0] + 1) || crong[1] !== (crong[0] + 1)) {
    answer = -1;
    return answer;
  } 
  if (pobi[0] % 2 === 0 || pobi[1] % 2 === 1 || crong[0] % 2 === 0 || pobi[1] % 2 === 1) {
    answer = -1;
    return answer;
  }
  if (pobi[0] === 1 || pobi[0] === 399 || pobi[1] === 2 || pobi[1] === 400 || crong[0] === 1 || crong[0] === 399 || crong[1] === 2 || crong[1] === 400) {
    answer = -1;
    return answer;
  }
  if (pobi[0] < 1 || pobi[0] > 400 || pobi[1] < 1 || pobi[1] > 400 || crong[0] < 1 || crong[0] > 400 || crong[1] < 1 || crong[1] > 400) {
    answer = -1;
    return answer;
  }
}

module.exports = problem1;

굉장히 장황한 것을 알 수 있다. 함수로 묶으면 좋을 것 같다고 리뷰해주신 민재 님의 코드를 허락받고 가져와봤다.

exceptionChecker라는 함수를 만들어 예외 처리를 하고 있는데, 나처럼 pobi와 crong을 함께 비교하는 것이 아니라 pobi와 crong을 각각 따로 비교한 후 || 연산자로 pobi와 crong의 값이 모두 참(예외가 아닌)인지 계산했다.

하나하나 비교할 생각만 했지, 이렇게 각각 비교하는 함수를 만들어 ||로 잇는 생각은 해보지 못해서 신기했다. 이 코드가 훨씬 더 가독성 있게 읽힌다!

// 민재 님 코드
function exceptionChecker(array) {
  if(!Array.isArray(array)) return false;
  if(array.length !== 2) return false;
  if(array[0]%2 !== 1 || array[1]%2 !== 0) return false;
  if(array[1]-array[0] !== 1) return false;
  if(array[0] < 1 || array[1] > 400) return false;
  array.forEach((index) => {
    if(!Number.isInteger(index)) return false;
  });
  return true;
}

function problem1(pobi, crong) {
  if(!exceptionChecker(pobi) || !exceptionChecker(crong)) return -1;
  const answer = compareScore(getScore(pobi), getScore(crong));

  return answer;
}

module.exports = problem1;

2) reduce 함수 사용하기

아래의 부분을 reduce 함수를 사용해 작성하는 것이 어떻냐는 리뷰를 받았다.

// 내 코드
for (let i = 0; i < arr.length; i++) {
  sum += arr[i]
}

민재 님은 아래와 같이 reduce를 사용하고 계셨다. 찾아보니 reduce는 배열의 요소들을 순회하면서 반복적인 연산을 하는 메서드라고 한다.

// 민재 님 코드
leftPageNumber.reduce((prev, current) => prev + Number(current), 0)

항상 파이썬으로 문제를 풀며 sum이라는 내장 함수를 사용하다가 자바스크립트에는 sum이라는 함수가 없다는 것을 알고 for문으로 하나하나 더해줬었다. 그런데 이렇게 유용한 함수를 알게 되어서 기뻤다!


3) 변경하지 않을 값은 let 대신 const를 사용하자

기존에는 포비의 왼쪽 페이지의 합을 저장하는 변수로 pobiLeftSum을 let으로 선언하였다. 하지만 유지 보수적인 측면을 고려해 값을 수정할 수 있는 let보다는 값을 수정할 수 없는 const를 사용하는 것이 좋을 것 같다는 리뷰를 받았다. 사실 이번 미션에서 습관적으로 let을 쓰고 const를 사용한 적이 거의 없는 것 같아 반성했다.

let pobiLeftSum = letterSum(pobi[0]);

4) 삼항 연산자로 간결하게 나타내자

if - else if - else 문을 삼항 연산자로 간결하게 나타낼 수 있을 것 같다는 피드백을 받았다.

// 내 코드
if (pobiResult > crongResult) {
    answer = 1
  } else if (crongResult > pobiResult) {
    answer = 2
  } else {
    answer = 0
// 고친 코드
answer = pobiResult > crongResult ? 1 : crongResult > pobiReuslt ? 2 : 0

삼항 연산자는 조금만 복잡해지면 어려워지는 것 같다..

위의 삼항연산자는 아래와 같은 뜻이라고 한다. 그러니까 if pobiResult가 crongResult보다 크면 1이고 else if crongResult가 pobiResult보다 크면 2이고 아니면 else 0이 된다...

answer =
    pobiResult > crongResult ? 1 :
    crongResult > pobiResult ? 2 : 0

2번

문제 설명

2번 문제는 연속된 문자를 차례대로 지워나가서 남은 문자가 무엇인지 알아맞히는 문제이다. 문제의 예시를 보면 browoanoommnaon은 o와 m이 각각 연속되므로 첫 단계에서는 이 둘을 모두 지워준다. 그러면 browoannon이 남는데, 여기서는 n이 연속됨을 알 수 있다. 그래서 그다음 단계로 n을 모두 지우면 browoaaon이 나오고, 그다음에도 이전과 같이 연속된 문자를 지워나가면 된다.


구현 기능 목록

  • 입력받기 ⭕
    • 길이가 1 이상 1000 이하인 문자열 cryptogram을 컴퓨터로부터 입력받기 ⭕
    • 문자열은 소문자로만 이루어져 있다 ⭕
  • 중복 문자 삭제하기 ⭕
    • 한 문자가 2개 이상 이어져 있으면 그 문자열을 삭제하기 ⭕
      • 문자열을 수정하기 용이하도록 배열로 만들기 ⭕
      • 일단 연속되는 X 중복되는 O 문자를 구하여 배열로 만들기 ⭕
      • 그 중복되는 문자가 연속되면 얀속되는 문자의 인덱스를 모두 구해 배열로 만들기 ⭕
      • for문으로 그 인덱스가 있는 배열을 돌며 문자열의 배열에서 연속된 문자 삭제하기 ⭕
    • 중복된 문자가 더 이상 없을 때까지 위의 과정을 반복하기 ⭕
  • 출력하기 ⭕
    • 결괏값을 반환하기 ⭕

나의 코드와 개선점(with 피어 리뷰)

1) 정규표현식 사용하기

사실.. 나처럼 풀 필요가 없었다. 정규식을 사용하면 간단하게 풀리는 문제였다.

실제로 민재 님의 코드에 따르면 아래와 같이 정말 간단하게 풀린다.

// 민재 님 코드
function decrypting(cryptogram) {
  const regExp = /(\w)\1+/g;
  while(cryptogram !== cryptogram.replace(regExp, ""))
    cryptogram = cryptogram.replace(regExp, "");
  return cryptogram;
}

function problem2(cryptogram) {
  const answer = decrypting(cryptogram);

  return answer;
}

module.exports = problem2;

여기서 /(\w)\1+/g의 의미는 무엇일까?
👉 \w는 알파벳과 숫자를 의미한다. 그리고 ()에 감싸져 있어 하나의 그룹이 된다.
\1은 첫 번째 그룹을 재사용한다는 뜻이다. \w가 첫 번째 그룹이 된다.
+는 앞에 있는 것이 1개 이상 있어야 한다는 뜻이다. 그래서 \1이 1개 이상 있어야 한다. 따라서 \w가 두 개 이상 오는 것을 찾는 정규식이다.
/g는 문자열 전체에 대해 탐색한다는 뜻인 것 같다.

정규표현식을 배울 수 있는 사이트
정규 표현식 시작하기
정규식 테스트하기


나는... 55줄이 나왔는데...^_^ 얼마나 나왔는지를 짐작하기 위해 내 코드를 가져와 봤다ㅎㅎㅎㅎ 이 글을 보시는 분은 내용은 보지 말고 코드양만 보시면 될 것 같다... 정규식으로 이렇게 긴 코드가 한번에 정리될 수 있다는 중요한 사실을 알게 되었다!

// 내 코드
function problem2(cryptogram) {

  let array = cryptogram.split("");

  // 전체에서 중복되는 문자 구하기
  const findDuplicates = function(arr) {
    let filtered = arr.filter((item, index) => arr.indexOf(item) !== index)
    return [...new Set(filtered)];
  }
  const duplicateArray = findDuplicates(array);

  let sum = 1;
  // 전체에서 연속되는 문자가 없을 때까지 while문 돌기
  while(sum !== 0) {
    let indexArray = []
    for (let i = 1; i < array.length; i++) {
      for (let j of duplicateArray) {
        // 연속되는 글자의 인덱스를 index.Array에 추가
        if (array[i] === j && array[i-1] === j) {
          indexArray.push(i-1, i);
        }
      }
    }

    // 실제 글자 배열에서 연속되는 글자 지우기
    indexArray = [...new Set(indexArray)];
    for (let i of indexArray) {
      delete array[i];
    };
    array = array.filter((e) => e !== '');

    // 연속되는 문자가 있는지 확인하여 연속되지 않으면 0, 연속되면 1 추가
    let trueFalseArray = [];
    for (let i = 1; i < array.length; i++) {
      if (array[i] !== array[i-1]) {
        trueFalseArray.push(0);
      } else {
        trueFalseArray.push(1);
      }
    }
    
    // sum이 0: 연속되는 문자가 더이상 없음, sum > 1: 연속되는 문자가 아직 남아있음
    sum = 0;
    for (let i of trueFalseArray){
      sum += i
    }
  }
  
  let answer = array.join('');
  return answer;
}

module.exports = problem2;

3번

문제 설명

3번 문제는 주어진 숫자까지 3, 6, 9가 총 몇 번 들어가 있는지를 출력하는 문제이다.


구현 기능 목록

  • 입력받기 ⭕
    • 1 이상 10,000 이하인 자연수 number를 컴퓨터로부터 입력받기 ⭕
  • 1부터 받은 숫자까지 3, 6, 9가 몇 번이나 들어가는지 확인하기 ⭕
  • 결과 출력하기 ⭕


나의 코드와 개선점(with 피어 리뷰)

1) 의미 있는 변수명을 짓자

아래의 두 코드를 비교해보자. 첫 번째는 나의 코드이고, 두 번째는 민재 님의 코드이다 .

// 나
count = flatArray.filter(element => '3' === element || '6' === element || '9' === element).length;
// 민재 님
count += digitList.filter((digit) => digit == 3 || digit == 6 || digit == 9).length;

나는 filter의 인자를 element라고 지었는데, 이때 element가 무엇인지 파악하려면 한 번 더 생각을 해봐야 했다. 하지만 element 대신 digit라고 이름 지어주면 이 인자가 무엇인지 한 단계 더 생각할 필요 없이 한 번에 알 수 있다.

다음부터는 이렇게 의미없는 변수명을 짓지 말아야겠다고 다짐했다.


2) 3, 6, 9 상수로 선언하기

나는 3, 6, 9를 하드코딩했는데, 이를 상수로 선언하는 것이 좋겠다는 피드백을 받았다.

예를 들면 아래와 같이 말이다.

// 변경한 코드
const NUMBER = ['3', '6', '9'];

3) 문자열을 배열로 변경할 수 있는 방법이 있다!

나는 num을 문자형으로 바꿔 이를 stringArray라는 배열에 push를 이용해 넣었었다. 그런데 더 좋은 방법이 있다고 한다.

// 내 코드
stringArray = []
  for (let num = 1; num < (number + 1); num++) {
    stringNum = String(num);
    stringArray.push(stringNum.split(""))
  }
// 바꾼 코드
// 1번 방법
for(let i = 1; i <= number; i++) {
  let stringArray = [...String(number)]
}
// 2번 방법
for(let i = 1; i <= number; i++) {
  let stringArray = Array.from(String(number))
}

4) num < (number + 1)를 더 나은 방법으로 표현해보자.

num < (number + 1)num <= number로 표현하는 것이 더 나을 것 같다는 피드백을 받았다 그러고보니 이렇게 표현하는 것이 훨씬 더 가독성이 좋은 것 같다!!!


4번

문제 설명

4번 문제는 제시된 청개구리 사전을 이용해 입력된 문자열로 새로운 문자열을 만드는 것이다.


구현 기능 목록

  • 입력받기 ⭕
    • 길이가 1 이상 1,000 이하인 문자열 word 컴퓨터로부터 입력받기 ⭕
  • 변환하기 ⭕
    • 청개구리 사전을 만든다 ⭕
      • for문과 ASCII를 이용해서 딕셔너리를 만들 수 있을 것 같다. ⭕
      • 0~25의 숫자에 65(대문자) or 97(소문자) ⭕
    • 알파벳만 청개구리 사전을 참고하여 변환한다 ⭕
    • 대문자는 대문자로, 소문자는 소문자로 변환한다 ⭕
  • 결과 출력하기 ⭕


나의 코드와 개선점(with 피어 리뷰)

1) 하드코딩 대신 상수를 사용하자

이 문제에서는 아스키코드를 사용해야 했으므로 나는 'A'를 나타내는 65와 'a'를 나타내는 97을 이렇게 직접 써줬다.

for (let i = 0; i < 26; i++) {
    frogDictUpper[String.fromCharCode(i + 65)] = String.fromCharCode(90 - i)
    frogDictLower[String.fromCharCode(i + 97)] = String.fromCharCode(122 - i)
  }

하지만 민재 님은 아래와 같이 상수로 아스키코드를 선언해줬다. 그리고 그것을 ASCIICODE라는 객체에 넣어서 묶어줬다. 이들을 사용할 때도 구조분해할당을 이용해 깔끔하게 할당해줬다. 정말 존경스럽다..!

// 블로그 작성을 위해 중간에 코드 삭제한 부분 있음
const ASCIICODE = {
  UPPERCASE_A: 65,
  UPPERCASE_Z: 90,
  LOWERCASE_A: 97,
  LOWERCASE_Z: 122
}

const { UPPERCASE_A, UPPERCASE_Z, LOWERCASE_A, LOWERCASE_Z } = ASCIICODE;

if(asciiNumber >= UPPERCASE_A && asciiNumber <= UPPERCASE_Z) {

5번

문제 설명

5번 문제는 주어진 money를 오만 원, 만 원, 오천 원, 천 원, 오백 원, 백 원, 오십 원, 십 원 순서대로 몇 개씩 변환되는지를 배열에 담아 반환하는 문제이다.


구현 기능 목록

  • 입력으로 money 받기 ⭕
    • money는 1 이상 1,000,000 이하의 자연수 ⭕
  • money를 특정 단위에 따라 분리하기 ⭕
    • 오만 원권, 만 원권, 오천 원권, 천 원권, 오백 원 동전, 백 원 동전, 오십 원 동전, 십 원 동전, 일원 동전 순으로 분리해야 함 ⭕
  • 출력하기 ⭕
    • money가 단위마다 몇 개씩 변환되었는지 금액이 큰 순서대로 배열에 담아 반환하기 ⭕


나의 코드와 개선점(with 피어 리뷰)

1) 내장함수를 사용하자

배열의 원소를 가져오기 위해 for문을 사용하며 항상 불편했었다. 코드가 길어졌기 때문이다. 그런데 이를 해결해주는 내장 함수가 있었다! 위에서는 reduce를 사용했었는데, 이번에는 forEach라는 함수이다.

아래를 보면 나는 for문으로 moneyTypeList에서 각 원소를 하나하나 가져오고 있다.

const moneyTypeList = [50000, 10000, 5000, 1000, 500, 100, 50, 10, 1];
  
  for (let coin in moneyTypeList) {
    coin = parseInt(coin)
    arr[coin] = parseInt(money / moneyTypeList[coin]);
  }

하지만 민재 님은 forEach를 사용하여 더 간결한 코드로 구현이 가능하게 했다. 이러한 자바스크립트의 유용한 내장 함수를 공부하여 더 간결한 코드를 작성해야겠다고 생각했다.

const MONEY_UNIT = [50000, 10000, 5000, 1000, 500, 100, 50, 10, 1];

function withDraw(money) {
  MONEY_UNIT.forEach((unit) => {
    wallet.push(parseInt(money/unit));
  });

6번

문제 설명

다른 사람들과 나의 닉네임에서 두 글자 이상이 연속적으로 포함되는 경우를 찾으려고 한다.


구현 기능 목록

  • 입력받기(이렇게 입력받겠다고 생각하고 구현하지 않는다) ⭕
    • 이메일과 닉네임을 각각 배열에 담고 이를 하나의 배열에 담아 입력값으로 준다. ⭕
    • 이메일의 전체 길이는 11자 이상 20자 미만이다. ⭕
    • 닉네임은 한글로 이루어져 있다. ⭕
    • 한글로 이루어진 이 닉네임은 1자 이상 20자 미만이다. ⭕
  • 중복된 닉네임 찾기 ⭕
    • 한글 두 글자(연속적으로 순서대로 이어진)이 다른 사람의 닉네임에 들어가 있으면 중복으로 간주한다. ⭕
    • 모든 닉네임에서 연속된 두 글자로 이루어질 수 있는 모든 단어를 찾아 배열에 넣는다. ⭕
    • 이들이 실제 글자에 몇 번 포함되어 있는지를 넣을 count 배열을 생성하고 각 원소를 0으로 초기화한다. ⭕
    • 이 count가 2 이상이면 이에 해당하는 두 글자가 들어간 닉네임을 찾는다 ⭕
    • 찾은 닉네임의 이메일을 새로운 배열 result 안에 넣는다. ⭕
    • result는 이메일에 해당하는 부분의 문자열을 오름차순으로 정렬한다. ⭕


나의 코드와 개선점(with 피어 리뷰)

for 대신 forEach를 사용하자!

이번에도 forEach를 몰라서 대신 for문을 썼었다. 앞으로는 forEach를 사용하여 코드를 작성하자!

forEach에 관한 설명


7번

문제 설명

7번 문제는 친구 추천 알고리즘을 구현하는 문제이다. 먼저 입력으로 들어오는 friends 배열을 통해 실제 친구를 구한다. 그리고, 그 실제 친구와 친구인 사람을 구하여 10점씩 부여한다. 그리고 함께 입력된 visitors에 있는 방문자에게는 방문 횟수 별로 1점을 부여한다. 점수를 가장 많이 받은 사람들을 출력하며 끝이 난다(5명 이하, 0점은 제외, 이미 친구인 사람은 제외)


구현 기능 목록

  • 입력 ⭕
    • 입력으로 user, friends, visitors, result가 하나의 배열에 담겨 주어진다. ⭕
  • 추천 점수 계산하기 ⭕
    • user와 이미 친구인 사람의 이름을 배열 alreadyFriendList에 담는다. ⭕
    • friends 목록과 visitors 목록을 합쳐 이름의 중복을 제외하고 user와 알 수도 있는 친구를 모두 배열 everyoneList에 담는다. ⭕
    • everyoneList와 길이가 같은 배열 'everyoneScoreList`을 만들고 각 원소를 0으로 초기화하며 이곳에 각각의 점수를 저장한다. ⭕
    • 예외) friends 리스트에서 alreadyFriendList에 있는 친구와 짝인 친구를 찾는다. ⭕
    • 예외) 이때 friends의 원소에서 user가 들어갔을 경우에는 무시한다. ⭕
    • 짝이면 eveyoneList에서 그 친구의 인덱스를 찾는다. ⭕
    • everyoneScoreList에서 그 인덱스의 score을 10 높여준다. ⭕
    • visitors 리스트에 있는 사람들은 한 번 등장할 때마다 everyoneScoreList의 score을 1 높여준다. ⭕
  • 출력하기 ⭕
    • 점수가 높은 대로 친구의 이름을 출력해 준다. ⭕
      • 딕셔너리를 만들고 이를 정렬한다(Object.entries() 사용) ⭕
  • 예외) 실제 친구는 제외한다 ⭕
  • 예외) 최대 5명을 출력한다. ⭕
  • 예외) 점수가 0점인 경우는 출력하지 않는다. ⭕
  • 예외) 추천 점수가 같은 경우에는 이름순으로 정렬한다. ⭕
  • 예외) user가 아무런 friends도 갖지 못했을 때 예외 처리하기 ⭕


나의 코드와 개선점(with 피어 리뷰)

1) 함수로 분리하기

7번은 문제가 복잡하여 구현하는데 긴 코드가 필요하다. 나의 경우 약 100줄이 쓰였다.
그런데, 나의 경우 이 모든 코드가 하나의 함수에 들어가 있었다. 하나의 기능을 하는 함수들로 이를 분리하여야 함을 머리로는 알고 있었지만, 코드 구현에 힘을 쓰느라 리팩토링을 하지 않았기 때문이다.

하지만 미션이 끝난 후 다른 지원자들은 여러 개의 함수로 기능을 분리한 것을 알 수 있었다. 나도 다음 미션부터는 함수를 꼭 분리해야겠다고 다짐했다.



2. 1주차 공통 피드백

1주 차 미션에 대해 지원자들이 제출한 코드에 대한 공통 피드백을 받았다.

그중에서 기억해야 할 중요한 피드백을 정리해 보려고 한다.

1) 이름을 통해 의도를 드러낸다

나 자신, 다른 개발자와의 소통을 위해 가장 중요한 활동 중의 하나가 좋은 이름 짓기이다. 변수 이름, 함수(메서드) 이름, 클래스 이름을 짓는데 시간을 투자하라. 이름을 통해 변수의 역할, 함수의 역할, 클래스의 역할에 대한 의도를 드러내기 위해 노력하라. 연속된 숫자를 덧붙이거나(a1, a2, ..., aN), 불용어(Info, Data, a, an, the)를 추가하는 방식은 적절하지 못하다.

2) 축약하지 않는다

의도를 드러낼 수 있다면 이름이 길어져도 괜찮다.

누구나 실은 클래스, 메서드, 또는 변수의 이름을 줄이려는 유혹에 곧잘 빠지곤 한다. 그런 유혹을 뿌리쳐라. 축약은 혼란을 야기하며, 더 큰 문제를 숨기는 경향이 있다. 클래스와 메서드 이름을 한 두 단어로 유지하려고 노력하고 문맥을 중복하는 이름을 자제하자. 클래스 이름이 Order라면 shipOrder라고 메서드 이름을 지을 필요가 없다. 짧게 ship()이라고 하면 클라이언트에서는 order.ship()라고 호출하며, 간결한 호출의 표현이 된다. 객체 지향 생활 체조 원칙 5: 줄여쓰지 않는다 (축약 금지)

3) 공백도 코딩 컨벤션이다

if, for, while문 사이의 공백도 코딩 컨벤션이다

4) 공백 라인을 의미 있게 사용한다

공백 라인을 의미 있게 사용하는 것이 좋아 보이며, 문맥을 분리하는 부분에 사용하는 것이 좋다. 과도한 공백은 다른 개발자에게 의문을 줄 수 있다.

5) 의미 없는 주석을 달지 않는다

변수 이름, 함수(메서드) 이름을 통해 어떤 의도인지가 드러난다면 굳이 주석을 달지 않는다. 모든 변수와 함수에 주석을 달기보다 가능하면 이름을 통해 의도를 드러내고, 의도를 드러내기 힘든 경우 주석을 다는 연습을 한다.

6) linter와 Code Formatter의 기능을 활용한다

가능하면 eslint와 prettier를 이용해 더욱 생산적으로 코드를 작성하자.

린트(lint)는 소스 코드에 문제가 있는지 탐색하는 작업을 의미하며, 린터(linter)는 이 작업을 도와주는 소프트웨어를 말한다. 자바스크립트와 같은 인터프리터 언어의 경우, 런타임 에러가 발생할 확률이 높기 때문에, 이 린트 작업을 통해 사전에 에러를 최대한 잡아준다면 훨씬 생산성 높은 개발을 할 수 있다. lint 중 eslint는 자바스크립트 진영의 오픈소스로 확장되고 있는 정적 분석 도구이다.

prettier는 일종의 Code Formatter이다. Code Formatter란 개발자가 작성한 코드가 정해진 코딩 스타일을 따르도록 변환해주는 도구이다. 이 두 가지 도구를 이용하면 코드를 짜는데 발생할 수 있는 오류를 미리 예방하고 쉽게 정돈할 수 있다.

7) 불필요한 console.log를 남기지 않는다

디버깅을 위해 사용한 console.log가 최종 제출하는 코드에 의미 없이 남아있지 않도록 주의한다.

8) JavaScript에서 제공하는 API를 적극 활용한다

함수(메서드)를 직접 구현하기 전에 JavaScript API에서 제공하는 기능인지 검색을 먼저 해본다.

JavaScript API에서 제공하지 않을 경우에 직접 구현한다.

예를 들어 우승자를 출력할 때 우승자가 2명 이상이면 쉼표(,) 기준으로 출력을 위한 문자열은 다음과 같이 구현할 수 있다.

const members = ['east', 'west', 'south'];members.map((member) => member).join(','); // "east,west,south"


3. 1주 차 회고

드디어 회고 시간이다. 사실 코드에 관한 내용 없이 회고만 쓰려고 했는데, 어쩌다 보니 다 쓰게 되어 엄청 길어졌다.

자바스크립트를 이렇게 하게 될 줄은 몰랐는데

사실 프론트엔드를 공부한다고 하면서도 자바스크립트를 거의 몰랐다. 왜냐면, 알고리즘은 파이썬으로 풀었고 자바스크립트를 거의 공부하지 않은 채로 리액트를 공부했기 때문이다. 그래서 자바스크립트가 언제나 너무 어렵고 생소했지만, 더 공부해서 알아갈 생각은 안 하고 회피하기만 했던 것 같다.

그런데 프리코스에 참여하며 정해진 언어인 자바스크립트로 코딩을 하게 되었다. 지난주에는 정말 일주일 내내 자바스크립트로 문제를 풀었다. 이렇게 자바스크립트를 사용하게 될 줄은 몰랐지만, 스파르타식으로 하니 오히려 자바스크립트에 대한 겁이 많이 없어진 것 같다. 지금은 자바스크립트에 대해 더 알고 싶은 마음뿐이다.

컨벤션이 대체 뭐야?!

이번 미션을 진행하며 자바스크립트 컨벤션과 커밋 메시지 컨벤션에 대해 공부하게 됐다. 이전에 혼자 공부할 때는 전혀 필요성을 느끼지 못했던 일이다. 하지만 이번에는 남이 나의 코드를 읽어야 하기 때문에 이를 알아야만 했다. 처음에 문서 등을 읽을 때는 이게 다 뭐야? 이걸 꼭 지켜야 해? 하는 생각이 들었지만, 코딩하며 지키라고 만들어진 컨벤션을 나 혼자 지키지 않으면 남들과의 의사소통 등에 문제가 있을 거라는 생각이 들었다. 그래서 몇 번이고 관련 자료를 읽고 코드를 작성했다. 지금도 물론 틀린 점이 많겠지만, 이전처럼 자유분방한 네이밍과 의미 없는 커밋 메시지는 대부분 사라진 것 같아 뿌듯하다.

비하인드 #코수타 (코치와 수다 타임)

1주 차 문제를 풀면서 모호한 점들이 많았다. 그래서 슬랙 '질의응답' 채널이 굉장히 활발히 운영되었다. 그런데, 그게 의도된 점이었다고 한다...!!! 오늘 있었던 '코치와 수다 타임(코수타)'에서 알게 되었다. 들으면서 코수타를 간단하게 정리한 정리본은 여기 있다.

현실 세계에는 정답이 없으며 우리가 하려는 것은 결국 현실 세계의 문제를 해결하는 것이다. 따라서 경우의 수를 작성하여 고민해보고 현실 세계를 반영한 코드를 작성해야 한다. 프리코스에서는 이 연습을 하는 것이다. 우리는 정답을 구하는 학생의 마인드에서 벗어나야 한다.

라고 하셨다. 이게 의도된 거였다니.. 나도 input과 output이 명확한 문제만 풀려고 하지 말고 많은 생각을 하면서 문제를 푸는 연습을 해야겠다고 생각했다.

함께하는 건 정말 좋은 거구나..

1주 차 미션을 진행할 때에는 모든 지원자들이 참여할 수 있는 슬랙 채널이 있었다.(물론 지금도 있다. 현재는 깃헙 커뮤니티가 추가되었을 뿐!) 이곳에서 응원을 주고받기도 하고, 질의응답을 하기도 하며 큰 힘을 얻었다. 특히 내가 쓴 글에 이모지가 달리면 소소하게 기뻤다. 그래서 그 후로 남들의 글에 이모지를 마구 달기 시작했다. 조금이라도 힘이 되길 바라면서!

가장 기대했던 피어 리뷰

독학할 때는 코드 리뷰를 받을 일이 거의 없었다. 그래서 프리코스 2주 차부터 지원자들 간 코드 리뷰를 할 수 있는 장을 열어준다고 하셔서 기대가 됐다. 사실 다른 사람들을 어떤 코드를 짜고 어떤 생각을 하는지 궁금해서 지원한 거라서 이 피어 리뷰가 정말 기대됐다. 그래서 프리코스 프론트 코드 리뷰 스터디에도 들어가게 됐다.

그 런 데... 다른 분들의 코드를 보고 많이 기가 죽었다. 내가 과연 남에게 코드 리뷰를 할 수 있는 실력이 될까? 싶어서 생각해 보면 아닌 것이다. 그래서 많이 쭈글쭈글해졌고... 스터디에서 나갈까, 그냥 리뷰해달라고 올리지 말까, 하다가 그 생각이 바뀌게 되는 계기가 발생했다.

쭈글거렸을 때 아무 생각 없이 그냥 '제가 많이 초보이니 코드 리뷰를 부디 부탁드립니다' 하고 올리게 되었는데, 리뷰 스터디 팀원 분이 너무 친절하고 상세하게 리뷰를 남겨주신 것이다. (바로 앞에서 많이 인용한 민재 님,,)

첫 피어 리뷰를 길이길이 간직하고자 캡쳐를 해뒀다.

나는 너무 감동을 받고 말았다.. 초라한 내 코드를 읽고 리뷰를 남겨주시다니..

리뷰를 해주신 분께 나도 리뷰를 남겨야 하므로 리뷰를 하긴 했는데, 대부분 좋은 코드에 대한 칭찬을 했고 가끔 보이는 자바스크립트 컨벤션에 반하는 부분에 대해 리뷰 드렸다. 앞으로 공부를 많이 해서 3~4주 차에는 코드 자체에 대한 부분도 꼭 리뷰할 것이다.

그래서 1주 차 미션을 해낸 소감은?

뿌듯하다! 일단 모두 돌아가게 만드는 것에 성공한 것이 뿌듯했다. Pull Request를 어떻게 보내는지도 몰랐던 내가 문제를 모두 풀어서 Pull Request로 제출하고, 오늘은 다른 분의 Pull Request에 리뷰를 남기기도 했다. 그리고 프리코스에 참여하며 겪은 모든 일이 추억이 될 것 같아 상세히 기록해두고 있다. 과제 제출 시에 작성하는 소감문은 2,500자를 적어서 내기도 했다. 느낀 점이 너무 많아서 문제다..!

2주 차 미션에서는 클린 코드를 적용해 보고 싶다

1주 차에는 기능 구현을 하느라 리팩토링을 하지 못했다. 그래서 다른 분들의 코드를 볼 때 나의 코드가 생각나서 아쉬움이 남았는데, 2주 차 미션은 꼭 리팩토링을 하려고 한다. 이를 위해 클린 코드에 대해서 공부할 것이다. 2주 차 미션도 화이팅이다!!

profile
🐹강화하고 싶은 기억을 기록하고 공유하자🐹

2개의 댓글

comment-user-thumbnail
2022년 11월 3일

잘보고갑니다!

1개의 답글