티스토리 뷰
단위테스트와 TDD는 다르다.
단위테스트는 프로덕션 코드에 대한 테스트코드를 작성하는 것이라면,
TDD는 실패하는 컴파일 되는 테스트코드를 기반으로 프로덕션 코드를 작성해 나가는 것을 의미한다.
레거시 코드 TDD로 리팩토링하기
단위가 큰 프로젝트일수록 TDD를 진행하기가 어렵다. 특히, 리팩토링을 하거나 새로운 기능을 추가하게 되는 경우가 많은데 이럴 경우 프로덕션 코드 하나에 따른 다수의 테스트코드 수정이 발생할 수 있다.
✨점진적 리팩토링 - 오버로딩
: 컴파일이 가능하게 기존 메소드를 유지한 채, 시그니처가 다른 수정 메소드를 하나 더 만든다. (메소드 오버로딩)
생성자나 변수의 경우에도 마찬가지이다. 컴파일이 가능하게 중복을 유지한 채로, 점진적인 수정을 진행한다. 리팩토링을 하면서 중간에 배포될 수도 있고, 기존 상황으로 되돌아가야할 수도 있다. 내가 생각할 땐, 어느시점에서든 ✨컴파일 되는 상황을 유지하는 것이 중요하다고 생각한다. (돌아가는 시스템이 가장 우선된다.)
컴파일되는 상황을 유지한 채(중복되는 상태인 과도기적 상태를 유지), 점진적으로 리팩토링하고, 테스트코드를 유지해나가는 연습이 필요하다. 이 경우에도 TDD의 원칙은 유지한채 작성해나갈 수 있다.
Getter를 지양하라 - 객체값으로 비교
생성자가 setting의 역할을 하기 때문에 불변객체가 되기위해 setter는 지양된다. 더불어, getter도 가능한 지양하도록 한다. equals, hashcode로 객체비교를 진행해야 한다. 하지만, 원시값을 포장하였는데 view에서 그 내용 값을 보여줘야 한다면 getter를 사용할 수 밖에 없지 않을까 하는 생각도 든다.
Cache - 적절한 자료구조✨를 생각하자!
Getter를 사용하지 않는다면 배열로 캐싱을 하여 사용할 때, 해당 인덱스에 내가 원하는 객체가 있는지 어떻게 비교하지? 고민이 많이 되었다. 그렇다면 더 적합한 자료구조가 있는지 생각해보자!
public class LottoNumber {
public static final int MINIMUM_NUMBER = 1;
public static final int MAXIMUM_NUMBER = 45;
private static final LottoNumber[] cache = new LottoNumber[MAXIMUM_NUMBER];
private final int number;
static {
for (int i = 0; i < MAXIMUM_NUMBER; i++) {
cache[i] = new LottoNumber(i + MINIMUM_NUMBER);
}
}
private LottoNumber(int number) {
validateNumberRange(number);
this.number = number;
}
public static LottoNumber valueOf(int i) {
if (i <= MAXIMUM_NUMBER && i >= MINIMUM_NUMBER) {
return LottoNumber.cache[i - MINIMUM_NUMBER];
}
return new LottoNumber(i);
}
//...
}
Map은 캐싱을 할 때 많이 사용된다고 한다. Map<Integer, LottoNumber> cache 로 만든다면 인덱스 실수가 발생하지 않는다. 제대로 들어있는지 의심점이 적어진다. 뭔가 잘 안 풀린다면 적절한 자료구조를 사용하고 있는지 다시 생각해보자! 😀
public class LottoNumber {
public static final int MINIMUM_NUMBER = 1;
public static final int MAXIMUM_NUMBER = 45;
private static final Map<Integer, LottoNumber> cache = new HashMap<>(MAXIMUM_NUMBER);
private final int number;
static {
for (int i = MINIMUM_NUMBER; i <= MAXIMUM_NUMBER; i++) {
cache.put(i, new LottoNumber(i));
}
}
private LottoNumber(int number) {
validateNumberRange(number);
this.number = number;
}
public static LottoNumber valueOf(int i) {
if (i <= MAXIMUM_NUMBER && i >= MINIMUM_NUMBER) {
return cache.get(i);
}
return new LottoNumber(i);
}
//...
}
new 생성자로 호출되면 생성되는 것을 막을 수 없다.
위와 같이 valueOf를 사용하여 정적 팩토리 메소드를 구현하였다면 생성자는 닫아주는 것이 잘못된 생성을 방지할 수 있는 방안이 될 수 있다. 1~45 값 이외의 객체 생성을 막으려면 생성자를 막고, 범위 이외에서 exception을 발생시키면 된다.
public class LottoNumber {
//...
private static final LottoNumber[] cache = new LottoNumber[MAXIMUM_NUMBER];
private final int number;
static {
for (int i = 0; i < MAXIMUM_NUMBER; i++) {
cache[i] = new LottoNumber(i + MINIMUM_NUMBER);
}
}
private LottoNumber(int number) {
this.number = number;
}
public static LottoNumber valueOf(int i) {
if (i > MAXIMUM_NUMBER || i < MINIMUM_NUMBER) {
throw new CustomException("로또 넘버는 1~45 사이 정수이어야 합니다.");
}
return LottoNumber.cache[i - MINIMUM_NUMBER];
}
//...
}
'우아한테크코스 > 레벨1' 카테고리의 다른 글
[수업] 상속과 조합, 좋은 객체의 7가지 덕목, 시그니처, final (0) | 2021.03.05 |
---|---|
블랙잭 미션 학습로그 (0) | 2021.03.05 |
[수업] 가변인자, 매개변수 final 선언, Exception (0) | 2021.02.24 |
로또미션 학습로그 (0) | 2021.02.24 |
[수업] 지역변수 final 선언, equals 비교, 문자열 (0) | 2021.02.21 |
- Total
- Today
- Yesterday
- Transaction
- 네트워크
- 내부코드
- 우테코수업
- 우아한테크코스
- CS
- 개발공부일지
- TCP/IP
- 운영체제
- JS
- 객체지향
- JPA
- 학습로그
- 글쓰기미션
- OS
- 마스터즈코스
- 모의면접준비
- java
- javascript
- DB
- 알고리즘
- 인증
- 회고
- React
- python
- TIL
- 카카오
- Spring
- 월간회고
- 코드스쿼드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |