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

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

개요

우와 벌써 '[우테코] 1주 차 미션 풀이(+코드 리뷰), 회고'를 쓴 지 일주일이 되었다.

2주 차 미션이 끝난 것이다! 이런 말 식상하지만, 정말 시간이 빠르게 지나갔다. 이번 주 회고에는 코드를 짠 과정, 피어 리뷰 스터디원에게 받은 코드 리뷰, 그리고 상당히 많은 느낀 점 & 사담이 있을 예정이다.

저번 주부터 사담을 최대한 줄이려고 했으나, 그냥 해야겠다ㅎㅎ

나는 사실 블로그 쓰는 게 너무 즐거워서.. 블로그 쓰려고 공부하는 것 같다.

블.꾸(블로그 꾸미기), 깃.꾸(깃허브 꾸미기), 노.꾸(노션 꾸미기) 하려고 공부하는 것 같음

하여튼 이번 포스팅 목차는 아래와 같다!

<목차>
1. 숫자 야구 게임 풀이 과정
2. 2주 차 공통 피드백 + 코치와 수다 타임
3. 피어 리뷰 스터디 시작! 코드 리뷰 내용
4. 3주 차에 공부해야 할 것
5. 2주 차 회고, 스터디 팀원들 회고 모음

❗ 이번 포스팅은 약 3만자로, 매우 길 예정입니다.


1. 숫자 야구 게임 풀이 과정

(1) 2주 차 미션 메일 정리

매주의 미션은 메일을 통해 전달받는다. 이 메일을 꼼꼼하게 읽는 것이 미션을 해결하는 첫 번째 단계라고 생각해서, 2주 차 미션으로 받은 메일을 정리해 보았다.

이번 주부터 우아한 테크코스의 미션 과정을 제대로 맛볼 수 있는 과제가 나간다

  • 1주 차 미션의 목표는 git, 과정별 언어, 그리고 미션 사이클에 익숙해지는 것이었다고 한다.
  • 2주 차부터는 우테코의 미션 과정을 제대로 맛볼 수 있는 과제가 나간다.

주어진 요구사항을 잘 파악하자

  • 요구사항을 이해하는 게 어려울 수 있지만 주어진 요구사항을 잘 파악하는 것도 좋은 개발자의 역량 중 하나!
  • 고민 없이 무작정 질문하거나 다른 사람의 도움을 받기 전에 스스로 고민하고 문제를 해결하자.

2주 차 미션의 목표는?

  • 2주 차 미션에서는 1주 차에서 학습한 것에 더해 함수를 분리하고, 함수별로 테스트를 작성하는 것에 익숙해지는 것이 목표이다.
  • 이번에 테스트를 처음 접하시는 분들(나ㅎㅎ)은 언어별 테스트 도구를 학습하고 작은 단위의 기능부터 테스트를 작성해보길 바랍니다. 👉 테스트가 뭔지 몰라서 이제부터 알아봐야 할 것 같다.
  • 정리해보면 2주 차의 목표는
    1. '함수 분리'와
    2. '테스트 작성'인 것이다!

과제 제출시에 소감문을 내야 한다

  • 과제를 제출 시에 이번 주차 목표를 중심으로 학습하면서 느낀 점을 소감문으로 작성해야 한다.
  • 이때 학습한 '과정’을 잘 드러내자.

진행 방식

  • 프리코스 2주 차 미션의 저장소
  • 매주 진행할 미션은 수요일에 메일로 발송되며, 그 다음 주 화요일까지 구현을 완료해 제출해야 한다.
  • 매주 미션은 기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항 세 가지로 구성되어 있다.
  • 세 개의 요구사항을 만족하기 위해 노력한다.
  • 기능을 구현하기 전에 기능 목록을 만든다.
  • 그리고 기능 단위로 commit한다.

미션 제출 방법

  • 1주 차와 같이 GitHub를 통해 제출한 후
  • 우테코 지원 플랫폼에 제출하고
  • 소감문을 작성하면 끝!

미션 마감 및 기준

  • 미션 제출 가능 기간: 2022년 11월 7일(월) 14시 00분 ~ 2022년 11월 8일(화) 23시 59분
  • 2022년 11월 9일(수) 00시 이후 추가 push도 허용하지 않는다.
  • 이 정해진 시간을 지키지 않은 경우, 미션을 제출하지 않은 것으로 한다.(미리도, 지나서도 안 됨)


(2) 2주 차 미션 저장소 정리(깃허브)

2주 차 미션이 상세하게 설명된 숫자 야구 게임 미션을 진행하는 저장소를 읽고 정리해보기로 했다.

기능 요구 사항

이번 숫자 야구 게임 미션은 우테코 프리코스에서 1번으로 나오곤 했던 기존의 숫자 야구 게임과 조금 다르다. 이전에는 화면까지 구현해야 했다면, 이번에는 CLI로 만들면 된다.

숫자 야구 게임은 1~9까지의 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이라고 한다.

  • 같은 수가 같은 자리에 있으면 스트라이크라는 힌트를 준다.
  • 같은 수가 다른 자리에 있으면 볼이라는 힌트를 준다.
  • 같은 수가 전혀 없으면 낫싱이란 힌트를 준다.
  • 이 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
    - (예) 상대방(컴퓨터)의 수가 425일 때
    - 123 제시 👉 1스트라이크
    - 456 제시 👉 1볼 1스트라이크
    - 789 제시 👉 낫싱
  • 상대방의 역할을 컴퓨터가 한다.
  • 컴퓨터는 1~9의 서로 다른 임의의 수 3개를 선택한다.
  • 플레이어는 컴퓨터가 생각하고 있는 서로 다른 3개의 숫자를 입력한다.
  • 컴퓨터는 입력된 숫자에 대한 결과를 출력한다.(낫싱과 같은)
  • 이 과정을 반복하여 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
  • 게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.
  • (예외) 사용자가 잘못된 값을 입력한 경우 throw 문을 사용해 예외를 발생시킨 후 애플리케이션을 종료시켜야 한다.

입출력 요구 사항

입력

  • 서로 다른 3자리의 수
  • 게임이 끝난 경우 재시작/종료를 구분하는 1과 2 중 하나의 수(재시작이 1, 종료가 2를 의미한다는 것 같다.)

출력

  • 입력한 수에 대한 결과를 볼, 스트라이크 개수로 표시한다
    - 예1: 1볼 1스트라이크
    • 예2: 낫싱
    • 예3: 3스트라이크 3개의 숫자를 모두 맞히셨습니다! 게임 종료(3개의 숫자를 모두 맞힌 경우)
    • 예4: 숫자 야구 게임을 시작합니다(게임 시작 문구 출력)

실행 결과 예시

숫자 야구 게임을 시작합니다.
숫자를 입력해주세요 : 123
11스트라이크
숫자를 입력해주세요 : 145
1볼
숫자를 입력해주세요 : 671
2볼
숫자를 입력해주세요 : 216
1스트라이크
숫자를 입력해주세요 : 713
3스트라이크
3개의 숫자를 모두 맞히셨습니다! 게임 종료
게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.
1
숫자를 입력해주세요 : 123
1

프로그래밍 요구 사항

  • Node.js 14 버전에서 실행 가능해야 한다. Node.js 14에서 정상적으로 동작하지 않을 경우 0점 처리
  • 프로그램 실행의 시작점은 App.js의 play 메서드이다.(play라는 함수를 만들어야 하나보다.)
    	```
    	const app = new App();
    	app.play();
    	```
  • package.json은 변경 불가능하다
  • 외부 라이브러리 jQuery, Lodash 등을 하용하지 않고 순수 Vanilla JS로만 구현한다.
  • JavaScript 코드 컨벤션을 지키면서 프로그래밍한다.
  • 프로그램 종료 시 process.exit()를 호출하지 않는다.
  • 프로그램 구현이 완료되면 ApplicationTest의 모든 테스트가 성공해야 한다. 테스트가 실패할 경우 0점 처리된다.
  • 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 이름을 수정하거나 이동하지 않는다.

추가된 요구 사항

  • indent(들여쓰기) depth는 2까지만 허용된다.
    - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
    • 이를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하는 것이다.
  • 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
  • Jest를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.
    - 테스트 도구 사용법이 익숙하지 않다면 tests/StringTest.js를 참고하여 학습한 후 테스트를 구현한다.

라이브러리

  • 우테코에서 제공하는 MissionUtils 라이브러리의 Random 및 Console API를 사용하여 구현해야 한다.
    - Random 값 추출은 MissionUtils 라이브러리의 Random.pickNumberInRange()를 활용한다.
    - 사용자의 값을 입력 받고 출력하기 위해서는 MissionUtils 라이브러리에서 제공하는 Console.readLine, Console.print를 활용한다.

  • 예)

    const computer = [];
    while (computer.length < 3) {
      const number = MissionUtils.Random.pickNumberInRange(1, 9);
      if (!computer.includes(number)) {
        computer.push(number);
      }
    }

과제 진행 요구 사항



(3) 요구사항 등 총정리

지금까지 적은 것들을 정리해보자. 너무 복잡하다!!!

<이번 미션의 목표: 함수를 분리하고, 각 함수별로 테스트를 작성하는 것에 익숙해지는 것>

  1. 일단 구현 기능 목록을 상세히 작성해야 한다.
  2. 하나씩 구현하는데, 각 함수 당 하나의 기능을 하는 함수들을 만들어 기능을 개발한다.
  3. 각 함수별로 테스트를 작성하여 확인한다. (테스트 도구 사용법이 익숙하지 않다면 tests/StringTest.js를 참고하여 학습한 후 테스트를 구현한다. 따로 파일을 만들거나 기존 파일에 작성해도 상관없다.)
  4. 각 기능을 구현할 때마다 기능별로 커밋 메시지 컨벤션을 지켜 커밋한다.
  5. 학습한 과정을 실시간으로 정리해서 갖고 있다가 나중에 코드와 함께 제출해야 한다.
  6. 프로그램 실행의 시작점은 App.js의 play 메서드가 되도록 코드를 짜야 한다.
  7. 프로그램 실행의 시작점은 App.js의 play 메서드이다.
  8. MissionUtils 라이브러리에서 제공하는 Random 및 Console API를 사용하여 구현해야 한다.

일단 이정도인 것 같다. 그럼 이제 구현 기능 목록을 작성해보자.



(4) 구현 기능 목록

## 숫자 야구 기능 목록
### 게임 시작
- App.js의 play 메서드로 프로그램 시작 
- 게임 시작 문구 출력
	- `숫자 야구 게임을 시작합니다.`
- 컴퓨터가 수 선택
	- 컴퓨터가 1~9까지의 서로 다른 3자리의 수를 선택함
		- MissionUtils 라이브러리의 Random.pickNumberInRange() 사용
### 사용자 입력이 들어올 때
- MissionUtils 라이브러리에서 제공하는 Console.readLine 사용
- (예외) 3자리가 아닐 경우 throw 문으로 종료시킴
- (예외) 모두 다른 숫자가 아닐 경우 throw 문으로 종료시킴

### 힌트 출력
- MissionUtils 라이브러리에서 제공하는 Console.print 사용
- 스트라이크: 같은 수가 같은 자리에 있음
-: 같은 수가 있지만 다른 자리에 있음
- 낫싱: 같은 수가 전혀 없음

### 숫자를 모두 맞혔을 때
- `3스트라이크` 출력
- `3개의 숫자를 모두 맞히셨습니다! 게임 종료` 출력
- 게임 종료
	- `게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.` 출력
	- 종료 후 게임을 재시작할 수 있음(1)
		- 재시작하면 다시 컴퓨터의 수 선택, 사용자의 입력이 반복됨
    - 종료 후 게임을 완전히 종료할 수 있음(2)


(5) 구현 시작!

new App(), app.play()로 App.js의 play 메서드로 프로그램 시작 을 구현해보자.

💥 문제 발생... 나는 class가 뭔지 모른다

문제 파일을 열었는데 이렇게 class가 딱 하고 나와 있다.

class App {
  play() {}
}

module.exports = App;

그리고 문제에서

  • 프로그램 실행의 시작점은 App.js의 play 메서드가 되도록 코드를 짜야 한다.
  • 프로그램 실행의 시작점은 App.js의 play 메서드이다.

라고 말하고 있는데... 그러면 class App 안에 한 개에 하나의 기능을 하는 함수 여러 개를 만들어야 하는 건가??? play()는 class App 안에 만들어져야 하는 거고?

일단 잘 모르겠으니 모던 자바스크립트 튜토리얼을 보기로 했다.

아니 봐도 모르겠음......^_^

그니까 play()를 실행시키는 방법 자체를 모르겠다.

👉 일단 실행은 시켰는데...이게 맞나..? 왜 여기서 class를 쓴 건지 진짜 모르겠다. 그니까 이렇게 일단 실행시키기만 하면 되는 건가? 그러면 그냥 function이랑 뭐가 다른 거지? 뭘 의도한 건지 모르겠다..

class App {
  constructor(name) {
    this.name = name;
  }
  play() {
    return this.name;
  }
}
let a = new App('kim')
console.log(a.play()); // kim

module.exports = App;

일단 실행시키고 보자. 실행시켰으니 넘어가겠음 일단..


함수를 private 프로퍼티를 사용해보자

함수를 private 프로퍼티(#)을 사용해 분리할 수도 있다는 것을 알게 되었다. (class App 밖에서 App 안의 함수에 접근할 수 없음) 이런 방법도 있다는 것을 알아두자!


play() 함수를 만들어보자

play 함수 실행은 문제에서 주어진 요구사항이다. play 함수에서는 시작 문구를 출력하고, 게임을 시작하는 함수를 만들려고 한다.

play() {
  this.#sayStart();
  this.#startGame();
}

sayStart() 함수를 만들어보자

게임이 시작됐을 때, 숫자 야구 게임을 시작합니다.를 출력해야 한다.

sayStart라는 함수를 만들어서 이 문구를 출력하도록 해보자.

아니 위 단계에서 넘어가면 안 됐나 보다. play()라는 함수 안에서 sayStart()를 넣어야 하나..? 그럼 play()가 무슨 의미를 갖는 거지..? 인자를 꼭 넘겨줘야 하나?

앗 일단 아무런 인자 없이 play()에서 콘솔로 값을 찍는 데 성공했다! (함수 분리부터 너무 어렵다..)

class App {
  play() {
    console.log(1);
  }
}
let app = new App()
app.play(); // 1

module.exports = App;

그럼 이제 sayStart()를 만들어서 숫자 야구 게임을 시작합니다.를 출력해보자.

아래와 같이 함수를 분리해서 시작 멘트를 출력하는 데 성공했다!(근데 이렇게 나누는게 의미가 있나 싶기도 하다. 지금 느끼기에는.. 👉 나중에 알아보니 이런 함수를 다른 파일로 분리할 수 있었음! 일단 함수로 기능을 나눈다는 데서 의미가 있고, 파일로 분리할 수 있다는 데서도 의미가 있는 것 같다)

class App {
  
  play() {
    function sayStart() {
      console.log('숫자 야구 게임을 시작합니다.');
    }
    sayStart();
  }
}
let app = new App()
app.play(); // 숫자 야구 게임을 시작합니다.

module.exports = App;

위의 코드는 private 프로퍼티가 있다는 것을 알기 전에 쓴 코드이다. 바꿔보면, 아래와 같이 간단하게 나타낼 수 있다. 👉 함수를 따로 만들 때 function 함수명() 이렇게 쓰지 않고 함수명만 앞에 써준다는 걸 처음 알았다. 파이썬에서 def를 사용해왔어서 당연히 자바스크립트도 그럴 거라고 생각했다.

#sayStart() {
    Console.print('숫자 야구 시작합니다.');
  };

또한 console.log 대신 MissionUtils.Console.print를 사용하라고 하였으므로 맨 위에 아래와 같이 임포트를 한 후, Console.print를 상용할 수 있게 했다.

아래처럼 하는 것을 구조분해할당이라고 한다고 한다.

const { Console, Random } = require('@woowacourse/mission-utils');

ComputerPicksNumber() 함수를 만들어보자.

ComputerPicksNumber함수를 만들어 컴퓨터가 세자리의 모두 다른 수를 뽑게 해보자. 아래의 조건을 지켜서 구현해야 한다.

<조건>

Random.pickNumberInrange()란?

  • pickNumberInRange(int startInclusive, int endInclusive)
  • validateRange()를 통해 startInclusive, endInclusive가 사용 가능한 범위인지 검증
  • return startInclusive 부터 endInclusive 사이의 랜덤한 숫자

그런데 궁금한 점이 있다. 이게 서로 다른 3자리의 수를 만들어야 하는데.. 만약에 pickNumberInRange(100, 999)라고 하면 랜덤한 3자리의 수를 뽑을 수는 있겠지만 각 자리가 서로 다른지는 검증할 수 없을 것이다. 그렇다고 3자리가 모두 다른 수일 때까지 계속 뽑는 건 또 이상하고...

일단 지금 생각나는 방법을 적어보자면,
1. pickNumberInRange(100, 999)로 서로 다른 3자리 수가 나올 때까지 계속 뽑기
2. pickNumberInRange(1, 9)(첫 번째 자리)를 일단 뽑고 나머지는 그 숫자를 제외한pickNumberInRange(0, 9)에서 뽑기 👉 이게 맞았음.. 남들 다 이렇게 했다

아무래도 2번 방법으로 하는게 좋을 것 같다. 근데 이미 뽑은 숫자를 제외하고 pickNumberInRange를 돌릴 수 있나..?

그럼 일단 좋은 방법이 생각 안 나니까 1번 방법으로 구현해보자. while문을 사용하면 쉽게 될 것 같다!

💥 문제가 생김. 왜 중복된 숫자가 나오는지 모르겠다

세 자리가 모두 다른 숫자인 숫자를 출력하는 기능을 구현해봤다. 그런데..! 중복이 있는 숫자를 출력하기도 하는 것이다. 뭐가 문제일까?
(jsbin에서 쉽게 테스트 하기위해 MissionUtils 대신 Math 라이브러리를 사용했다.)

let targetNumber = Math.floor(Math.random() * 900) + 100;
let [a, b, c] = targetNumber.toString().split("");
// console.log('기본: '+ a+b+c);
while (true) {
  if (a !== b && b !== c) {
    break;
  } else {
  targetNumber = Math.floor(Math.random() * 900) + 100;
  [a, b, c] = targetNumber.toString().split("");
//     console.log('while문: '+ (a+b+c));
  }
}  
targetNumber = a + b + c;
console.log('결론: '+ (a+b+c));

첫째 자리와 셋째 자리가 같은 숫자인 464가 출력된 것을 알 수 있다. 어디서 잘못 된 걸까?

일단.. console.log로 확인해보니까 숫자 727의 숫자가 모두 다른 숫자라고 판단한다는 것을 알았다. 뭐지??


앗 뭔가 단서를 발견한 것 같다. 414로 맨 처음 뽑았을 때 중복이 있어서 while문에서 else로 넘어갔을 것이다. 그런데 그때도 똑같이 414가 나왔고, 근데 loop를 돌지 않고 종료된 거 아닐까..? 그렇다면 왜 loop를 돌지 않는 걸까 a !== b & b !== c일 때만 break를 걸어줬는데? 👉 loop를 돌지 않는 게 아니라... if문 조건이 잘못된 거여였음

✅ 뭐가 문제인지 알아냈다!!!!

좀 더 테스트하기 쉬운 코드로 바꿔봤다.
(jsbin에서 쉽게 테스트 하기위해 MissionUtils 대신 Math 라이브러리를 사용했다.)

let num = Math.floor(Math.random() * 900) + 100;
let [a, b, c] = num.toString().split("");
if (a !== b && b !== c) {
  console.log((a + b + c) + '는 모두 다른 숫자입니다.');
} else {
  console.log((a + b + c) + '는 모두 다르지 않은 숫자입니다.');
}

// "뽑힌 숫자는?: 426"
// "모두 다른 숫자입니다."
// "뽑힌 숫자는?: 179"
// "모두 다른 숫자입니다."
// "뽑힌 숫자는?: 632"
// "모두 다른 숫자입니다."
// "뽑힌 숫자는?: 135"
// "모두 다른 숫자입니다."
// "뽑힌 숫자는?: 525"
// "모두 다른 숫자입니다."

여기서 문제는 a !== b && b !== c 이 부분이다. 예를 들면 121이라는 숫자가 있을 때, 이 조건문은 121을 걸러내지 못한다. 왜냐하면, a와 c를 비교하는 부분이 없기 때문이다.


예전에 이와 반대로 같음을 탐지할 때, a와 b가 같고 b와 c가 같으면 a도 c와 같으므로 a === c는 쓸 필요가 없다는 걸 들은 적이 있다. 그래서 모두 같을 때 a와 c를 비교하지 않았으니 모두 다를 때도 a와 c를 비교하지 않아도 되겠다고 착각한 것 같다😂

<참고>
a와 b가 같고 b와 c가 같으면 a도 c와 같다는 걸 추이성(Transitivity)라고 한다.
👉 집합 A에서 임의의 세 원소 a, b, c에 대하여 a와 b가 관계가 있고 b와 c가 관계가 있으면, a와 c가 관계가 있음


더 간단하게 이렇게 해결했다!!!

(jsbin에서 쉽게 테스트 하기위해 MissionUtils 대신 Math 라이브러리를 사용했다.)

let targetNumber = Math.floor(Math.random() * 900) + 100;
let [a, b, c] = targetNumber.toString().split("");
do {
  let targetNumber = Math.floor(Math.random() * 900) + 100;
  [a, b, c] = targetNumber.toString().split("");
} while (a === b || b === c || a === c)
targetNumber = a + b + c; // 얘가 없으면 정상적으로 실행되지 않는다 scope에 의해
console.log(targetNumber);

이제 Math가 아니라 MissionUtils를 사용하여 코드를 수정해보면 아래와 같이 바꿀 수 있다.

let targetNumber = MissionUtils.Random.pickNumberInRange(100, 999);
let [a, b, c] = targetNumber.toString().split("");
do {
  let targetNumber = MissionUtils.Random.pickNumberInRange(100, 999);
  [a, b, c] = targetNumber.toString().split("");
} while (a === b || b === c || a === c)
targetNumber = a + b + c;

✨ 다른 방법으로 구현해보았다!

pickNumberInRange(1, 9)(첫 번째 자리)를 일단 뽑고 나머지는 그 숫자를 제외한pickNumberInRange(0, 9)에서 뽑기가 어려워보여서 앞선 방법으로 하다가, 이렇게 하는 법을 알게 되었다.

아래와 같이 1부터 9에서 뽑아서 겹치지 않으면 computePick이라는 변수에 더해주어서 결론적으로 모두 다른 세 자리의 숫자를 뽑는 함수를 만들 수 있다.

#computerPicksNumber() {
    const computerPickArr = [];
    while (computerPickArr.length < 3) {
      const number = Random.pickNumberInRange(1, 9);
      if (!computerPickArr.includes(number)) {
        computerPickArr.push(number);
      }
    }
    const computerPick = computerPickArr.join('');
    console.log(computerPick);
    return computerPick;
  }

MissionUtils.Console.readLine으로 '사용자가 입력'하는 것을 받아보자.

MissionUtils 라이브러리에서 제공하는 Console.readLine을 사용해야 한다.

명령줄에 입력하는 숫자를 입력값으로 받아보자. MissionUtils 사용법은 이곳에 잘 나와있다.

아래처럼 해서 입력받는데 성공했다!

const MissionUtils = require("@woowacourse/mission-utils");

MissionUtils.Console.readLine('숫자를 입력해주세요 : ', input => {
	const userInput = input;
});

MissionUtils를 매 함수 앞에 쓰지 않고 푸는 방법을 알아냈다. 바로 아래와 같이 써주면 된다!(구조분해할당)

const { Console, Random } = require('@woowacourse/mission-utils');

evaluateInput() 함수를 만들어보자.

evaluateInput()로 '(예외) 3자리가 아닐 경우 throw 문으로 종료', '(예외) 모두 다른 숫자가 아닐 경우 throw 문으로 종료시킴'을 구현해보자.

일단 input의 예외를 검사하는 함수 evaluateInput를 만들었다. 그리고 세 자리의 숫자인지 .length로 검사한 후, 세 자리의 숫자이면 모두 다른 세 자리의 숫자인지 검사했다.

👉 여기서 두가지 개선할 점이 있다.
1. evaluateInput에서 evaluate는 '평가하다'라는 의미로 썼는데, eval()이라는 함수가 있어서 다른 의미로 해석될 수 있다고 한다. 그래서 이후에 validate로 변경했다.
2. 아래의 코드는 정규표현식으로 간단하게 구현할 수 있다.


조건에 부합하지 않으면 throw 문으로 프로그램이 종료되게 만들었다.

👉 throw를 처음 봐서... 낯설었다. 그냥 if의 조건에서 어긋나면 어떤 문자열을 출력하는 기능만 있는 줄 알았다.throw new Error가 있는 걸 시간이 지나고 나서 알았다. 여기서 Error가 고정된 것이 아니라 따로 만드는 객체이고, 내장 에러 객체를 쓸 수 있다는 것도 몰랐다.

function evaluateInput(input) {
  let inputString = input.toString();
  let inputLength = inputString.length;
  let [a, b, c] = inputString.split("");
  if (inputLength !== 3) {
    throw "세 자리의 숫자가 아닙니다.";
  } else {
    let [a, b, c] = inputString.split("");
    if (a === b || b === c || a === c) {
      throw "모두 다른 세 자리의 숫자가 아닙니다."
    }
  }
}

💥 코드에 문제가 있다!!

만약에 두 자리 숫자가 들어온다면 c는 undefined가 될 것이다.

아래의 코드에서 확인할 수 있다.

inputString = '23';
let [inputA, inputB, inputC] = inputString.split("");
console.log(inputA, inputB, inputC); // 2 3 undefined

따라서 조건을 각각 따로 줘서 이런 일이 발생하지 않게 코드를 수정해봤다. 더 길어지긴 했지만, 이게 맞는 것 같다..! (그리고 a, b, c를 좀 더 의미있는 변수명으로 바꿨다.)

function evaluateInput(input) {
  let isNotNumber = isNaN(input);
  if (isNotNumber === true) {
    return false;
  }
  let inputString = input.toString();
  let inputLength = inputString.length;
  if (inputLength !== 3) {
    return false;
  }
  inputString = input.toString();
  let [inputA, inputB, inputC] = inputString.split("");
  if (inputA === inputB || inputB === inputC || inputA === inputC) {
    return false;
  } else {
    return true;
  }
};

✨ 최종적으로 이렇게 했다(대폭 수정)

  1. 복잡한 코드를 정규표현식으로 바꿨다.
  2. 함수명도 사용자가 넣는 값(input)에서 사용자가 질문하는 값(guess)로 바꾸고, evaluate(평가하다)에서 validate(평가하다. 근데 의미가 조금 다른)으로 바꿨다.
validateGuess(guess) {
  if (!/^[1-9]{3}$/.test(guess)) {
    throw new Error("1-9 범위의 세 자리 수가 아닙니다: " + guess);
  }
  if (
    guess[0] === guess[1] ||
    guess[1] === guess[2] ||
    guess[2] === guess[0]
  ) {
    throw new Error("세 자리 수가 다르지 않습니다: " + guess);
  }
}

getHint() 함수를 만들어보자.

getHint()로 '힌트 출력'을 구현해봤다.

힌트를 출력하는 조건은 아래와 같다. console.log 대신 MissionUtils.Console.print를 사용해야 하고, 스트라이크/볼/낫싱을 구현해야 한다.

  • MissionUtils 라이브러리에서 제공하는 Console.print 사용
  • 스트라이크: 같은 수가 같은 자리에 있음
  • 볼: 같은 수가 있지만 다른 자리에 있음
  • 낫싱: 같은 수가 전혀 없음

여기서 스트라이크와 볼을 각각 탐지하여 결과를 출력할 때 붙여서 출력해주면 될 것 같다.

getHint(computerPick, guess) {
  let strikes = 0;
  let balls = 0;

  for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) {
    if (computerPick[i] !== guess[j]) {
      continue;
    }

    if (i === j) {
      strikes++;
    } else {
      balls++;
    }
  }

  if (balls && strikes) {
    return `${balls}${strikes}스트라이크`;
  } else if (balls) {
    return `${balls}`;
  } else if (strikes) {
    return `${strikes}스트라이크`;
  } else {
    return '낫싱';
  }
}

👉 개선할 점이 두 가지 있다.
1. 자바스크립트 컨벤션에서 ++, --를 지양하고 += 1, -= 1을 지향한다고 한다.
2. if 문에서 얼리 리턴이 됐다면, 굳이 else if를 쓸 필요 없이 if를 쓰면 된다고 한다. else if가 너무 많아서 if로 바꾸는 것이 가독성 측면에서 좋을 것 같다. (다만 오히려 가독성이 떨어진다는 의견도 있었다)


gameLoop() 함수를 만들어보자

gameLoop()로 '게임 종료 혹은 재시작'을 구현해보자.

gameLoop(computerPick, guess) {
  this.validateGuess(guess);
  Console.print(this.getHint(computerPick, guess));
  if (computerPick === guess) {
    Console.print("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
    Console.readLine(
      "게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.",
      (response) => {
        if (response.trim() === "1") {
          this.startGame();
        } else if (response.trim() === "2") {
          return;
        } else {
          throw new Error("1 혹은 2가 아닌 값을 입력하였습니다");
        }
      }
    );
    Console.close();
    return;
  }
  Console.readLine("숫자를 입력해주세요 : ", (guess) => {
    this.gameLoop(computerPick, guess.trim());
  });
}

위에서 언급한 것 외의 삽질

1) 터미널에서 실행이 안됨

코드를 제출하고 나니 터미널에서 갑자기 실행이 안됐다. 알고보니 제출할 때 이 부분을 지워놓고 다시 작성하지 않아서 안되는 거였다.

let app = new App();
app.play()

2) 홈페이지에서 테스트를 통과 못함

홈페이지에서 예기치 못한 오류로~ 라는 걸 띄우며 테스트를 통과하지 못했었다.

이유는 바로...Console을 쓰고 Console.close()를 안했음.. 우테코에서 제공하는모듈이라 공식 문서를 더 꼼꼼히 읽었어야 했는데, 그러지 못했던 것 같아 반성했다.

성공!



2. 2주 차 공통 피드백 + 코치와 수다 타임

2주 차 공통 피드백과 두 번째 코수타(코치와 수다타임) 내용을 정리해보았다.

(1) 2주 차 공통 피드백 정리

1주 차 피드백은 어느정도 필요한 것만 정리해서 올렸는데, 이번에는... 모든 피드백이 나에게 적용됐기 때문에 거의 대부분을 가져왔다. 정말 모든 피드백이 큰 도움이 되었다.

README.md를 상세히 작성한다

미션 저장소의 README.md는 소스코드에 앞서 해당 프로젝트가 어떠한 프로젝트인지 마크다운으로 작성하여 소개하는 문서이다. 해당 프로젝트가 어떠한 프로젝트이며, 어떤 기능을 담고 있는지 기술하기 위해서 마크다운문법을 검색해서 학습해보고 적용해 본다.

기능 목록을 재검토한다

기능 목록을 클래스 설계와 구현, 함수(메서드) 설계와 구현과 같이 너무 상세하게 작성하지 않는다. 클래스 이름, 함수(메서드) 시그니처와 반환값은 언제든지 변경될 수 있기 때문이다. 너무 세세한 부분까지 정리하기보다 구현해야 할 기능 목록을 정리하는 데 집중한다. 정상적인 경우도 중요하지만, 예외적인 상황도 기능 목록에 정리한다. 특히 예외 상황은 시작 단계에서 모두 찾기 힘들기 때문에 기능을 구현하면서 계속해서 추가해 나간다.

기능 목록을 업데이트한다

README.md 파일에 작성하는 기능 목록은 기능 구현을 하면서 변경될 수 있다. 시작할 때 모든 기능 목록을 완벽하게 정리해야 한다는 부담을 가지기보다 기능을 구현하면서 문서를 계속 업데이트한다. 죽은 문서가 아니라 살아있는 문서를 만들기 위해 노력한다.

값을 하드 코딩하지 않는다

문자열, 숫자 등의 값을 하드 코딩하지 마라. 상수를 만들고 이름을 부여해 이 변수의 역할이 무엇인지 의도를 드러낸다.

구현 순서도 코딩 컨벤션이다

클래스는 필드, 생성자, 메서드 순으로 작성한다.

class A {    필드

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

함수 길이가 길어진다면 한 함수에서 여러 일을 하려고 하는 경우일 가능성이 높다. 아래와 같이 한 함수에서 안내 문구 출력, 사용자 입력, 유효값 검증 등 여러 일을 하고 있다면 이를 적절하게 분리한다.

const userInput = () => {

  MissionUtils.Console.readLine("숫자를 입력해 주세요: ", (input) => {

  if (userNumbers.length !== 3) {

}

};

함수가 한 가지 기능을 하는지 확인하는 기준을 세운다

만약 여러 함수에서 중복되어 사용되는 코드가 있다면 함수 분리를 고민해 본다. 또한, 함수의 길이를 15라인을 넘어가지 않도록 구현하며 함수를 분리하는 의식적인 연습을 할 수 있다.

JavaScript에서 객체를 만드는 다양한 방법을 이해하고 사용한다.

JavaScript에서는 클래스 말고도 객체를 만드는 방법은 여러 가지가 있다. 객체를 생성하는 방법에 대해서는 MDN 문서의 JavaScript 객체 기본Classes을 참고한다.

테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다

단지 기능을 점검하기 위한 목적으로 테스트를 작성하는 것은 아니다. 테스트를 작성하는 과정을 통해서 나의 코드에 대해 빠르게 피드백을 받을 수 있을 뿐만 아니라 학습 도구 학습테스트를 통해 JUnit 학습하기.pdf로도 활용할 수 있다. 이런 경험을 통해 테스트에 대해 어떤 유용함을 느꼈는지 알아본다.

처음부터 큰 단위의 테스트를 만들지 않는다

테스트의 중요한 목적 중 하나는 내가 작성하는 코드에 대해 빠르게 피드백을 받는 것이다. 시작부터 큰 단위의 테스트를 만들게 된다면 작성한 코드에 대한 피드백을 받기까지 많은 시간이 걸린다. 그래서 문제를 작게 나누고, 그 중 핵심 기능에 가까운 부분부터 작게 테스트를 만들어 나간다.

큰 단위의 테스트

  • 숫자 야구 게임을 시작해서 사용자가 숫자를 입력하면, 컴퓨터 숫자와 비교하여 그 결과를 알려준다.

작은 단위의 테스트

  • 사용자의 숫자가 컴퓨터의 숫자와 하나도 일치하지 않으면 낫싱을 출력한다.
  • 사용자의 숫자가 컴퓨터의 숫자와 1개는 일치하고, 위치가 다르면 1볼을 출력한다.

추가 학습 자료

  • 숫자 야구 피드백 강의

(2) 코치와 수다 타임

2주 차 미션이 끝난 다음 날 두 번째 코수타(코치와 수다 타임)이 있었다.

두 번째 코수타는 이곳에 자세히 정리해두었다! 세 분의 코치 님과 함께 유튜브 라이브로 소통하며 진행되었다. 이번에는 안드로이드 코치님 두 분도 나오셨다!

아주 간단하게 내용을 정리하자면, 아래와 같다.

1. 테스트는 아주 작은 단위부터 차근차근 해보기 시작해라.
2. 포비 님의 피가 되고 살이 되는 위로...



3. 피어 리뷰 스터디 시작! 코드 리뷰 내용

(1) 이 스터디에서는 뭐해요?

피어 리뷰를 하는 스터디가 시작됐다. 어떤 분이 프론트엔드 피어 리뷰 스터디원을 모집한다고 하셔서 냉큼 신청했고, 선착순 5명 안에 들어서 하게됐다.

스터디 내용은 아래와 같다. 피어 커파일링, 피어 리뷰를 하게 된다. (둘 다 처음 들어보는 용어였음)

2주 차 미션이 끝난 다음 날인 오늘 모여서 두시간 정도 스터디를 진행했다. 항상 생각하지만 게더타운 캐릭터는 정말 귀엽다.

스터디에서 리뷰받은 내용을 정리해봤다.


(2) 피어 리뷰 내용 정리

README 부분

  • 민재 님처럼 ‘흐름 파악’ 부분을 작성해보자!

자바스크립트 컨벤션 부분

  • else if는 if로! else를 지양하자(얼리 리턴)
  • for문 대신 forEach() 사용하기(가독성 부분)
  • 마지막 코드 끝에 한 줄 띄워야 함(프리티어 등을 쓰자)
  • ++, — 는 컨벤션에서 지양함. += 1 등으로 쓰는게 좋음
  • 객체 안에 마지막도 ,를 쓴는 것이 좋다

👉 자바스크립트 컨벤션을 다시 한번 쭉 정독해야겠다

클린코드 부분

  • 변수 설정 - 1, 2는 따로 상수로 처리(변수 이름)
  • 함수를 여러 파일에 나눠서 저장하기 - 유지보수 측면
  • for을 쓸 때 i 대신 더 구체적으로!
  • reaponse ⇒ 안의 기능을 함수로 분리하는 것이 좋을 것 같다!
  • for for if를 forEach로 나누기
  • class별로 분리를 했으면 좋았을 것 같다
  • getHint, gameLoop 안에 기능이 많은 것 같다
  • computerPick을 따로 변수로 빼는게 낫지 않았을까?
  • constant는 바깥으로 빼주기

테스트 부분

  • 테스트코드 짜기(다른 팀원의 코드를 참고하자)

코드 오류 부분

  • sayStart()에 this를 써야 함. 클래스라서. 아니면 static을 붙여야 함(객체지향)
    👉 이부분 이해 못해서.. 객체지향에 대해 공부해야 한다.
  • trim()을 안써줘도 될 것 같음(3자리가 아닌 수를 이미 거르기 때문에)
  • 반환값이 있어야 하는 함수에는 return을 꼭 쓰자.
  • 내려가기 규칙을 적용하자!(처음 알았다)

부가적인 설정 부분

  • package.json, package.lock.json은 아예 커밋이 안되게 설정하면 좋을 것 같음
  • prettier, ESlint 등을 쓰자(커밋만 안하면 됨)

(3) 피어 리뷰 소감

사실 1주 차에도 피어 리뷰를 경험해봤다. 스터디의 공식 일정은 아니었지만, 따로 이 스터디에 있는 민재 님, 예슬 님과 리뷰를 주고받은 적이 있다.

그리고 커뮤니티에서도 두 분 정도가 '리뷰해주세요!'라고 한 내 글을 보시고 간단한 리뷰를 해주셨다.

그런데 이렇게 각잡고 하는 리뷰는 처음이라 스터디 전에 무척 떨렸다. 사실 내가 이분들께 도움이 될까..? 하는 생각에 스터디에서 나갈까 말까 고민한 적이 한두번이 아니다. 근데 어디선가 코드 리뷰에는 칭찬, 질문도 포함된다고 해서 용기를 내어 남아있기로 했다.

일단 남아있길 정말 잘한 것 같다!! 코드 리뷰에서 정말 정말 많은 것을 알아갔다.

🧡 민재 님

자바스크립트 컨벤션 전체를 외우고 계신 듯 했다. 마지막 줄은 띄우는 것, 쌍따옴표 대신 홑따옴표를 쓰는 것, else를 지양하는 것(얼리 리턴), for for 대신 forEach를 쓰는 것.. 등등이 모두 컨벤션이었다는 것을 처음 알았다. (그리고 민재 님이 구조분해할당을 사랑하신다고 하셔서, 그정도로 좋구나! 하는 생각이 들어 나도 구조분해할당을 적극적으로 이용해야겠다고 생각했다.)

💛 철원 님

철원 님은 스터디 장이신데, 스터디는 이렇게 진행해야 하는구나! 하고 알아갈 수 있을 정도로 멋진 리더십을 보여주셨다. 코드 리뷰도 피피티를 만들어서 자세하게 해주셔서 정말 많은 것을 새롭게 알아갔다.

💚 예슬 님

게임에 들어가는 문자열 등을 새 변수로 선언하여 다른 파일로 분리하신 것을 보고 나도 다음에는 꼭 저렇게 해야지!! 하고 생각했다. 그리고 클린코드에 대한 링크도 주시면서 클린 코드에 대하여 많이 리뷰해주셨는데, 몰랐던 부분이 많아 새롭게 배워갔다.

💙 현호 님

나와 가장 비슷하게 코드를 짜셔서 어떤 고민을 하셨고 어떤 생각으로 코드를 짜셨을지 많이 공감이 갔다. 현호 님과 나 둘 다 함수를 각기 다른 파일로 분리하지 않는다든가 상수를 새로운 변수로 선언하지 않는 등 비슷한 리뷰를 받았다. 리뷰해주실 때 코드에 대한 전체적인 느낌에 대한 리뷰와 함께 칭찬도 해주셔서 많은 도움이 되었다.



4. 3주 차에 공부해야 할 것

코드리뷰를 받고 뭘 공부해야할지 알게되었다.

이건 정말 중요한데.. 내가 뭘 모르는지, 뭘 개선해야할지도 몰랐는데 이제 뭘 모르는지를 알게 된 것이다!! 기쁜 마음으로 공부할 수 있을 것 같다.

정리해보니 진짜 공부할게 정말 정말 많다😇 후후.. 하나씩 공부해보자!!!!!

  1. 자바스크립트 컨벤션 쭉 읽기
  2. 객체, class, static 등 공부
  3. 테스트 공부
  4. 클린 코드 공부
  5. 내장 함수 공부
    • 최소한 한 번씩이라도 직접 코딩해면서 공부하기
    • forEach, reduce 필수
  6. 2주 차 공통 피드백 자세히 읽기


5. 2주 차 회고, 스터디 팀원들 회고 모음

포스팅 중간중간 회고를 하기도 했지만, 이제는 정말 사담이 섞여있는 2주 차 회고이다.

(1) 2주 차 나의 회고

몰입하지 못해서 아쉬움이 남았다

일단 이번 주는 정말 아쉬움이 많이 남는다. 2주 차 프리코스에 완전히 몰입했나? 하면 아니라고 답할 것이기 때문이다.

학교를 다니면서 기말고사는 완전히 포기했지만, 이번 주에 발표 과제가 두 개 있었고, 하나는 졸업을 위한 수업의 발표여서 공을 들여야 했다. 정말 큰 부담이 되었고.. 완벽주의라는 좋지 않은 성격으로 인해 발표 자료를 끊임없이 다시 체크하며 시간을 써서 2주 차 프리코스에 도저히 집중을 할 수 없었다.

건강 관리를 하자

최근 잠을 잘 못자고 있다. 할게 많아서 긴장이 되는지 저저번주에는 4일을 밤을 새며 공부했고, 그 후에도 매주 이틀은 밤을 새는 것 같다. 하지만.. 인생은 길게봐야하니 건강을 관리해야 한다고 하신 현호 님의 말씀처럼 정말 건강을 관리해야겠다는 생각이 들었다. 잠을 못자서 면역력이 약해졌는지 발이 다 텄고, 다래끼가 났고 자주 토할 것 같고 오늘은 갑자기 온몸이 간지러워서 급하게 알러지 약을 먹었다. 이렇게 살다가 정말 죽는다.. 조심해야겠다.

모르는 것이 많아서 기가 죽었다

문제를 처음 받았을 때, 예전부터 몰랐지만/알아야 하지만/공부해야 하지만 공부하지 않아 부채감을 갖고 있었던 개념인 class가 나와서 굉장히 당황했고, 어떻게 동작은 시켰지만 끝내 완전히 이해하지는 못했다. 피어 리뷰에서 다른 팀원들이 짠 코드를 보고서야 class가 뭔지 조금 알게 된 것 같다. 처음부터 모르는 것이 나와서 기가 죽었고, 그래서 몰입할 의지가 많이 꺾였던 것 같다.

얻은 것은?

함수를 분리하는 법을 알게 됐다

사실 이번에 함수 분리를 처음 해본다. 함수 분리를 어떻게 하는 건지 아무것도 몰라서 1주 차 미션이 끝나고 세운 목표는 바로 함수를 분리해보자였고, 2주 차에 이것은 알아갈 수 있었다. 함수를 분리한다는 것은 정말 신기했다. 기능을 나눈다는 것은 이런 거구나, 지금까지 내가 했던 건 코딩이 아니었던 것 같아!! 하고 느끼기도 했다. 그정도로 기능별로 함수를 만든 것은 신기한 경험이었다. (하지만 한 함수 당 하나의 기능을 하도록 완벽하게 만들지는 못했다. 코드 리뷰에서 지적도 받음! 3주 차에는 개선하여 하나의 기능을 하는 함수를 만들어볼 것이다.)

뭘 모르는지, 그래서 앞으로 뭘 공부해야 하는지 알게 됐다

다른 사람들과 함께 공부한다는 것은 정말 대단한 효과를 주는 것 같다. 남이 뭘 아는지 인지함으로써 내가 뭘 모르는지도 함께 인지하게 해준다. 내가 뭘 몰라서 괴로워하고 답답해했는지를 이번 피어 리뷰를 통해 많이 알게 되었다. 그리고 우테코 측에서 제공한 2주 차 공통 리뷰도 많은 도움이 되었다.

주저하지 말고 질문을 하자

이번 주에는 질문을 거의 하지 않았다. 모른다는 사실이 부끄러웠고, 그래서 질문하는 것이 두려웠다.

작년에 같은 경험을 한 적이 있다.
당시 아무것도 모르는 채로(이 말에 과장은 1%도 없다😂) 프로젝트를 하게 됐는데, 그때 아는 것이 아무것도 없어서 자주 울고.. 포기할까 수없이 생각하고 괜히 팀원들에게 피해만 주는 것이 아닐까 생각했던 적이 있었다.

그런데 그때 팀장님이 모르는 것은 반드시 물어봐야 한다고 강조하며 말씀하셔서 거의 하루종일 질문하는 무언가로 살았던 적이 있다. 혼자 삽질해서 8시간 걸렸는데 팀장님이 설명해주면 15분에 끝나는 경험을 한 이후로 팀장님은 제발 본인에게 질문해서 알아가라고 하셨다. 그래서 그때 매일 팀장님과 팀원에게 질문을 했고, 그래서 그랬던 건지는 모르지만 프로젝트를 성공적으로 마친 경험이 있다.

이때 팀원들에게 피해만 줄 것이라고 생각했으나, 실제로 나중에 내가 질문하는 내용을 본인도 몰랐다/내가 열심히 하는 모습을 보고 많이 자극받았다/회의 시간에 적극적으로 질문해서 분위기가 좋아졌다는 피드백을 받았다. 이것은 정말 자랑이 아니라 신기해서 아직도 기억하고 있기 때문에 적어보았다. 잘 모르는 사람도 도움을 줄 수 있다는 것을 알게 된 경험이었다.

하지만 현재 프리코스에서 함께 공부하라고 하면서 무작정 질문하지 않고 일단 혼자 공부해야 한다고 말씀하셔서 조금 혼란스러웠다.(아마 아예 노력하지 않고 질문하지 말라는 의도가 아닐까 생각한다.) 또한 남들은 모르면 구글링을 해서 알아가는데, 나는 구글링을 아무리 해도 모른다. 👉 나의 노력 부족인가? 라는 생각으로 이어져 심리적으로 조금 괴로웠던 것 같다.

그래서 질문을 하지 않게 되었고, 또 위축되어 질문을 부끄러워했는데 일단 나는 질문을 하는게 맞다는 결론을 내렸다. 질문을 남발한다고 해도, 그렇게 생각하는 사람들은 지나칠 것이고 아니라고 생각하는 사람들은 답을 해줄 것이다. 나는 아직 질문하지 않고 공부할 수 있는 단계가 아니라고 생각한다. 혼자 끙끙대며 며칠간 같은 코드를 짜는 것보다 남의 코드를 보고 배우는 것이 훨씬 많고, 검색해도 나오지 않는 결과로 위축되어 자기비하할 이유도 없는 것 같다.

그리고 나는 내가 최선을 다해 열심히 한다는 것을 알고 있다. 질문을 할 정도로 안 되면 정말 내 힘으로는 할 수 없는 거지, 내가 노력을 하지 않는 것이 아니다.고 믿기로 했다. 그래서, 앞으로는 주저하지 않고 질문을 하기로 했다.

사람마다 의견이 많이 갈릴 수 있다고 생각한다. 그런데 나는 독학을 하기 때문에 특히 질문을 하지 않으면 취약해질 수 있다고 생각한다. 지난 시간 동안 독학하며 질문을 해도 되는가? 내가 혼자 알아가야 하는 거 아닌가? 하는 생각으로 오랫동안 괴로웠고, 그래서 포기하려고 한 적도 많았다. 그런데, 뭘 해도 포기하는 것보다는 낫겠다는 생각이 든다. 그래서 앞으로는 질문을 할 것이다.

3주 차에는 정말 몰입해야지

3주 차에는 발표도 없고 과제도 거의 없다! 정말.. 이제는 몰입뿐이야 공부 열심히 해야지...

그리고 철원 님의 블로그에서 많은 도움을 받았기 때문에 내가 공부한 것이 남들에게 도움이 될 수 있다는 생각을 하게 되었다. 그래서 공부한 내용을 철원 님처럼 블로그에 공유하려고 한다.


(2) 스터디 팀원들 회고 모음

정말 정말 많은 도움을 주시는 스터디 팀원분들의 회고이다. 두고두고 보려고 정리해보았다.

앞으로 회고를 쓰시는 분이 더 있으면 추가할 예정이다!



정말 마지막으로

진짜 마지막으로.. 글이 3만자가 넘어가서 맞춤법 검사를 거의 하지 못했다. 아마 띄어쓰기에서 틀린 부분이 많을 것 같은데, 읽으실 때 양해를 부탁드린다.

그리고 프리코스 하시는 다른 분들의 회고를 모두 읽고 있는데, 다들 대단하신 것 같다.

항상 많이 배우고 갑니다, 3주 차에도 모두 화이팅해요!!😚

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

2개의 댓글

comment-user-thumbnail
2022년 11월 10일

잘 봤습니다! 블로그 정리를 굉장히 잘하시는 것 같아요~!! 쭉쭉 읽히네요. ㅎㅎ

1개의 답글