20241030 우테코 프리코스 2주차 피드백, 3주차 체크리스트
우테코 프리코스 2주차 과제를 제출했다.
이번에도 3주차 과제를 시작하기 전 2주차 공통 피드백을 정리해보려고 한다.
우테코 프리코스 2주차 과제 공통 피드백
학습 목표 : 함수 분리와 테스트 도구 사용법 익히기
▶ 🔺 함수 분리는 잘했다고 생각하는데, pr을 하다보니 테스트 도구 사용법 익히기는 조금 부족했던 것 같다.
다른 사람과 비교하다 보면 조바심이 생길 수 있지만 다른 사람과의 비교보다는 어제의 나와 비교하며 자신의 속도에 맞추어서 마무리하는 것을 목표로 삼아보자.
이번 경험이 ‘좋은 프로그래머로 성장하는 중요한 역량을 키우는 과정’임을 기억하기.
2025 우테코 입학 설명회에서 설명했듯이 메타인지를 위한 최고의 도구 중 하나는 회고라고 한다.
회고를 통해 우리는 학습과 경험을 그냥 지나치지 않고 반성하고 개선할 수 있음. 회고를 작성하자.
우테코 크루들이 작성한 내용 참고하기
▶ 🔺 2주차 과제 제출하면서 소감에 회고를 작성했다. 입학 설명회도 시간될 때 한번 봐보도록 하자.
단위 테스트와 같은 용어가 아직 낯설 수 있지만, 작은 기능부터 테스트를 작성하는 연습을 차근차근 해 나가면 빠르게 성장할 수 있음.
1주차 피드백에서 제공된 문자열 덧셈 계산기 피드백 강의에 단위 테스트를 작성하는 내용이 있으니 이름 참고하자.
▶ ✅ pr도 하고 강의도 보고 생각한것. 상수를 꺼낸다거나 해서 중복 코드를 피하자.
README.md를 상세히 작성한다
미션 저장소의 README.md는 소스 코드 이전에 프로젝트의 개요를 소개하는 문서다.
이 문서를 통해 해당 프로젝트가 어떤 프로젝트인지, 주요 기능이 무엇인지 소개할 수 있다.
효과적으로 작성하기 위해 마크다운 문법을 검색하여 학습하고, 이를 활용해 README.md를 작성해 본다.
▶ ✅ 확인완료! README.md에 구현할 기능을 정리하라고 해서 그것만 했지 다른 내용도 작성할 생각을 못했다. 이번에는 프로그램 소개를 간략히 작성해보자
기능 목록을 재검토한다
기능 목록을 작성할 때 클래스 설계와 구현, 메서드 설계와 구현 같은 상세한 내용은 포함하지 않는다. 클래스 이름이나 메서드 시그니처, 반환값 등은 언제든지 변경될 수 있기 때문이다. 구현해야 할 기능 목록을 중심으로 작성하되, 정상적인 경우뿐만 아니라 예외 상황도 함께 정리한다. 예외 상황은 시작 단계에서 파악하기 어려우므로, 기능을 구현하면서 지속적으로 업데이트하는 것이 좋다.
▶ ✅ 클래스 이름이나 메서드 시그니처, 반환값 등은 언제든지 변경될 수 있기 때문에 구현해야 할 기능 목록 중심으로 작성. 그리고 예외 상황도 같이 정리하기. 잘한것 같다!
기능 목록을 업데이트한다
README.md 파일의 기능 목록은 구현 과정에서 변경될 수 있다. 시작부터 모든 기능을 완벽하게 정리해야 한다는 부담을 갖기보다는, 기능을 구현하면서 문서를 지속적으로 업데이트하는 것을 목표로 한다. 이를 통해 죽은 문서가 아닌 살아있는 문서로 유지될 수 있도록 노력해 보자.
▶ ✅ 이 부분도 항상 하고 있는 부분이다.
값을 하드 코딩하지 않는다
코드 내에서 문자열이나 숫자 값을 하드 코딩하지 않는다. 대신 상수(const)를 정의하고 의미 있는 이름을 부여하여 해당 값이 어떤 역할을 하는지 명확히 드러낸다. 구글에 “javascript const” 등의 키워드로 검색하여 상수 구현 방법을 학습하고 코드에 적용해 본다.
▶ ✅ 하드 코딩이란 무엇인가.
안 좋은 코딩 습관을 말할때 꼭 언급되는 것이 하드코딩인데 하드코딩이 뭘까? 하드코딩이란 프로그램의 소스 코드에 데이터를 직접 입력해서 저장하는 것이라고 한다. 주로 파일 경로, URL 또는 IP 주소, 비밀번호, 화면에 출력될 문자열, 조건문 안에 들어가는 숫자 등이 대상이 되는데 예를 들어서, 경로로 FILE("C:/Users/User/file.txt");
이런식으로 FILE()안에 직접 경로를 적거나 if (number > 5)
이렇게 5라는 숫자를 사용하는 경우도 하드코딩에 해당된다.
하드코딩의 문제점에는 의미를 파악하기 어렵고 유지 보수하기 어렵다는 점이 있다.
그냥 위의 예시처럼 ‘5’를 사용할때는 무슨 의미인지 바로 알기가 어렵다는 것이다. 이렇게 하드코딩을 하게 되면 가독성이 안 좋은 코드가 될 확률이 높다고 한다. 따라서 const STANDARD = 5;
이렇게 상수를 정의하고 조건문 안에서는 이 상수를 활용한다면(if (number > STANDARD)
) 의미를 더 명확히 전달할 수 있고 가독성 좋은 코드가 된다.
또한 유지 보수하기 어렵다. 만약 12개월 할부를 가정하고 프로그램을 작성하기 위해 메서드 내에서 12라는 숫자를 바로 사용했었는데, 이후에 6개월 할부로 변경해야 한다면 12라는 숫자를 일일이 6으로 변경해야하고 혹시나 수정을 못하는 부분이 생긴다면 문제가 생길 것이다. 즉 변화에 대응하기 어려운 코드, 유지 보수하기 어려운 코드가 된다.
이번에 pr에서 ‘시도 횟수’를 직접 넘긴 이유에 대해서 피드백 받았었는데 생각해보니 이것도 하드 코딩이었다. 상수를 사용하자.
구현 순서도 코딩 컨벤션이다
클래스는 필드, 생성자, 메서드 순으로 작성한다.
class A {
필드
생성자
메서드
}
▶ ✅ 클래스 필드는 클래스 내에 변수를 선언할 수 있는 부분이라고 생각하면 될듯. 원래는 생성자 내에서 인스턴스 프로퍼티를 정의할 수 있었다면, 클래스 필드에 변수를 선언하면 인스턴스의 변수가 되는 것이다.
class Person{
constructor(){ // 생성자
this.firstName = "Lee";
}
}
const p = new Person();
class Person{
firstName = "Lee"; // 필드
}
const p = new Person();
위 코드는 같은 코드. 둘 다 p를 콘솔에 찍어보면 Person {firstName: 'Lee'}
로 같음.
한 메서드가 한 가지 기능만 담당하게 한다
함수의 길이가 길어진다면 여러 기능을 한 함수에서 처리하려는 신호일 가능성이 높다. 예를 들어, 안내 문구 출력, 사용자 입력 처리, 유효값 검증 등의 작업을 한 함수에 모두 포함하는 대신, 이를 각기 다른 함수로 분리해 본다.
// bad
const userInput = () => {
MissionUtils.Console.readLine("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분): ", (input) => {
const carNames = input.split(",");
for (int index = 0; index < carNames.length; index++) {
if (carNames[index].length < 1 || carNames[index].length > 5) {
throw new Error("[ERROR] 자동차 이름은 1자 이상 5자 이하만 가능합니다.");
}
}
return carNames;
});
};
▶ ✅ 노력한 부분이다!
메서드가 한 가지 기능을 하는지 확인하는 기준을 세운다
여러 메서드에서 중복되는 코드가 있다면 이를 별도 메서드로 분리하는 것을 고려한다. 메서드의 길이가 길어지면 여러 기능을 포함하고 있을 가능성이 커지므로, 15라인이 넘지 않도록 구현하면 의식적으로 메서드를 분리하는 연습을 할 수 있다.
▶ ✅ 기준 세우기. 여러 메서드에서 중복되는 코드가 있으면 분리. 메서드 길이가 15라인이 넘으면 분리.
테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다
테스트를 작성하면 기능의 정확성을 점검함을 넘어 코드의 즉각적인 피드백을 받을 수 있다. 테스트 작성 과정을 통해 구현한 기능의 문제를 빠르게 발견할 수 있을 뿐만 아니라, 코드의 구조와 의도를 명확히 이해하는 데도 도움을 받을 수 있다. 학습 도구로도 활용할 수 있는데, 수 많은 테스트의 장점 중 본인이 가장 공감하는 작성 이유를 작성해 본다.
학습테스트를 통해 JUnit 학습하기
▶ ❌ 학습테스트를 통해 JUnit 학습해보기. 나도 pr을 하려고 할 때 테스트 케이스들을 먼저 봐서 이 사람이 빠짐없이 기능을 구현했는가를 빠르게 파악할 수 있었다. 2주차 과제에서 작성하지 않은 테스트 케이스가 좀 있었다.(ex. name1,,name2) 이번에는 테스트할 케이스가 어떤것들이 있는지 더 고민해보자.
처음부터 큰 단위의 테스트를 만들지 않는다
테스트의 핵심 목적 중 하나는 코드에 대해 빠르고 자주 피드백을 받는 것이다. 처음부터 큰 단위의 테스트를 작성하게 되면, 작성한 코드의 문제를 발견하기까지 시간이 오래 걸린다. 따라서 문제를 작게 나누어 핵심 기능부터 작게 테스트를 만들어 가는 것이 효과적이다.
- 큰 단위의 테스트 // bad
- 자동차 경주 게임을 시작하여, 사용자가 이름과 진행 횟수를 입력하고, 게임을 진행한 후 결과를 확인한다.
- 작은 단위의 테스트 // good
- 무작위 값이 4 이상이면 자동차가 전진한다.
- 무작위 값이 3 이하이면 자동차가 전진하지 않는다.
- 무작위 값이 4 이상이면 자동차가 전진한다.
▶ ✅ 작은 단위로 테스트하자.
JavaScript에서 객체를 만드는 다양한 방법을 이해하고 사용한다
JavaScript에서는 클래스를 사용하는 방법 이외에도 객체를 만드는 다양한 방법이 존재한다. 다양한 객체 생성 방식을 익히면 유연하게 코드를 설계할 수 있다.
JavaScript 객체 기본
Classes
▶ 🔺 읽어보기.
우테코 프리코스 3주차 과제 체크리스트
# 학습 목표
- [ ] 관련 함수를 묶어 클래스를 만들고, 객체들이 협력하여 하나의 큰 기능을 수행하도록 한다.
- [ ] 클래스와 함수에 대한 단위 테스트를 통해 의도한 대로 정확하게 작동하는 영역을 확보한다.
- [ ] 2주 차 공통 피드백을 최대한 반영한다.
<br>
# 과제 제출 전 체크 리스트
- [ ] 요구 사항에 명시된 출력 형식을 따랐는가
- [ ] 모든 테스트가 성공적으로 실행되는가
<br>
# 과제 진행 요구 사항
- [x] 미션은 로또 저장소를 포크하고 클론하는 것으로 시작한다.
- [ ] 기능을 구현하기 전 README.md에 구현할 기능 목록을 정리해 추가한다.
- [ ] Git의 커밋 단위는 앞 단계에서 README.md에 정리한 기능 목록 단위로 추가한다.
- [ ] AngularJS Git Commit Message Conventions을 참고해 커밋 메시지를 작성한다.
- [ ] 자세한 과제 진행 방법은 프리코스 진행 가이드 문서를 참고한다.
<br>
# 기능 요구 사항
- [ ] 로또 번호의 숫자 범위는 1~45까지이다.
- [ ] 1개의 로또를 발행할 때 중복되지 않는 6개의 숫자를 뽑는다.
- [ ] 당첨 번호 추첨 시 중복되지 않는 숫자 6개와 보너스 번호 1개를 뽑는다.
- [ ] 당첨은 1등부터 5등까지 있다. 당첨 기준과 금액은 아래와 같다.
- [ ] 1등: 6개 번호 일치 / 2,000,000,000원
- [ ] 2등: 5개 번호 + 보너스 번호 일치 / 30,000,000원
- [ ] 3등: 5개 번호 일치 / 1,500,000원
- [ ] 4등: 4개 번호 일치 / 50,000원
- [ ] 5등: 3개 번호 일치 / 5,000원
- [ ] 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다.
- [ ] 로또 1장의 가격은 1,000원이다.
- [ ] 당첨 번호와 보너스 번호를 입력받는다.
- [ ] 사용자가 구매한 로또 번호와 당첨 번호를 비교하여 당첨 내역 및 수익률을 출력하고 로또 게임을 종료한다.
- [ ] 사용자가 잘못된 값을 입력할 경우 "[ERROR]"로 시작하는 메시지와 함께 Error를 발생시키고 해당 메시지를 출력한 다음 해당 지점부터 다시 입력을 받는다.
- [ ] 로또 구입 금액을 입력 받는다. 구입 금액은 1,000원 단위로 입력 받으며 1,000원으로 나누어 떨어지지 않는 경우 예외 처리한다. ex) 14000
- [ ] 당첨 번호를 입력 받는다. 번호는 쉼표(,)를 기준으로 구분한다. ex) 1,2,3,4,5,6
- [ ] 보너스 번호를 입력 받는다. ex) 7
## 출력
- [ ] 발행한 로또 수량 및 번호를 출력한다.
- [ ] 로또 번호는 오름차순으로 정렬하여 보여준다. ex) [8, 21, 23, 41, 42, 43]\n [13, 14, 16, 38, 42, 45]
- [ ] 당첨 내역을 출력한다. 3개 일치 (5,000원) - 1개\n 4개 일치 (50,000원) - 0개\n 5개 일치 (1,500,000원) - 0개\n 5개 일치, 보너스 볼 일치 (30,000,000원) - 0개\n 6개 일치 (2,000,000,000원) - 0개
- [ ] 수익률은 소수점 둘째 자리에서 반올림한다. (ex. 100.0%, 51.5%, 1,000,000.0%) ex) 총 수익률은 62.5%입니다.
- [ ] 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다. ex) [ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다.
- [ ] 실행 결과 예시
/*
구입금액을 입력해 주세요.
8000
8개를 구매했습니다.
[8, 21, 23, 41, 42, 43]
[3, 5, 11, 16, 32, 38]
[7, 11, 16, 35, 36, 44]
[1, 8, 11, 31, 41, 42]
[13, 14, 16, 38, 42, 45]
[7, 11, 30, 40, 42, 43]
[2, 13, 22, 32, 38, 45]
[1, 3, 5, 14, 22, 45]
당첨 번호를 입력해 주세요.
1,2,3,4,5,6
보너스 번호를 입력해 주세요.
7
당첨 통계
---
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
총 수익률은 62.5%입니다.
*/
# 프로그래밍 요구 사항
- [ ] Node.js 20.17.0 버전에서 실행 가능해야 한다.
- [ ] 프로그램 실행의 시작점은 App.js의 run()이다.
- [ ] package.json 파일은 변경할 수 없으며, 제공된 라이브러리와 스타일 라이브러리 이외의 외부 라이브러리는 사용하지 않는다.
- [ ] 프로그램 종료 시 process.exit()를 호출하지 않는다.
- [ ] 프로그래밍 요구 사항에서 달리 명시하지 않는 한 파일, 패키지 등의 이름을 바꾸거나 이동하지 않는다.
- [ ] 자바스크립트 코드 컨벤션을 지키면서 프로그래밍한다.
- [ ] 기본적으로 JavaScript Style Guide를 원칙으로 한다.
- [ ] Airbnb 자바스크립트 스타일 가이드
- [ ] 네이밍 컨벤션
- [ ] 소스의 변수명, 클래스명 등에는 영문 이외의 언어를 사용하지 않습니다.
- [ ] 클래스, 메서드 등의 이름에는 특수 문자를 사용하지 않습니다.(ex) function $some(){} (x))
- [ ] 상수명은 SNAKE_CASE(전부 대문자. ex) firefox(x), FIREFOX(o), is_left(x), IS_LEFT(o))로 작성합니다.
- [ ] indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- [ ] ex) while문 안에 if문이 있으면 들여쓰기는 2이다.
- [ ] 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다.
- [ ] 3항 연산자(조건문 ? 선택문1:선택문2)를 쓰지 않는다.
- [ ] 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
- [ ] Jest를 이용하여 정리한 기능 목록이 정상적으로 작동하는지 테스트 코드로 확인한다.
- [ ] 테스트 도구 사용법이 익숙하지 않다면 아래 문서를 참고하여 학습한 후 테스트를 구현한다.
- [ ] Using Matchers
- [ ] Testing Asynchronous Code
- [ ] Jest로 파라미터화 테스트하기: test.each(), describe.each()
- [ ] 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- [ ] 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
- [ ] else를 지양한다.
- [ ] 때로는 if/else, when문을 사용하는 것이 더 깔끔해 보일 수 있다. 어느 경우에 쓰는 것이 적절할지 스스로 고민해 본다.
- [ ] 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
- [ ] 구현한 기능에 대한 단위 테스트를 작성한다. 단, UI(System.out, System.in, Scanner) 로직은 제외한다.
- [ ] 단위 테스트 작성이 익숙하지 않다면 'LottoTest'를 참고하여 학습한 후 테스트를 작성한다.
- [ ] @woowacourse/mission-utils에서 제공하는 Random 및 Console API를 사용하여 구현해야 한다.
- [ ] Random 값 추출은 Random. pickUniqueNumbersInRange()를 활용한다.
- [ ] ex) MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); // 1에서 45 사이의 중복되지 않은 정수 6개 반환
- [ ] 사용자의 값을 입력 및 출력하려면 Console.readLineAsync()와 Console.print()를 활용한다.
- [ ] 제공된 Lotto 클래스를 사용하여 구현해야 한다.
- [ ] Lotto에 numbers 이외의 필드(인스턴스 변수)를 추가할 수 없다.
- [ ] numbers의 접근 제어자인 #은 변경할 수 없다.
- [ ] Lotto의 패키지를 변경할 수 있다.
- [ ] Lotto 클래스
/*
class Lotto {
#numbers;
constructor(numbers) {
this.#validate(numbers);
this.#numbers = numbers;
}
#validate(numbers) {
if (numbers.length !== 6) {
throw new Error("[ERROR] 로또 번호는 6개여야 합니다.");
}
}
// TODO: 추가 기능 구현
}
*/
Leave a comment