우아한 테크코스의 레벨1이 본격적으로 시작되면서 첫 미션인 자동차 경주를 페어 프로그래밍으로 진행하게 되었다. 온보딩 미션인 자동차 경주에서는 단위 테스트를 학습하는 것을 주요 목표로 삼았고, 미션 진행 과정은 다음과 같이 2단계로 나뉘어져 있었다.
- 미션 진행 및 코드 리뷰
- 1단계 - 자동차 경주 (페어 프로그래밍)
- 2단계 - 자동차 경주 리팩터링
나는 테바와 페어가 되어 함께 1단계 자동차 경주 미션을 구현하게 되었다. 그리고 수달의 리뷰를 통해 코드를 리팩토링해보았다.
페어 프로그래밍에서 다룬 내용들
자동차 경주 미션을 수행하면서 사소한 코드부터 큰 범위의 로직까지 많은 내용을 다뤘다. 그 중에서 의문으로 남았던 몇 가지 큰 주제들에 대해서 정리해보려 한다.
RandomNumberGenerator 테스트하기
이 부분에 대한 건 내용이 많이 길어져서 별도의 게시글로 정리하였다.
문제를 해결하는 인사이트를 준 레디, 짱수, 커비, 백호 감사합니다 😊
2024.02.22 - [우아한테크코스/레벨1] - Random 기능이 포함된 메서드를 어떻게 테스트할 수 있을까? (feat. 전략 패턴)
테스트 코드를 작성하는 범위
Cars와 Car는 별도의 객체이다. 따라서 각자 테스트를 작성하는 것이 마땅한데, 나는 Cars의 move() 함수의 테스트에 대해 많이 고민하였다.
public void move() {
for (Car car : cars) {
car.move();
}
Cars의 move()는 이 코드가 사실 상 전부이다. 따라서 Car의 move() 함수는 테스트할 필요가 없다.
그래도 테스트해야하는 것 아닌가요?
물론 테스트하면 좋겠지만, 이를 테스트해서 사용되는 에너지를 아껴 더 가치있고 우선순위가 높은 것에 투자하는 것도 좋은 자세가 될 수 있다. 그래서 나는 당연한 것을 테스트하기 보다 이를 더 가치 있는 기능을 구현하거나 리팩토링 하는 것에 사용하는 것이 좋다고 생각한다.
View와 Model의 데이터 교환 시 DTO 사용의 필요성
처음에 컨트롤러에서 뷰를 호출할 때 필요한 정보들을 Cars라는 객체를 그대로 참조하여 넘겨주었다.
그러나 이런 설계에 대해서 수달이 지적해주었고, 변경 가능성 방지를 위해 DTO를 생성하여 넘기는 것으로 결정하였다.
DTO를 왜 생성할 필요가 있는 지 다시 생각해보자.
MVC 패턴 기반으로 리팩터링해 view 패키지의 객체가 domain 패키지 객체에 의존할 수 있지만, domain 패키지의 객체는 view 패키지 객체에 의존하지 않도록 구현한다.
A가 B에 의존한다는 것은 A는 B의 책임을 가지지 않으며, A에서 사용되는 값이 B에게서 전달된 값이라는 것이다. 그래서 위에서 설명한 내용을 아래 처럼 정리할 수 있다.
- View 패키지가 Domain 객체에 의존할 수 없다 ⇒ View에서 사용되는 값은 Model에서 전달된 값이다.
- Domain 패키지의 객체는 View 패키지 객체에 의존할 수 없다. ⇒ Model에서 사용되는 값은 View에서 전달된 값일 수 없다.
즉, MVC 패턴에서는 Controller가 Model에 대한 값을 View로 넘겨주고, View는 사용자마다 다른 생애주기를 가진 데이터만을 받아와야한다. 쉽게 말해서 동적인 데이터는 Model이, 정적인 데이터는 View가 갖는다고 표현할 수 있다.
그래서 뷰에서는 도메인 객체에 포함된 정보를 참조해야한다. 그러나 리뷰어 수달이 설명해준 것처럼, 민감한 도메인 비즈니스 기능이 뷰 클래스에 노출될 수 있기 때문에 강한 의존성을 제거할 필요도 있는 것이다. 이를 DTO를 통해서 구현해주는 것이며, 대규모 프로젝트일 수록 DTO의 중요성은 커진다.
정적 팩토리 메서드의 필요성
정적 팩토리 메서드는 객체를 생성하는 역할을 하는 메서드이다.
이펙티브 자바에서는 생성자 대신 정적 팩토리 메서드를 고려하라! 라는 말을 하는데, 이름을 가질 수 있고, 생성자의 접근 제한자를 private 로 막아서 무분별한 객체 생성을 제한할 수 있다는 장점이 있다. 그 외에도 객체 생성의 캡슐화와 DTO 변환의 기능을 맡을 수 있다.
https://tecoble.techcourse.co.kr/post/2020-05-26-static-factory-method/
그러나 내가 사용한 것과 같이 의미없는 정적 팩토리 메서드의 사용은 지양해야 하며, 주로 형변환이나 여러 번의 객체 생성을 수행하는 경우 정적 팩토리 메서드를 사용해 볼 수 있겠다.
final를 사용하는 것의 의미
변수에 사용했을 때, final은 한번 값을 저장하고 다시 변경하지 않을 때 사용할 수 있다.
메소드에 사용했을 때, 상속한 후 메소드를 오버라이딩하지 못하게 하기 위해 사용한다.
클래스에 사용했을 때, 상속을 막기 위해 사용한다.
참고 : https://mangkyu.tistory.com/131
Static 메소드는 언제 사용할 수 있을까?
정적 메서드를 사용하는 이유는 인스턴스 생성 없이 바로 호출이 가능하기 때문이다.
정적이라는 것은 클래스가 메모리에 올라갈 때 메서드가 자동으로 생성되는 것이다.
따라서 메서드는 변화되지 않음을 내포하고 있고, 메서드는 인스턴스 변수를 사용하지 못한다.
일반적으로 final로 선언된 유틸성 클래스에서 Static 메서드를 많이 사용하는데, 이 메서드는 오버라이딩 될 수 없다.
1. 변화를 가정하지 않는다.
2. 메소드가 인스턴스 변수를 사용하지 않는다.
3. 인스턴스 생성에 의존하지 않는다.
4. 메소드가 공유되고 있다면, 정적 메소드로 추출해낼 수 있다.
5. 메소드가 변화되지 않고, 오버라이딩 되지 않는다.
출처: https://dev-coco.tistory.com/175
[슬기로운 개발생활:티스토리]
이번 미션에서는 단위 테스트를 위주로 학습하며 구현해보았다.
특히나 전략 패턴을 사용해서 테스트하기 어려운 코드를 최대한 분리해내는 것을 깊게 배우게 되었으며, final이나 static과 같은 사소한 코드 사용에 대한 기준을 마련하게 되는 계기가 되었다.
'우아한테크코스 > 레벨1' 카테고리의 다른 글
[회고] 우아한테크코스 6기 백엔드 레벨1 3주차 회고 (0) | 2024.03.03 |
---|---|
[TDD] 1단계 `사다리 생성 미션` 페어 프로그래밍 & 코드 리뷰 회고 (4) | 2024.03.03 |
[회고] 우아한테크코스 6기 백엔드 레벨1 2주차 회고 (0) | 2024.02.25 |
Random 기능이 포함된 메서드를 어떻게 테스트할 수 있을까? (feat. 전략 패턴) (0) | 2024.02.22 |
[회고] 우아한테크코스 6기 백엔드 레벨1 1주차 회고 (4) | 2024.02.19 |