우아한 테크 캠프 PRO 2기 - 1주차 로또 TDD 후기

2021. 5. 27. 16:05우아한테크캠프PRO

1주차 로또 TDD 후기

1주차가 완료되었다. 다행히 일정대로 미션수행을 완료하였고 생각보다 정말 쉽지 않다는 걸 깨닫았다.

1주차에는 그냥 간단한 로또 프로그램을 개발하는 것이다. 요구사항에 대해 간략히 요약해보자면,

  • 자동 로또 번호가 생성기능, 수동 생성 기능, 보너스 볼 기능
  • 사용자는 콘솔을 이용하여 로또 구매 가격, 로또 수동 구매 개수, 수동 구매 로또 번호, 보너스 볼 등 입력받는다
  • 입력받은 정보를 이용하여 사용자의 로또 담청 보상금을 계산하여 결과를 콘솔로 보여준다.

 

어떻게 보면 정말 간단한 프로그램이다. 기능 구현은 누구든지 할 수 있다.

하지만 이 교육은 기능 구현이 목적이 아니다. 이 미션을 수행할 동안, 기능 요구사항이 아닌, 프로그래밍 요구사항이 주어진다. 예를들어 클린코드를 위한 메소드 분리, 인덴트 뎁스 제한하기, TDD로 개발하기, 일급컬렉션, 원시값 포장 등 요구사항에 맞춰 개발되야하며, 총 5단계로 나눠 코드 리뷰가 진행되고 피드백을 다시 반영해야한다. 그 과정에서 정말 많이 배운다.

이 경험은 정말 돈 주고도 어디서 배울수 없는 경험이다. 어떤 좋은 회사를 가더라도 이런 경험을 쉽게 할 수 없을 것이다.

 

1주차 로또 TDD 저장소 Github: https://github.com/ybh89/java-lotto/tree/ybh89

 

1주차를 진행하며 직접 경험했던 것들 중에 기억에 남는 것들을 정리했다.

  • 클린코드
  • 테스트가 쉬운 코드
  • 도메인 중심 설계

1. 클린코드

메소드 코드라인 길이 제한하기(15줄 이하)

메소드 코드라인 길이를 줄이기 위해서는 메소드가 담당하는 역할(책임)을 줄여야한다. 메소드 길이가 15줄 이상이되면 이 메소드가 담당하는 역할이 많지는 않은지 의심을 해봐야한다. 그리고 신기하게도 1개의 역할을 담당하는 메소드는 대부분, 거의, 무조건 15줄이 넘어가지 않는다.

Indent depth 줄이기(1 depth만 허용)

예를들어 while문 안에 if문이 들어가면 이건 2 depth 이다.

뎁스를 줄이기 위해서는 위 내용과 마찬가지로 메소드 분리를 해야한다.

정말 간혹 메소드 분리를 하면 가독성이 더 안좋아지는 경우가 있는데 (예를들어 for-if-return 패턴) 이런 경우 스트림을 적극 활용하자!

else 사용하지 않기

Early return 패턴을 사용하면 else를 사용하지 않아도 된다. 여기서 else는 eles if문을 포함하고, switch문도 포함한다.

2. 테스트가 쉬운 코드

테스트가 어려운 영역과 테스트가 가능한 영역을 분리하라

테스트가 어려운 영역은 최대한 상위 클래스가 의존하게 만들어 하위 클래스(도메인 영역)는 테스트가 쉬운 영역으로 만들어 준다. 그럼 일단, 테스트가 쉬운 도메인 영역의 테스트를 집중적으로 진행하면 된다.

테스트가 어려운 영역과 쉬운 영역이 분리가 되면 어려운 영역은 일단 테스트를 진행하지 말고 쉬운 영역을 테스트하는게 1차 목표이다.

다양한 생성자 활용

리팩토링이 진행되면서 객체 생성 코드가 변경되면 변경된 코드가 테스트에 영향을 주는 경우가 있다. 그럼 테스트 코드도 전부 변경해야할까? 이럴 때는 다양한 생성자를 허용하여 기존 테스트를 수정하지 말고, 새로 생성한 생성자 테스트만 진행할 수 있도록 해야한다.

TDD

테스트 코드를 먼저 작성하고 이에 맞는 비즈니스 로직을 작성하면서 필요에 따라 리팩토링을 진행하는 설계방법이다. 테스트 코드가 중심이 되기 때문에 테스트가 어려워 질 수 없다.

3. 도메인 중심 설계

리팩토링 과정에서 도메인의 역할이 나눠지면 나눠질수록 도메인이 많아지는 것을 볼 수 있었다.

원시값은 포장해라

int, String과 같은 원시값은 객체로 포장해야한다. 미션중 로또 번호의 경우에 Lotto라는 객체의 int 멤버변수로 사용할 수도 있지만, int가 아닌 LottoNumber와 같이 객체를 포장하게 되면, 해당 값에 대한 유효성 체크, 캐시관리, 상수관리 등을 LottoNumber에 위임할 수 있다.

일급 컬렉션

원시값 포장과 같은 원리이다. 이번엔 컬렉션을 포장하는 것이다. 장점 또한 원시값 포장과 같다. 다만, 일급 컬렉션을 만들었다면 일급 컬렉션을 사용하는 곳에서 값(컬렉션)을 꺼내려고하지 말고(getter) 일급 컬렉션 객체에 메시지를 보내는 식으로 활용하는 것이 좋다.