기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.
IllegalArgumentException
을 발생시킨 후 애플리케이션은 종료되어야 한다.test/java/study
를 참고하여 학습한 후 테스트를 구현한다.docs/README.md
에 구현할 기능 목록을 정리해 추가한다.docs/README.md
에 정리한 기능 목록 단위로 추가한다.[번호]. [기능] - [클래스명]
public void gameStart() {
Computer computerBalls = new Computer();
this.strike = 0;
this.ball = 0;
System.out.print("숫자를 입력하세요 : ");
String userBalls = Console.readLine();
Exception.Check(userBalls);
while (throwBall(userBalls, computerBalls.getComputerBalls())) {
this.strike = 0;
this.ball = 0;
System.out.print("숫자를 입력하세요 : ");
userBalls = Console.readLine();
Exception.Check(userBalls);
}
}
서로 밀접한 개념은 같은 파일에 속하는 것이 좋습니다.
무엇을 하는지 이해하기 위해 이 조각 저 조각이 어디에 있는지 찾고 기억해야 한다.
함수나 변수가 정의된 코드를 찾으러 상속 관계를 거슬러 올라간 경험이 있다면 공감할 것이다.
같은 파일에 속할 정도로 밀접한 두 개념은 세로 거리로 연관성을 표현합니다.
연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 여기저기 뒤져야 한다.
private void compareBalls(int userBall, ArrayList<Integer> computerBalls, int ballCount)
int computerBall;
boolean isStrike;
boolean isBall;
for (int computerBallCount = 0; computerBallCount < computerBalls.size();
computerBallCount++) {
computerBall = computerBalls.get(computerBallCount);
isStrike = (ballCount == computerBallCount);
isBall = (userBall == computerBall);
refereeBall(userBall, computerBall, isStrike);
}
}
private void compareBalls(int userBall, ArrayList<Integer> computerBalls, int ballCount)
int computerBall;
isStrike;
for (int computerBallCount = 0; computerBallCount < computerBalls.size();
computerBallCount++) {
int computerBall = computerBalls.get(computerBallCount);
boolean isStrike = (ballCount == computerBallCount);
boolean isBall = (userBall == computerBall);
refereeBall(isBall, isStrike);
}
}
사실 loop문 안에 있든, 메서드 지역변수로 있던 "무엇을 하는지 이해하기 위해 이 조각 저 조각이 어디에 있는지 찾고 기억해야 한다. 함수나 변수가 정의된 코드를 찾으러 상속 관계를 거슬러 올라간 경험이 있다면 공감할 것이다." 이런 일이 일어날것 같지는 않지만 수정했다.
구현 전에 어떻게 돌아가는지 기능에 대해서 정의만하고 TestCase를 만들다 보니 Access Modifier를 고려하지 않았다.
그러다 보니 막상 구현했을때 필요없는 getter를 만들어야하고, 나중에 기능을 완성하고 Access Modifier를 public에서 private로 수정하고 나니 사용 할 수 없는 테스트가 되었다.
이 경우에 어떻게 처리를 해야되는지 찾아보았다.
[JUnit] private 메서드, 변수 테스트 방법, Unit Test Private Methods in Java
저번 주 단체 피드백 부분 중 잘 못지켰다고 생각하는 의미 있는 커밋 메시지 작성, , git을 통한 자원 관리, space와 tab 혼용을 중점적으로 체크했고 이 부분은 이번에는 잘 지킨거 같다.
"메서드에 오직 한 단계의 들여쓰기(indent)만 허용했는가?" 이 부분이 이번에는 반드시 지켜야 할 추가된 요구사항으로 나왔지만 저번 주 부터 지킬려고 애쓴덕인지 이번에는 그렇게까지 이 요구사항을 준수하는게 어렵지는 않았다.
처음 작성한 코드들은 들여쓰가가 2 단계인 소스들도 있었지만, 정말 작은 단위의 기능으로 나누니 금방 들여쓰기를 없앨 수 있었다.
우아한테크코스 클린코드 원칙에 있는 부분들이 결국 앞으로 요구사항으로 추가될 것 같아 이 부분에 있는 것들을 다 지켜며
"메소드의 인자 수를 제한했는가?" 최대 3개 (3개도 가능한 줄이는게 좋다)
1개의 method 빼고 전부 이러한 점을 준수하고 있는데, 매개변수가 3개인 compareBalls method인데, 매개변수를 줄이기 위해 새로운 클래스를 만들려다가, 매개변수의 특징을 공통적으로 가지는 네이밍을 못하겠어서, 그대로 사용하는게 가독성 괜찮은 것 같아 이 method는 매개변수가 3개인 상태로 두기로 했다.
private void compareBalls(int userBall, ArrayList<Integer> computerBalls, int ballCount) {
for (int computerBallCount = 0; computerBallCount < computerBalls.size();
computerBallCount++) {
int computerBall = computerBalls.get(computerBallCount);
boolean isStrike = (ballCount == computerBallCount);
boolean isBall = (userBall == computerBall);
refereeBall(isBall, isStrike);
}
}
private void compareBalls(UserComBall userComball, int ballCount) {
for (int computerBallCount = 0; computerBallCount < computerBalls.size();
computerBallCount++) {
int computerBall = userComBall.getComputerBalls(computerBallCount);
int userBall = userComBall.getUserBalls(ballCount);
boolean isStrike = (ballCount == computerBallCount);
boolean isBall = (userBall == computerBall);
refereeBall(isBall, isStrike);
}
}
"콜렉션에 대해 일급 콜렉션을 적용했는가?" 일급 콜렉션이라는 말을 들어본적이 없어 공부했는다.
Collection을 Wrapping하면서, 그 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 합니다.
Wrapping 함으로써 다음과 같은 이점을 가지게 됩니다.
1. 비지니스에 종속적인 자료구조
2. Collection의 불변성을 보장
3. 상태와 행위를 한 곳에서 관리
4. 이름이 있는 컬렉션
나의 코드 중에 Computer가 일급 콜렉션을 통해 구현했다.
내가 이해한 일급 콜렉션 처럼 Collection 멤버 변수 하나만을 Wrapping하고, 중복이 없도록 생성되록 상태와 행위를 한 곳에서 관리한다.
public class Computer {
private ArrayList<Integer> computerBalls;
public Computer() {
this.computerBalls = new ArrayList<>();
while (computerBalls.size() < BALL_MAX_SIZE) {
int randomNumber = Randoms.pickNumberInRange(1, 9);
duplicationCheck(randomNumber);
}
}
public ArrayList<Integer> getComputerBalls() {
return computerBalls;
}
private void duplicationCheck(int randomNumber) {
if (!this.computerBalls.contains(randomNumber)) {
this.computerBalls.add(randomNumber);
}
}
}
네이밍과 클래스 분리를 많이 고민했는데, 다른 사람들도 읽기 편한 코드 인지 많이 궁금해서 바로 피어리뷰를 받아보고 싶다.
잘보고갑니다!
저도 2주차하면서 클린코드 5장의 내용이 도움이 많이됐는데 공감되네요 ㅎㅎ😊