[우아한테크코스5기] ⚾ 숫자야구 게임

진승범·2022년 11월 9일
0
post-custom-banner

개요

2주차 미션은 숫자야구 게임을 여러 요구사항에 맞춰서 개발하는 것이었다. 확실히 1주차 미션 때보다 더욱 더 많은 조건들이 붙어있었다. 주의깊게 본 부분은 다음과 같다.

추가된 요구사항 및 주의사항

가장 눈에 띄는 요구사항은 인덴트와 한 가지 일만 하는 메소드 그리고 테스트 코드였다. 1주차 미션 때, 인덴트가 많은 코드를 작성했던 기억이 있다. 이걸 어떻게 줄여야 하지 하는 고민이 있었는데, 이번 주차는 기능 목록을 잘 정의하여 메소드 분리를 잘 해야겠다고 다짐했다. 그리고 알곤 있었지만, 자세하게는 모르던 JUnit과 AssertJ를 활용한 테스트 코드 작성에도 심혈를 기울였다. 추가적으로 자바 코드 컨벤션에 대해서 지켜야 했다.

기능 목록

📌 컴퓨터(상대방) 숫자 생성

  • 컴퓨터의 숫자 3자리를 생성합니다.
  • 숫자가 중복되지 않도록 검증합니다.

📌유저(사용자) 숫자 생성

  • 사용자로부터 숫자를 입력받습니다.
  • [3자리, 숫자, 중복되지않음] 조건을 만족하는 지 검증합니다.
  • 만족하지 않는다면 IllegalArgumentException 발생시킵니다.

📌 Count(스트라이크/볼) 결과 관리

  • 컴퓨터 숫자와 유저 숫자를 바탕으로 스트라이크와 볼을 판별하고 관리합니다.
  • 판별 결과를 바탕으로 힌트(Hint) 문자열을 생성합니다.

📌 Inning 관리 기능

  • 야구에서 사용하는 용어 Inning(이닝) 을 의미하며, 한 번의 숫자 야구 게임을 관리합니다.
  • 입/출력 기능, 컴퓨터와 유저 숫자 생성 및 판별 결과 관리를 포함합니다.

📌 Game 관리 기능

  • 게임 자체를 관리합니다.
  • 사용자가 컴퓨터의 숫자를 맞춘다면 게임 재시작 여부를 물어 재시작하거나 종료합니다.

📌 입/출력 기능

  • 사용자에게 게임 진행에 도움을 주는 문자열을 출력을 담당합니다.
  • 사용자로부터 게임에 사용될 숫자나, 게임 재시작 여부를 입력받습니다.

기능은 우선 이 정도로 정의했다. 그리고 이에 맞춰서 클래스들을 작성했다.

Indent 줄이기

indent를 줄이기 위해선 메소드를 분리하는 것이 중요하다. 그리고 메소드 분리를 용이하게 잘 하려면 로직의 구조를 잘 짜는 것 역시 중요하다. 숫자 야구 게임을 개발하다보면, 많은 이들이 반복문 두 개를 중첩시켜서 개발하였을 것이다. 이를 분리하여 개발하지 않는다면 많은 indent가 생성될 것이다.

이번 주차에서는 indent를 줄이기 위해서 메소드와 클래스를 잘 분리하여 작성했다고 생각했지만, 피어 리뷰에서 간과한 부분이 있었다는 것을 깨달았다.

while (true) {
            List<Integer> computerNumber = ComputerNumber.generate();
            InningManager.play(computerNumber);
            if (!isRegame(BaseballGameInput.getRegameStatus())) {
                break;
            }
        }

해당 코드를 살펴보면 if문이 들어가 있어 indent가 2인 것을 확인할 수 있다. 이 if문은 무한 반복문을 종료시키는 코드인데, 아래와 같이 바꾸면 indent를 줄일 수 있다는 피드백을 받았다.

while (isRegame(BaseballGameInput.getRegameStatus()) {
            List<Integer> computerNumber = ComputerNumber.generate();
            InningManager.play(computerNumber);
        }

하지만 이렇게 바꾸게 되면 게임을 최초 시작했을 때, 게임 재시작 여부를 물어보기 때문에 로직을 조금 수정해야 했다. 그래도 indent를 줄여 가독성을 높일 수 있어 충분히 시도해볼만한 방법이었다.

테스트 코드

처음에는 로직을 중심으로 프로그램을 작성했지만, 테스트를 해보려고 할 때 막상 테스트 하기 용이하지 않은 부분이 있었다. 예를 들어 UserNumber는 유저의 숫자를 생성하고 검증한다. 생성할 때에는 사용자의 입력을 받는데, 테스트 시에 입력을 받기보단 값을 넣어 케이스 별로 검증을 하고 싶었다. 다음 코드를 같이 살펴보자.

public class UserNumber {
	public static List<Integer> generate() {
    	String userNumber = Console.readLine();
        // 검증 및 리스트 변환 로직
    }
}

여기서 generate() 메소드를 테스트 하고 싶을 때, 테스트 코드를 구현하기가 만만치 않다. 나는 다음과 같이 코드를 테스트 해보고싶었다.

@Test
void 세자리가_아닌_숫자_입력() {
	String userNumber = "1234";
    
	assertThrownBy(() -> UserNumber.generate(userNumber))
            .isInstanceOf(IllegalArgumentException.class);
}

이런식으로 테스트 코드를 작성하려면 메소드의 구조를 바꾸어야 했다.

public class UserNumber {
	public static List<Integer> generate(String userNumber) {
        // 검증 및 리스트 변환 로직
    }
}

이런식으로 구성한 후 호출하는 부분에서 UserNumber.generate(Console.readLine()) 이렇게 호출하게 되면 위에 작성한 테스트 코드로 테스트를 진행할 수 있고, 비즈니스 로직도 정상적으로 수행된다. 이 외에도 테스트가 용이하게끔 클래스 및 메소드 구조를 설계하여 작성하려고 노력했다.

소감

Discussion에 공유된 다른 분들의 코드를 보며 참 많이 배웠다. 개발은 공부보단 직접 해봐야 는다고 하지만 남의 코드를 보는 것도 많이 늘게 되는 것 같다. 이번 주차에서는 로직보단 코드의 가독성 및 테스트 즉 요구사항을 중점적으로 생각하며 미션 풀이를 했다. 하루하루 지나면서 코드의 품질을 신경 쓰는 시간이 늘어갔다. 그리고 TDD에 관심이 생겨 켄트 백의 '테스트 주도 개발' 이라는 책을 구매했다. 등하교 시간에 조금씩 조금씩 읽어볼 예정이다. 또한 피어리뷰를 처음으로 받아봤는데, 꽤나 많이 신경쓰고 작성했던 코드도 다른 분들이 피드백을 남겨주시니까 아직 한참 부족하다고 생각했다. 하지만 앞으로 배울 점이 많이 남아있다는 사실이 설레기도 한다. 이제 곧 3주차가 시작하는데, 남은 미션들을 수행하면서 어제보다 나은 개발자가 되기를 기대한다 😊

참고자료
https://tecoble.techcourse.co.kr/post/2020-06-10-one-level-of-indentation-per-method/
https://tecoble.techcourse.co.kr/post/2020-05-10-single-job-method/
https://da-nyee.github.io/posts/tecoble-unit-test-vs-integration-test-vs-acceptance-test/
https://tecoble.techcourse.co.kr/post/2020-05-07-appropriate_method_for_test_by_parameter/
https://www.youtube.com/watch?v=3LMmPXoGI9Q

이번 주차 때 주의해야 할 점!

✅ 자바 코드 컨벤션 지키기!
✅ 좋은 테스트 코드 작성하기!
✅ indent를 줄여 가독성 높이기!
✅ 메소드 작성 시 한가지 일만 시키기!
✅ 스스로 생각하고 풀어보기!

post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 11월 10일

잘보고갑니다!

답글 달기