교육/우아한테크코스

[우테코] 프리코스 2주차 <자동차 경주> 미션 회고

알파카털파카 2024. 10. 22. 01:38
[우테코]
프리코스 2주차 <자동차 경주> 미션 회고

 

 

🚗 2주차 미션 : 자동차 경주
  - 학습 목표 분석하기
  - @woowacourse/mission-utils 라이브러리 뜯어보기
  - 구현 과정 : 객체지향을 지향하기 
✍️ 일간 회고
  - 아바타에서 사람으로
  - 의식적인 연습으로 성장하기
  - 나를 죽이지 못하는 고통은 나를 더욱 강하게 만든다
📑 주간 회고
  - 잘한 점
  - 아쉬운 점
  - 앞으로의 계획

 

 


 

 

2주차 미션 : 자동차 경주

학습 목표 분석하기

목표

 

2주차 미션은 간단한 자동차 경주 게임 구현이었다. 사용자가 각 자동차에 이름을 부여하고, 몇 번 이동을 할 것인지 시도 횟수를 입력한다. 무작위 값을 구해 4 이상일 경우에 이동시키고, 매 차수별 실행 결과와 우승자를 보여주는 미션이다. 1주차에 비해 미션 난이도는 낮아진 편이었지만 Jest를 이용한 테스트코드 작성과, 최대한 관심사를 분리해 작성하라는 조건이 있었다. 1주차 학습목표가 'Git, GitHub에 익숙해지기'였던 것에 비하면 초보자에게는 급격한 난이도 상승이라 볼 수 있다. 

 

실제로 구현하다보니 여러 함수가 만들어졌고, 코드 읽기가 불편해져서 리팩토링을 하면서 여러 클래스와 메소드로 분리하게 되었다. 단일책임원칙과 관심사 분리를 학습시키려는 의도같았다. 테스트 코드는 처음 접하는 사람들을 위해 여러 가지 자료가 첨부되어 있었다. 이 부분에서 난이도가 확 올라가지 않았을까 싶다. 

 

1주차 공통 피드백에는 여러가지가 있었는데, 학습 목표에도 있는걸 보면 공통 피드백의 모든 사항을 지키라는 의미일 것이다. 피드백 중 내가 반영하면 좋을 점은 다음과 같았다. 

변수,함수,클래스 이름을 통해 의도를 드러낸다
디버거를 사용한다
축약하지 않는다
의미없는 주석을 달지 않는다
커밋 메시지를 의미있게 작성한다
 

 

@woowacourse/mission-utils 라이브러리 뜯어보기

프로그래밍 요구사항 중, 라이브러리 조건이 있었다. 1주차 미션에도 있던 내용이다.

🔗@woowacourse/mission-utils에서 제공하는 Random Console API를 사용하여 구현해야 한다

 

1주차에는 제대로 확인하지 못했지만, 2주차에는 이 라이브러리의 코드를 뜯어보기로 했다.

 

javascript-mission-utils/src/random.js at main · woowacourse-projects/javascript-mission-utils

Utility library for mission. Contribute to woowacourse-projects/javascript-mission-utils development by creating an account on GitHub.

github.com

 

@woowacourse/mission-utils의 random.js에 대해 분석했다. 기능별 분리가 잘 되어있고 예외 처리도 가독성 좋게 분리되어 있어 깔끔하다는 인상을 받았다.

 

npm의 기능 설명을 미리 읽어서 대략 어떤 기능을 하고 있는지는 알고 있었지만, 변수명과 함수명을 통해 의도를 명확히 드러낸다는 것이 어떤 의미인지 알 것 같다. 설명 없이 코드를 처음 봤어도 어떤 맥락의 코드인지 이름을 통해 알 수 있도록 작성하는 연습을 해야겠다.

 

클래스에서 static과 private이 어떤 기능을 하는지 몰라서 이 부분의 학습이 필요했다. 해당 내용을 알면 설계 의도를 파악할 수 있을 것 같다.

 

정적 메소드(static methods)는 클래스의 인스턴스가 아닌 이름으로 호출할 수 있는 메소드다. 정적 메소드는 클래스 선언부 안에 위치하고 앞에 static이라는 키워드가 붙는다. 정적 메소드는 this에 접근할 수 없지만, 인스턴스를 생성하지 않아도 사용할 수 있다. 객체를 생성하지 않아도 재활용이 가능해서, 정적 메소드는 전역에서 사용하는 유틸 함수(클래스에 속한 함수를 구현할 때)로 많이 활용된다. 정적 메소드는 특정 클래스 인스턴스가 아닌 클래스 '전체’에 필요한 기능을 만들 때 사용할 수 있다. 클래스 본인에 의해서만 호출할 수 있다. 

 

Class의 private은 '#' 프리픽스를 사용해 생성한다. private 필드는 클래스 선언문 내부의 클래스 생성자(class constructor)에서 접근이 가능하다. Private static 필드는 해당 필드를 선언한 클래스에서만 접근할 수 있다. 스코프 밖에서 # 이름에 접근하는 것은 문법 오류이다.

 

클래스에서 static은 어떤 기능을 하며 왜 사용할까? private은 어떤 경우에 사용할까? 이번 미션에 사용되는 코드를 살펴보았다.

 

class Random {
  constructor() {}

  static pickNumberInRange(startInclusive, endInclusive) {
    Random.#validateRange(startInclusive, endInclusive);

    startInclusive = Math.ceil(startInclusive);

    return (
      Math.floor(Math.random() * (endInclusive + 1 - startInclusive)) +
      startInclusive
    );
  }

  static #isNumber(value) {
    return typeof value === "number";
  }

  static #validateRange(startInclusive, endInclusive) {
    if (!Random.#isNumber(startInclusive) || !Random.#isNumber(endInclusive)) {
      throw new Error("arguments must be numbers.");
    }

    if (startInclusive < Number.MIN_SAFE_INTEGER) {
      throw new Error(
        "startInclusive cannot be less than Number.MIN_SAFE_INTEGER"
      );
    }

    if (endInclusive > Number.MAX_SAFE_INTEGER) {
      throw new Error(
        "endInclusive cannot be greater than Number.MAX_SAFE_INTEGER."
      );
    }

    if (startInclusive > endInclusive) {
      throw new Error(
        `startInclusive ${startInclusive} cannot be greater than endInclusive ${endInclusive}.`
      );
    }

    if (endInclusive - startInclusive >= Number.MAX_VALUE) {
      throw new Error("the input range is too large.");
    }
  }
}

export default Random;

 

클래스의 인스턴스를 생성하지 않고도 Random.pickNumberInRange()으로 정적 메소드를 실행할 수 있다. 미션에서 바로 사용할 수 있는 유틸 함수의 역할을 하고 있다.

 

프라이빗 메소드인 #isNumber와 #validateRange는 클래스 내부에서만 사용 가능하다. 내부적으로 예외 처리를 담담하고 있다. 정적 메소드인 pickNumberInRange를 호출해서 사용하면 내부에서 먼저 프라이빗 메소드를 호출해 입력 값이 유효한지 확인하게 된다. 정적 메소드를 실행하면서 굳이 개발자가 일일이 실행할 필요가 없는 메소드를 프라이빗 메소드로 분리해두었다. 

 

 

구현 과정 : 객체지향을 지향하기

이번 미션에서는 객체지향과 관심사 분리에 초점을 맞춰 구현을 시도했다. 주어진 과제 코드가 클래스로 구현되어 있다는 점, 미션에 사용되는 라이브러리 역시 클래스로 구현되어 있다는 점에서, 이번 과제는 관심사별로 클래스와 메소드를 나눠서 구현하라는 의미라고 받아들였다.

 

앞서 적은 공통 피드백 내용을 확인하고, 1주차 과제에서 개선하면 좋을 점을 고려하며 개발했다. 다른 분들과 코드리뷰를 주고받을 때도 느꼈던 점이지만, 명확한 함수명, 변수명은 주석을 적을 필요가 없고 이해가 쉬워진다.

과제 조건 中
Indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.

 

이번 미션에서 나의 머릿속을 지배한 문장이다. 과제 조건 중 하나인데, 들여쓰기 뎁스 제한을 신경쓰다보니 자연스레 작은 기능 단위로 분리하기 위해 고민하게 됐다. 여기에 명확한 변수, 함수, 클래스 이름을 붙여 의도를 드러내고자 했다.

 

디렉토리 구조

 

처음에는 App.js 파일 내에서 모든 로직을 구현했다가, 여러 클래스를 생성하고 관심사에 맞게 코드를 분리하는 방식으로 구현했다. 리팩토링을 거듭하며 App 클래스에는 몇 줄만이 남았고, 나머지는 각자의 관심사에 맞는 클래스로 분리되어 깔끔해졌다. 객체지향에 대해 잘 알지 못했기도 하고, 처음 시도해보는 방식이기 때문에 완전한 객체지향이라고 하긴 어렵겠지만, 객체지향이 지향하는 바가 무엇인지 알게 된 것 같다. 아쉬운 점은 Jest를 이용한 테스트 코드를 많이 작성하지 못한 점이다. 갈수록 고려할 사항이 많아져서 다 챙기지 못했고, 아쉬움이 남는다.

 

 

[자동차 경주] 오신정 미션 제출합니다. by ShinjungOh · Pull Request #409 · woowacourse-precourse/javascript-raci

자동차 경주 🎯 초간단 자동차 경주 게임을 구현한다. 🔎 리뷰어가 중점적으로 봐주었으면 하는 부분 커밋 메시지를 의미있게 작성했나요? 변수,함수,클래스 이름을 통해 의도를 충분히 드러

github.com

 

2주 차 프리코스 통과!

 

 

 

 

일간 회고

2주차에는 데일리 회고를 매일 일기쓰듯 남기는 대신, 큼직한 사건 위주로 적어보려 한다. 다양한 회고의 방식을 시도 중이다.

 

 

아바타에서 사람으로

오프라인 스터디

 

오전 게더타운 모각코를 12시까지 진행하고 얼른 준비해서 2시에 진행되는 스터디 오프라인 모임에 나갔다. 첫 만남이어서 조금 떨렸다. 인사를 나누고, 각자의 코드를 설명한 후에 질문답변을 하는 식으로 코드 리뷰를 진행했다. 남의 코드를 보는 일, 나의 코드를 말로 설명하는 일 모두 새로운 경험이었고 많이 배웠다. 같은 문제여도 각자 접근하고 풀어낸 방식이 달라서 재미있었다.

 

특히 내가 생각지 못한 다양한 예외 케이스가 있다는걸 알게되었다. 내 코드를 설명하려면 내 코드에 대해 정확히 이해하고 있어야 했다. 이 부분을 다음번에는 더 보강해야겠다. 스터디와는 별개로 나에게 안좋은 습관이 있다는걸 인지했는데, 이 부분은 차차 개선해나가보려 한다.

 

원래 계획은 1시간 진행이었는데, 2시간 반이나 모임이 지속됐다. 그만큼 재미있고 알찬 시간이었다. 스터디 진행 요일 변경 계획과 진행 방식에 대한 의논도 나누고 점점 틀을 잡아가고 있다. 특히 FE 스터디 모집글이 없어서 직접 만드셨다는 스터디장님과, 많은 경쟁자를 제치고 이 스터디에 들어오게 되었다는 점에 감사했다. 매일 게더타운에서 아바타로 만나다가 실제 사람들과 만나니까 생동감있고 동기부여도 됐다. 더 친근해진 것 같다.

 

모니터 뒤에 사람 있어요!

 

 

의식적인 연습으로 성장하기

우아한 테크살롱

 

넥스트스텝에서 진행하는 <의식적인 연습> 워크숍을 들으러 선릉에 위치한 테크살롱에 다녀왔다. 우테코 교육이 진행되는 곳이다. 간 김에 조금 둘러보고 왔다. 창의력이 솟아날 것만 같은 공간 디자인과, 특히 페어프로그래밍 룸이 마음에 들었다. 나도 여기서 공부하고 싶다...(제발)

 

워크숍에서는 자신이 잘 하고 싶은, 성장하고 싶은 목표를 설정하고 구체적인 실천 방법과 10분 몰입 방법을 공유하는 챌린지를 진행한다. 매일 의식적인 연습으로 몰입하고 셀프 피드백과 회고를 슬랙에 2주간 남기는 방식이다. 나는 'ChatGPT, 코파일럿 등 AI를 사용하지 않고 개발하기'를 목표로 잡았다. 프리코스 기간과 맞춰서 챌린지가 진행되서 마침 잘 됐다.

 

14일 챌린지

 

 

나를 죽이지 못하는 고통은 나를 더욱 강하게 만든다

갑자기 추워져서인지, 어제 오전 9시부터 밤 12시까지 계속된 일정에 무리해서인지 몸살이 났다. 하루종일 거의 아무것도 못했다. 몸이 아프니 부정적인 생각이 몰려왔다. 최종 코딩테스트에 가지 못하게되면 프리코스 기간 동안 열심히 한 게 헛짓거리가 되는걸까? 나는 이제 앞으로 뭘 어떻게 해야하지? 새벽감성에 젖어 나의 인생에 대해 좌절하고 걱정했다.

 

그런데 새삼 내가 잘못 생각하고 있었다는 걸 깨달았다. ‘우테코에 합격해야 한다’가 각인되어 그 자체가 목표가 되어버렸다. 원래 목표가 생기면 그 목표를 왜 목표로 삼았는지 생각하기보다, 목표니까 이루어야만 한다는 터널 시야 현상이 일어난다. 내가 우테코를 목표로 한 것은 더 나은 환경에서 학습하고 개발 실력을 늘려서, 좋은 회사에 들어가기 위함이 아니었는가? 언제부터 우테코에 합격하기 위해 개발을 했지?

 

과제를 해결하면서 막히는 부분이 있으면 깊이 이해하고 해결하기보다 미션을 빨리 제출해야 하는 것을 걱정했다. 커밋 컨벤션을 틀리진 않았는지, 리드미의 구현 목록을 정확히 순서대로 지켰는지 등의 형식에 얽매여서 본질인 개발을 놓치고 있었던 것 같다. ‘너 이거 왜해? 과제 제출이 더 중요해?’라는 질문에 ‘응 어쨌든 과제를 제출해야 합격할 수 있잖아’라고 대답하면서 무언가 위화감을 느꼈다.

 

나는 좋아하고 재밌는 것을 할 때 잘 했다. 반면 실력이 없거나 재미가 없을 때 못했다. 내 스스로 개발을 재미없는 방식으로 진행하고 있었다. 그렇게 되면 번아웃이 찾아온다는걸 간과했다. 그래서 생각을 바꿨다. ‘합격해야만 해’ 대신에 ‘합격하지 못하더라도 몰입해서 즐기고 실력을 다지면 돼’로.

 

프리코스를 진행하면서 ‘AI 사용하지 않고 개발하기’라는 나만의 챌린지를 달성하면, 분명 프리코스 이전보다 실력이 늘었을 것이다. 그러면 우테코에 탈락하게 되더라도 남는게 있다. 몰입 경험과 그 과정에서 다져진 내실과 자신감이 남는다.

 

 

 

 

주간 회고

한 주간의 잘한 점, 아쉬운 점, 앞으로의 계획을 정리해본다. 이번주는 코딩을 많이 못해서 스스로 아쉬움이 많이 남는 주였다. 

 

 

잘한 점

1. 오프라인 스터디에서 서로 코드 리뷰를 주고받은 점

2. 매일 습관 챌린지에 참여하고 있는 점

3. 매일 기록을 남기며 내 사고의 흐름을 정리해둔 점

4. 감상문을 벼락치기로 쓰지 않고 일주일간 생각해보며 작성한 점

5. PR 내용을 지난주보다 신경써서 작성한 점

 

아쉬운 점

1. 코딩에 쓴 절대적인 시간이 부족한 점

2. 체력, 컨디션 관리에 실패한 점

3. 매일 정해둔 일정을 지키지 못한 점

4. 습관 챌린지가 작심삼일 된 점

5. 시간이 부족해 테스트 코드를 충분히 작성하지 못한 점(학습 목표에 있었음에도 불구하고)

6. 🚨 미친듯한 벼락치기로 과제를 제출한 점

 

앞으로의 계획

1. 매일 산책과 스트레칭 등, 운동을 해서 체력을 키울 것

2. 일정이 늦어지지 않게 신경쓸 것

3. 계속 AI를 사용하지 않을 것

4. 개발하는 시간을 이번 주보다 늘릴 것