[우테코] level-1 / mission1 회고
![[우테코] level-1 / mission1 회고](/assets/images/thumbnail/woowa-racingCar.png)
요약 우테코 1주차 RacingCar 미션을 수행하며 배운 내용을 정리했습니다. 페어프로그래밍 후기 및 test 코드 작성에 대한 소감을 작성했습니다.
목차
미션 1단계
페어 프로그래밍
우선 우테코 1주차를 지내며 가장 큰 전환점이라고 한다면 페어프로그래밍을 진행하게 된 점이다. 사실 페어프로그래밍을 들어봐서 알고는 있었지만 실제로 해본 적은 없어서 사실상 우테코에서 처음 진행하게 된 학습 방식이였다.
짧게나마 소감을 나눠보자면,, 우선 생각보다 쓰이는 에너지 소모가 크다는 점이다. 혼자 생각했을 땐 그저 생각하는 대로 바로 작성할 수 있었는데 페어프로그래밍을 진행하다보니 상대방은 어떻게 생각하는지, 왜 이렇게 사용해야하는지 등을 설명해야 하는 부분이 많았다.
서로 사고하는 방식이 다르니 당연한거긴 하지만,,! 그래도 두배로 신경써야 할 부분이 많아졌던 것 같다. 하루에 사용할 수 있는 에너지가 방전되어버리면 사회성을 잃어버리는 나이기에.. (우리개는 물어요) 어쩌면 나에게 가장 조절이 많이 필요했던 부분이 아니였나 싶다. 😂
페어프로그래밍을 통해 좋았던 점이라고 한다면 효과적으로 내 생각을 정리하고 전달할 수 있게 된 것 같다. 계속해서 소통하고 설득하고 토론해야 하기에 끊임없이 생각하고 어떻게 하면 더 상대방에게 내 의도가 전달 될 수 있을까? 하는 고민을 많이 했던 것 같다.
그리고 당연한 부분이겠지만 매번 페어가 바뀔 때 마다 새로운 방법을 시도하게 된다. 이번에는 class 방식을 사용했다면 다음번엔 함수형으로도 작성해보고.. 많은 시도를 해보게 되고 그 과정 속에서 각 방법의 장단점을 찾게 되는 것 같다.
간단한 회고
조금 이전에 썼던 표현을 그대로 살려보자면 “이틀 다녔는데 한달 다닌 듯한 느낌이 드는건 참 생소했던 것 같다"”라는 표현이 있는데,, 그냥 최고의 비유라고 할 수 있다. 😂 매번 생각하고 토론하고 끊임없이 고민하는 방법을 가르친다. 그리고 그 속에서 우리는 야생학습
을 통해 스스로 배울 점을 찾고 정리하며 일어서야 한다는게 지금까지의 내 느낌이다.
그리고 그건 그만큼 에너지를 많이 쓰고 또 투자한다는 의미이기도 해서, 체력이 굉장히 중요한 것 같다는 생각을 한다. (운동가야지…..)
공부내용
📌 Q3 ) PR피드백 - test 코드를 작성하는 기준
📌 Q1 ) 테스트를 진행해야 하는 값은 어디까지일까
✔️ A1 ) test에서 진행해야 하는 경계 값은 n,n+1
이렇게 두 값만 테스트 진행하면 된다.
📌 Q2 ) mock 사용을 최대한 지양하자
테스트를 진행하다 보면 제어되지 않는 값들 (랜덤 숫자)을 테스트 하기위해 mock
함수를 사용하는 경우가 있다. 공원은 mock
함수 사용을 최대한 지양 하라고 하는데, 그럼 랜덤 값에 대한 test는 어떻게 진행해야 하는가?
✔️ A2 ) 제어할 수 없는 값은 최대한 그 값을 호출하는 부모가 제어 가능하도록 수정하자.
예를 들어 이번 racingCar
미션에서는 자동차가 움직이기 위한 조건으로 랜덤 숫자가 4 이상일 때 앞으로 전진할 수 있다.
이때 Car
객체의 move()
함수 안에서 랜덤 숫자를 생성하고, 판단하고, 앞으로 한칸 움직이는 역할을 부여하는 것이 아니라 car
객체를 불러오는 부모로부터 랜덤값을 제어 가능하도록 하는 방법이다.
1
2
3
4
5
6
7
//Car 객체에서 랜덤 값 사용 + 관리
move(){
const randomNum = Math.floor(Math.random() * 10);
if(randomNum <= 4 ){
this.#position +=1;
}
}
위와 같이 객체를 사용하게 되면 move() 라는 함수를 test하기 위해선 randomNum
이라는 객체를 제어할 수 있어야 한다. 그렇기에 mock
함수를 사용할 수 밖에 없게 되는데 이때 이 역할을 부모로 넘긴다면 아래와 같이 리팩토링 가능하다.
1
2
3
4
5
6
move(number){
if(number <= 4) {
this.#position +=1;
}
}
위와 같이 랜덤 숫자 생성을 Car
객체를 호출하는 부모에게 맡기고, Car
에서는 그 값만 받아와서 전진할지, 멈출지만 판단하면 더 좋은 코드가 될 수 있다.
📌 Q3 ) PR피드백 - test 코드를 작성하는 기준
미션을 진행하며 궁금했던 점은 class의 private 변수가 동작하는 것을 확인하기 위한 코드를 작성 할 필요가 있을까에 대한 의문점이였다. 이전 프리코스 피드백 중에 하나가 test코드를 위한 코드 작성을 지양하라고 했는데, 그렇다면 private 함수와 변수에 대해서는 test를 진행할 수 없는가? 에 대한 고민이 생겼었다.
PR 답변을 통해 정리된 생각으로는 private으로 선언된 함수와 변수들은 대게 public에서 사용되게 된다.
✔️ A3 ) 그렇다면 public으로 선언된 함수들이 제대로 동작하는 것을 검증할 수 있다면 private으로 선언된 함수들 또한 테스트 가능하다고 생각한다.
추가로, private과 public 함수를 나누는 기준은 사용자가 건드려도 되는 부분과 건드리면 안되는 부분을 기준으로 나눌 수 있을 것 같다.
이번주 키워드
🔑 K1 ) 함수 선언문 VS 함수 표현식
함수 선언문
function
키워드를 사용해서 함수를 선언 => 전역 또는 지역에서 독립적 사용- 호이스팅이 적용되어 선언 전에 호출 가능
- 익명 함수 불가능
1
2
3
function sayHello() {
console.log("Hello!");
}
함수 표현식
- 함수가 변수에 할당되는 형태 => 다른 변수에 할당하여 사용
- 호이스팅이 안된다. 즉, 선언 전에 호출할 수 없다.
- 익명 함수 가능
1
2
3
const sayHello = function () {
console.log("Hello!");
};
🔑 K2 )클래스, 함수, 객체
클래스를 사용하는 경우
- 인스턴스를 생성해야 하거나 상태를 관리해야 하는 경우
- 상속을 사용해야 하는 경우 (extends)
- 호이스팅 안돼서 정의 전에 사용 불가능 +
new
키워드 필수임
일반 객체를 사용하는 경우
- 단순한 데이터 구조를 저장할 때 ( 하나의 고정된 객체를 다룰 경우 )
- 전역으로 상태를 관리해야 하는 경우에서도 사용함.
- 함수 선언문으로 사용하면 호이스팅 자유로움.
🔑 K3 )비동기 처리의 다양한 접근
callBack
- 함수의 매개변수로 콜백을 전달해서 비동기 작업이 완료된 후 실행
- 콜백 중첩이 많아지면 콜백 지옥 발생 가능
- 에러처리의 경우 콜백 안에서 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
function fetchData(callback) {
setTimeout(() => {
callback(new Error("Something went wrong"), null);
}, 1000);
}
fetchData((err, data) => {
if (err) {
console.error("Error:", err); // 에러처리 방식
return;
}
console.log(data);
});
promise
.then
과.catch
를 사용해서 체이닝 가능- 콜백보다 가독성도 좋고 여러 개의 비동기 작업을 이을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
fetchData()
.then((data) => console.log(data))
.catch((err) => console.error("Error:", err)); // 에러처리 방식
async/awit
- ES8에서 도입된 방식으로 비동기 코드를 동기 코드처럼 작성 가능
try/catch
로 간편한 예외처리 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
async function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
async function main() {
try {
const data = await fetchData();
console.log(data);
} catch (err) {
console.error("Error:", err); // 에러처리 방식
}
}
main();
🔑 K4 ) 명령형 프로그래밍 VS 선언형 프로그래밍
명령형 프로그래밍
- “어떻게(How) 해결할 것인가“를 중점적으로 다룬다. 단계별로 명확한 명령을 내리는 방식
- 프로그램이 어떤 절차로 동작해야 하는지를 명확하게 기술함
- 개발자가 직접 로직의 흐름 관리
- 장점 : 실행 흐름 직접 제어 => 직관적
- 단점 : 상태 관리의 어려움 => 유지보수의 어려움 + 사이드 이펙트 발생가능
1
2
3
4
5
6
7
// mission : 배열의 모든 원소를 2배로 만들기
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = [];
for (let i = 0; i < numbers.length; i++) {
doubledNumbers.push(numbers[i] * 2);
}
선언형 프로그래밍
- “무엇(What)을 해결할 것인가“를 중점적으로 다룬다. 결과를 선언적으로 표현하고 내부 동작 방식을 추상화
- 어떻게가 아니라 무엇을 할 것인지 기술
- 개발자가 구현하지 않고 목표를 기술
- 장 : 코드가 짧고 간결 => 유지보수 좋음 + 사이드 이펙트 적음
- 단 : 내부 동작의 추상화 -> 성능 최적화 / 예측이 어렵다.
1
2
3
4
5
// mission : 배열의 모든 원소를 2배로 만들기
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map((num) => num * 2);
console.log(doubledNumbers); // [2, 4, 6, 8, 10]