Review
우선, 1주차의 시간 관리 부족으로 인해 마무리와 마감에 있어 너무나 큰 아쉬움이 남았었습니다.
덕분에(?) 확실히 2주차 미션 구현에 있어서는 1주차 보다 더욱 열심히 불태울 수 있었던 것 같습니다. 또한, 경험치가 조금 쌓여서 데드라인을 조금 넉넉하게 잡고 구현을 해서 리팩토링, 스타링일 수정, 컨벤션 맞추기, README.md 명세 등등.. 1주차에 계획만 세우고 지키지 못 했던 내용들을 어느정도 많이 지켜낼 수 있었던 것 같아서 아쉬운 점도 많았음에도 성장했다는 점에서 만족합니다.
개인적으로 함수형 패러다임으로 주로 개발했던만큼 이번 과제에서는 보다 객체지향적인 클래스와 생성자, 메소드 등의 사용법을 익히고 사용해서 개발해보는게 재미있었던 것 같습니다.
TDD 방식으로 문제 정의와 접근 방법도 조금 다각화 해보고, 문제 요구사항에서 정확하게 기술되어 있지 않은 부분은 직접 명세 및 정의해가면서 풀어보기도 하고, 코치님들의 피드백도 되새김질 하면서 개발해보니, 이전에 경험해보지 못 했던 적당한 압박감으로 부터 오는 적당한 스트레스가 기분 좋았던 것 같습니다.
무엇보다 문제 정의와 기초 기능 구현에 충실하려고 노력했습니다. 코치님들이 리뷰해주신 1 주차 피드백 중에 다소 놓치고 있었던 점들도 있었기에 개발을 할 때 계속해서 이를 상기시키면서 개발하려고 노력했습니다. 특히 신경 썼던 부분은 코드의 '가독성'과 '메소드의 최소 단위'입니다.
메소드 1개당 기능 1개씩으로 나누어 구현했지만, 전체적으로 보았을 때 유의미한 분할을 했다거나 재사용성이나 퍼포먼스를 끌어올리진 못 했던 것 같다.
"상수"라는 개념을 제대로 이해하고 적용하지 못 했던 것 같다. 코드 컨벤션 중에서 상수에게는 스네이크 케이스를 적용해서 선언하라는 부분을 보고 const로 선언한 모든 변수들을 지칭하는 줄 알았다. 모든 const가 들어간 부분을 전부 스네이크 케이스로 선언했는데 이는 해석에 오류가 있었던 부분이다. 문제 내에서 정해져 있는 확실한 숫자를 상수로써 정의하고 사용한다면, 클래스를 분리할 때 상수들을 파일 단위로 쪼개서 따로 객체 형태로 보관하고 게임 메소드가 있는 메인 파일에서 불러와 사용했다면 어땠을까? 싶다.
class 형으로 구현하는 부분이나 기능 단위로 굉장히 잘게 쪼개서 객체 지향적인 패러다임으로 구현하는 것의 장점을 제대로 살리지 못했다. 모듈화 시켜서 반복해서 사용할 수 있는 부분들은 불러다 사용한다거나, 클래스 단위의 분할 자체가 프로그램의 퍼포먼스 향상에 영향을 끼치지는 못 했던 것 같다.
TDD 방식을 채용해서 개발하기는 했지만, 이를 문제를 푸는데 있어서 접근 방법 및 문제 해결 과정에 제대로 적용시키지 못 했다. 이 부분은 2 주차 공통 피드백에서도 나온 내용인데, 테스트 하나하나의 단위들을 큰 단위부터 시작하는 것이 아니라 아주 작은 단위부터 시작하라는 내용이었다. '메소드 단위의 개발 - 테스트'의 형태로 개발해보자..
private과 정적 메소드를 활용하지 못 했다.
else 키워드 및 부정 연산자 사용 했던 부분을 미처 수정하지 못 하고 제출해서 아쉬움이 남는 것 같다.
코드 컨벤션을 완벽하게 지키면서 개발하지는 못 했던 것 같다.
flowchart 작성. 개발에 들어가기 전에 문제 정의와 함께 플로우 차트를 작성해보고 흐름을 좀 명확하게 그린 후에 구현 단계로 넘어가려고 한다.
린팅 적용해보기. (for apply convention - es-lint) 3주차 미션 부터는 컨벤션 적용에 있어서 하나하나 순수 체크하기에 놓치는 부분이 많을 수 있다 보니, 개발 기능 규모가 커지는 만큼 보다 자동화 시킬 수 있는 방법인 린팅을 해보려고 한다.
상황에 따라, 정적 메소드도 활용해보기. (2주차에서는 프로토타입 메소드와 생성자만 사용해서 개발했었는데, 3주차 부터는 필요에 따라 정적 메소드도 활용해서 개발해려고 한다)
상수 파일 분리해서 관리 해보기. 따로 상수들을 객체로 담아서 관리하고, 핵심 로직 구현부에서 그때그때 가져다 사용해보자.
else 키워드 및 조건문에 부정 연산자 사용 지양하기.
유의미한 모듈화 및 클래스 분할 / 메소드 분할하기 + 정적 메소드, private 개념을 적용해서 활용해보기.
다양한 js 메소드들을 적용해보기. 쓰는 것만 쓴다고, 개발하다보니 어느 순간 코드가 자꾸 익숙한 메소드들로만 구성되어지는 느낌을 받아서, 다른 분들의 코드도 좀 참고하고, 공식문서도 뒤적거리면서 보더 다양한 js 메소드들을 적용해서 구현해볼 예정이다.
jest 공식문서를 찾아보면서, 개발 초반부 부터 메소드 단위로 테스트 케이스를 작성해서 구현해볼 예정이다.
1주차에 부족했던 점을 어느정도 2주 차에 채우는데 성공했다고 생각한다. 3주차에는 2주차에 아쉬웠던 점과 느낀점을 채워서, 총 1달간의 프리코스 기간 동안 매주 계속해서 성장하는 것이 가장 큰 목표이다.
클래스 내에서 private 개념. '#' (필드..?)
좀 더 다양한 js 메소드들.
린팅. (es-lint5) 참고할 인사이트
jest. (jest 공식문서)
정적 메소드. (딥다이브 책 참고)
컨벤션. 에어비엔비 자바스크립트 코드 컨벤션.
참고한 인사이트: 1주차 미션 피드백.
추가된 요구 사항:
indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
함수(또는 메소드)가 한 가지 일만 하도록 최대한 작게 만들어라.
Jest를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.
++ 추가로 적용 해본 내용
커밋 메시지 구조
커밋 타입: 제목(커밋 로그 타이틀) 바디(옵션)
🍎 chore: 자잘한 수정
📄 docs: 문서 관련
🖊 feat: 새로운 기능, 페이지 추가
🎨 style: 코드 포맷팅, 세미콜론 누락 등 코드 자체의 변경이 없는 경우
🐞 fix: 버그 수정
💡 refactor: 코드 리팩토링
🧪 test: 테스트 관련
접근 방식.
이번엔, 다양한 테스트 케이스들을 기반으로 한 개발론. 테스트 주도 개발(TDD)방법을 적용해서 개발해보고자 했다.
1주차 미션 진행에 있어 원래 계획에 실패한 가장 큰 이유가 바로 '시간 부족'이었다.
미션 수행 중 가장 크게 시간을 소모시킨 부분이 바로 예외 케이스들에 처리 + 각 문제들에 대해 사전에 정확하게 정의 내리지 않았기 떄문이다.
-> 때문에 TDD 방식으로 문제를 사전에 정의 내리고 기능에 대한 명세를 보다 구체적으로 할 수 있다면
1주차 미션 해결 과정중에 발생했던 다양한 이슈들을 예방해 줄 수 있는 방법이라고 생각이 들었다.
사용자가 잘못된 값을 입력한 경우에 대한 처리를 담당하는 기능이다. 야구 게임은 3 자리수를 기점으로 게임 메커니즘이 돌아가는데, 1자리수 혹은 2자리수 등 3 자리수가 아닌 수의 경우 + 1~9를 제외한 모든 기타 등등의 입력값(문자열, 특수 문자 등) + 중복된 수가 들어오는 경우를 체크해서, 하나라도 잘 못 되었을 경우 false 값을 반환해준다.
사용자가 입력한 숫자를 '볼' / '스트라이크'/ '낫싱'이라는 조건으로 검사해서 충족하는 내용을 반환해주는 기능이다. 스트라이크 검사 기능 메소드와 볼 검사 기능 메소드를 호출해서 볼과 스트라이크의 갯수를 알아낸다. -> 알아낸 두 개의 수를 바탕으로 사용자에게 보여줄 힌트를 문자열로 담아서 반환해준다. 또한, 스트라이크의 개수가 3개인지 검사해서 만약 3 스트라이크로 컴퓨터의 랜덤 한 세자리 수를 모두 맞췄다면, 게임이 끝났다는 내용을 boolean 형식으로 담아놓았다가 힌트와 함께 배열 형태로 반환해준다.
입력값에 '볼'이 있는지 검사해주는 기능으로, 컴퓨터에서 뽑아낸 3자리의 랜덤한 수와 사용자가 입력한 값을 비교해서 수의 자리는 다르지만 값은 일치하는 수가 있는지 검사한다. -> 여기서 중요한 점은 수의 자리는 다르고, 값만 같다는 조건이어야 한다는 점이다. 해당 조건에 맞는 수의 갯수만큼 카운트해서 반환해준다.
입력값에 '스트라이크'가 있는지 검사해주는 기능으로, 컴퓨터에서 뽑아낸 3자리의 랜덤한 수와 사용자가 입력한 값을 비교해서 수의 자리와 값까지 일치하는 수가 있는지 검사한다. -> 해당 조건을 만족하는 수의 개수를 반환해준다.
컴퓨터의 랜덤 수이자 게임의 정답을 생성해주는 기능으로, 중복되지 않는 임의의 1 ~ 9 사이의 수로 이루어진 세자리 수를 만들어서 반환해준다.
게임의 전반적인 프로세스를 관리하는 메인 로직 기능으로, 사용자에게 숫자를 입력받아 -> 해당 숫자가 올바른 값인지 체크해주는 메소드를 호출한다. 올바르지 않은 값이라면 throw 문을 사용해 예외를 발생시킨후 애플리케이션을 종료한다. -> 올바른 값이라면 2번 메소드를 호출해서 사용자에게 보여줄 출력 값(힌트)과 게임을 계속 진행해도 되는지 여부를 받아온다. -> 사용자에게 힌트를 출력해주고, 만약 받아온 값 중 게임이 끝났다는게 true 값이라면, 게임을 종료하는 메소드를 호출 / 그게 아니라면 다시 자기 자신을 호출해줘서 다음 숫자값을 입력받을 수 있도록 한다.
게임이 정상적으로 종료되었을 때(스트라이크 갯수 === 3) 호출되는 메소드로 엔딩 멘트를 출력해주고, 게임을 재시작할지 아예 종료할지 1 or 2로 사용자에게 입력값을 받는다. 재시작 명령어인 1이 입력되면 재시작 메소드를 호출해주고, 다른 값이 입력되면 프로그램을 종료한다.
게임 재시작이 입력되었을 때 호출되는 메소드로 정답(컴퓨터의 랜덤 수)을 새로운 값으로 초기화시켜주고, 6번 메인 메소드인 play를 호출해준다.
게임이 시작되었을 때 생성자 함수에 의해 최초로 호출되는 메소드로, 오프닝 멘트("숫자 야구 게임을 시작합니다.")를 출력해준다.
생성자 함수로, 9번 메소드를 호출해서 오프닝 멘트를 출력해주고, 5번 메소드를 호출해서 정답(컴퓨터의 랜덤 수)을 초기화 시켜준다.
Section 2에서 구현한 기능 목록들을 각각의 정체성들에 맞게 다음과 같이 세 가지의 파일로 나누어보았다.
순수 게임 실행 관련 메소드들. (게임 시작 / 사용자로부터 직접적인 입력 값을 받고, 일정 조건들에 따라 게임 진행 / 게임 종료 / 재시작 등의 게임 실행 관련 기능들)
게임 실행에 필요한 로직 기능 수행 메소드들. (낫싱 / 볼 / 스트라이크 갯수 체크 및 힌트 메시지 생성 기능)
로직과 상관 없는 정적 형태의 게임 자원 메소드들. (맞는 형식인지 체크 기능 for 예외처리 / 랜덤한 1~9 세자리 수 생성 기능)
게임이 정상적으로 종료 된 이후에, 게임의 재시작과 종료 사이에서 잘 못 눌렀을 경우 다시 1, 2번 버튼을 입력할 수 있게 로직을 구현해 두었다.
이 부분은 요구사항에 명세되어 있지 않았던 부분이라 알아서 판단하여 구현한 기능인 만큼, 테스트 케이스에 추가를 해 잘 돌아가는지 확인하면서 진행하였다.
최대한 TDD 기반으로 개발을 진행하려고 했던 만큼, 기존 케이스에 포함되지 않은 내용들을 하나하나 넣어보면서 예외 처리 / 정상적인 값일 때의 경우의 수 세분화 / 게임 종류 이후의 예외처리 까지 꼼꼼하게 체크하면서 개발을 진행해볼 수 있었다.