우아한테크코스 6기 : 프리코스 2주차 회고

Handwoong
self-retrospect
Published in
4 min readNov 1, 2023

2주차 미션 — 자동차 경주

2주차 미션의 목표

프리코스 2주차 미션의 목표는 함수의 분리함수별로 테스트 작성 하는 것이다.
기능 단위로 함수를 분리하고 테스트를 작성하게 되면 좋은 단위 테스트가 만들어지는 경험을 해보라는 의도라고 생각되었다.

2주차 미션 중 배운 것

프리코스 2주차 미션을 진행하면서 고민하고, 찾아봤던 내용들은 다음과 같다.

  1. 랜덤값 테스트는 어떻게 할까?
  2. getter와 setter를 지양하자.

2번 항목은 명확한 가이드가 없었다.
그래서 나름대로 장단점을 비교해서 나만의 기준점을 세우고 적용하였다.

랜덤값 테스트는 어떻게 할까?

자동차 경주 테스트 케이스는 mock 을 사용해서 랜덤값을 테스트하고 있다.

이걸 그대로 가져다 써도 되겠지만 의도한 방향은 아니라고 생각한다.
그렇다면 mock 을 사용하지 않고 어떻게 랜덤값을 테스트 할수 있을까?

테스트 하기 힘든 코드

랜덤 숫자에 따라 자동차를 전진 시키는 코드가 있다.

moveForward 메소드를 테스트하려면 매번 변경되는 랜덤값으로 인해 테스트에 성공하기도 하고, 실패하기도 한다.

테스트가 가능한 코드

랜덤값 뿐만 아니라 테스트 하기 힘든 코드를 테스트가 가능한 코드로 변경하는 핵심은 다형성의존성 주입이다.

NumberGenerator 인터페이스를 통해 RandomNumberGenerator 를 구현한다.

인터페이스를 구현하여 RandomNumberGenerator 타입뿐만 아니라 NumberGenerator 타입 또한 사용할 수 있게 된다.
Car 클래스는 위에서 생성한 NumberGenerator 를 주입받아 사용하기만 하면 된다.

이로써 랜덤값을 테스트 할수 있게 되었다.

테스트

Car 인스턴스를 생성할 때 NumberGenerator 를 구현하여 주입해주면 된다.

getter와 setter를 지양하자

setter를 지양하라는 말은 많이 들어봤다. 그런데 getter는 왜 지양해야하는지 의문이 들었다.

잘못된 getter의 사용 예

getter를 무분별하게 사용하면 무슨 문제가 있을까?

  1. 캡슐화의 의미 퇴색
  2. getter에 대한 의존성 증가

두가지로 적었지만 사실 캡슐화 하나의 문제라고 생각해도 된다.

이 코드의 문제는 무엇일까?
문제를 알아보기 위해 현재 자동차를 관리하는 ListHashMap 으로 변경해보자.

변경은 RacingGame 에서 일어났지만 GameController 까지 영향을 미치고 있는 것을 확인할 수 있다.

getter를 사용하지 않고 어떻게 할까?

getter와 setter를 지양하라는 키워드로 검색하다보면 “객체에 메시지를 전달하세요.” 라는 말을 자주 볼수 있다.
RacingGame 에게 자동차를 추가해줘라고 요청하는 것이다.

RacingGame 에게 자동차를 추가해달라는 요청을 함으로써 자동차를 관리하는 자료구조가 List 인지 HashMap 인지 Controller 는 아무 관련이 없어졌다.

그런데 getter를 써야 view에 출력을 할수 있는데?

객체에 메시지를 전달해라? OK. 그런데 view에 출력하려면 getter 없이 어떻게 해? 이 부분이 가장 큰 고민이었다.
‘getter를 무조건 쓰면 안돼!’ 라는 생각에 빠져있었는데 이것은 틀렸다.
비즈니스 로직에 getter를 쓰지 말라는 것이 내가 내린 결론이다.
그렇다면 view에 사용될 getter는 그냥 열어두면 되는걸까?

getResult() 를 통해 가져온 List<Car> 를 view에서만 사용한다고 보장할 수 없다.
누군가 개발을하다 getResult() 를 통해 가져온 List 에 자동차를 추가하거나 삭제하는 등 변경이 가능하다.
이는 컬렉션을 읽기 전용으로 만들거나 참조를 끊어 해결할 수 있다.

  • 읽기 전용

Collections.unmodifiableList 를 사용하여 읽기전용 컬렉션으로 반환한다.
완벽한 읽기 전용이 아닌 원본 리스트가 변경되면 같이 변하는 성질을 가지고 있다.
자세한 내용은 따로 검색해보자.

  • 새로운 객체 생성

새로운 List<Car> 를 생성하여 원본과의 참조를 완전히 끊을 수 있다.
하지만 view에 출력할 용도로 생성하는 것인데 RandomNumberGenerator 와 같은 불필요한 의존성을 주입해주어야 한다.

  • DTO 사용

계층간 데이터 전달만을 목적으로 하는 DTO로 변환하여 전달한다.
많은 고민 끝에 미션에서 DTO를 사용하는 방법을 선택했다.

--

--

Handwoong
self-retrospect
0 Followers
Editor for

Backend Developer (Java, Spring)