우테코

[우아한테크코스 6기] 프리코스 3주차 회고록

처누 2023. 12. 18. 16:15
다음은 2주 차 공동 피드백에 적혀있는 내용이다. 내가 확인해야할 피드백은 다음과 같다.

1. 기능 목록을 재검토한다.
 - 이 부분은 계속 신경 쓰고 있다. '구현해야 할 기능 목록을 정리하는데 집중한다.'라고 적혀있는데 말 그대로 구현해야 할 기능만 정리하자. 특히 예외 상황은 기능을 구현하면서 계속해서 추가해 나가자.

2. 기능 목록을 업데이트한다.
 - 처음부터 기능 목록을 완벽하게 작성하고 구현하려고 애썼다. 이럴 필요 없이 구현해가면서 기능 목록을 업데이트 해도된다.

3. 값을 하드 코딩하지 않는다.
 - 사실 2주 차에서는 Const클래스를 만들어서 메시지와 숫자에 대한 상수값을 설정하고 사용했다. 3주 차에는 enum을 공부해서 사용해보자.

4.구현 순서도 코딩 컨벤션이다.
 - 클래스는 상수, 멤버 변수, 생성자, 메서드 순으로 작성하자. 상수같은 경우는 맨처음에 사용하는데 멤버 변수, 생성자 순서를 꼭 기억하자.

5. 변수 이름에 자료형을 사용하지 않는다.
 - 2주 차에서 자동차 이름이 담긴 리스트의 변수명을 carNameList나 carList로 명명했다. 변수 이름에 자료형, 자료 구조 등을 사용하지 말자.

6. 한 함수가 한 가지 기능만 담당하게 한다. 함수가 한 가지 기능을 하는지 확인하는 기준을 세운다.
 - 테스트 코드를 작성하면서 한 함수가 여러 기능을 담당하게 구현했던 메서드를 발견했었다. 한 함수가 한 가지 기능만 담당하게 구현한다면 테스트 코드 작성도 수월해질 것이다. 여러 기능을 담당한다면 함수 분리를 고민하자. 또한, 한 함수의 길이를 15라인을 넘어가지 않도록 주의해보자.


7. 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다.

 - 코딩테스트 공부할 때 값이 제대로 입력되서 출력이 되는지 확인하기 위해 코드 사이사이에 System.out.println()를 삽입하여 결과를 확인했었다. 하지만 코드가 방대해진다면 모든 코드를 이런식으로 확인하기 어려울 것이다. 이것을 방지하고 효율적으로 확인하기 위해 테스트를 작성한다고 생각한다.

8. 처음부터 큰 단위의 테스트를 만들지 않는다.
 - 이것의 의미는 무엇일까. 나는 Arguments를 사용하여 Map과 List를 반환해 결과를 테스트 하는 기능을 구현했었다. 이것도 큰 단위의 테스트 일까? 아니면 테스트 코드 작성 중 발견했던 한 함수가 한 가지 기능만 담당하도록 구현을 하라는 의미일까? 아무튼 작은 단위의 테스트를 할 수 있도록 코드를 구현하자!

 

 아래는 3주차 때 제출한 코드이다.

https://github.com/woowacourse-precourse/java-lotto-6/pull/1167

 

[로또] 천현우 미션 제출합니다. by Cheonwooo · Pull Request #1167 · woowacourse-precourse/java-lotto-6

 

github.com

 

 

- 클래스(객체)를 분리하는 연습

 2주 차 때는 기능을 분리해서 클래스를 여러개로 나눠보았다. 진행하면서 패키지를 나누고 싶었지만 제대로 된 개념이 없었고 어떻게 해야하는지 감이 안잡혀서 클래스만 구분했는데 이번 3주 차 메일로 클래스를 분리하는 연습이 적혀있길래 잘하고 있구나라고 생각했다. 이번 주차에는 패키지를 나누어서 진행해보자.

 

- 도메인 로직?

 '이 코드가 현실 문제에 대한 의사 결정을 하고 있는가?' 도메인 로직을 구분할 때 생각해야 하는 것이다. 메일 내용에 보면 '도메인 로직에 대한 단위 테스트를 작성하는 연습'이라고 되어있었다. 이 말의 의미가 뭘까 하고 생각해봤다. 도메인 로직을 공부하면서 이 말에 대한 의미를 깨달았다. 테스트를 해야될 것과 안해야될 것을 명확하게 분리해서 테스트의 가성비가 올라가는 것이다. 3주차에서는 패키지를 domian, constant, service로 나누어 구현해보려고 한다.

 

- IllegalArgumentsExeception과 다른 Exception들과의 차이?

기능 구현 중 "Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다."라는 요구사항이 있었다. 예를 들면 사용자가 입력하는 값이 null이라면 NullPointerExcepiton을 처리하라는 의미로 받아들였다. 근데 이렇게 구현하다보면 하나의 try/catch문에서 여러개의 예외를 처리할 수가 없었다. 여기서 하나의 궁금증이 발생했다. IllegalArgumentsException은 메서드가 허가되지 않거나 부적절한 arguments를 받았을 경우에 던지는 예외라고 알고있다. 그러면 NullPointerException이나 NumberFormatException을 포함하는 의미가 아닐까?라는 의문이 생겼다. NumberFormatException 클래스를 들여다보니 IllegalArgumentsException을 extends하고 있었다. 즉, IllegalArgumentsException안에 NumberFormatException이 포함되는 것이다. NullPointerException 클래스를 들여다보니 RuntimeException을 extends하고 있었고, RuntimeException은 Exception을 extends하고 있었다. 요구사항에서 Exception이 아닌 명확한 유형을 처리하라고 했다. 이 부분은 어떻게 해결해야 할까?

 이 부분은 전부 IllegalArgumentsException으로 처리했다.

 

- UnsupportedOperationException?

Lotto클래스를 사용하여 구현하고 테스트를 실행하던 도중 다음과 같은 오류가 발생했다.

찾아보니 수정할 수 없는 값을 수정하려고 할 때 발생하는 에러였다.. Lotto로 객체 생성후 List를 생성할 때 Lotto클래스 안에서 List를 반환하는 getLottoNumbers()메서드를 통해 List<Integer> lottoNumbers = lotto.getLottoNumbers(); 이렇게 List를 생성했다. getLottoNumbers()가 List를 반환하는데 List<Integer> lottoNumbers = List면 에러가 발생하면 안되는게 아닌가 생각했다. 에러 코드를 보니 Collections.sort(lottoNumbers)에서 에러가 발생했고, Collections 클래스 파일을 들어가서 sort메서드를 보니 list.sort(null) null값을 정렬하는 경우 발생하는 에러로 구현되어있었다. 즉 내가 getLottoNumbers()메서드로 반환한 List가 null이라는 것이었다. Lotto 클래스에서 List<Integer> numbers는 final로 정의되어있던걸 까먹고 계속 그 값을 바꾸려다보니 발생한 에러였다! lotto.getLottoNumbers()를 new ArrayList<>()감싸고 다시 테스트해보니 정상 작동했다.