TDD - 테스트 주도 개발
3주차에서 테스트 주도 개발을 시도하였으나 실패하였다. 로또 프로젝트를 완성하고 난 후 살펴보면 충분히 테스트 주도 개발을 할 수 있을 것만 같은데 시작 단계에서는 왜이리 막막한 건지 원인을 생각해보니 설계의 문제인 것 같았다.
프로젝트 시작 전 기능 구현 목록을 정리하는 시간을 매번 가지고 있었는데, 절차 지향적으로 기능을 생각하다 보니 TDD가 더욱 어렵게 느껴졌던 것으로 판단하여 이번에는 가장 작은 단위의 클래스는 어떤 것이 있는지, 그 클래스에는 어떤 기능이 있어야 하는지, 객체 단위로 설계를 해보는 시간을 가졌다.
가장 작은 단위에 클래스와 그 안에 어떤 기능이 있으면 좋겠다 라는 설계를 한 뒤 진행을 해보니, 한결 수월하였다. 성공적으로 프로젝트가 진행될 줄 알았으나, 그 생각이 무색하게 곧이어 두번째 위기가 닥치게 되었다. 익숙하지 않은 TDD 방법으로 진행하다 보니 무지에서 오는 두려움이 엄습한 것이었다. 내가 원래 코딩하던 방식은 절차지향적으로 코드를 작성하고 프로젝트가 돌아가도록 완성한 다음 역할과 책임을 기능별로 분리하는 방법을 진행하는 것이었다. 기존에는 프로젝트를 일단 완성하였다는 안정감이 있었고 기능 분리가 실패하더라도 언제든지 돌아갈 수 있다는 생각에 편하게 코딩을 할 수 있었다면, TDD로 진행할 때는 마지막에 프로젝트를 완성할 수 있기 때문에 시간안에 잘 동작하는 프로젝트를 만들 수 있을까? 라는 불안감이 엄습하기 시작하였다. 그러나 도전하지 않으면 성공도 없는 법, 완벽하다고는 할 수 없지만 할 수 있다는 생각 하나로 계속 진행하다 보니 어느덧 프로젝트를 완성할 수 있었고, 불안했기에 성취감을 두배로 더 얻을 수 있었다.
테스트 주도 개발이 좋은 것일까?
테스트 주도 개발이 주는 장단점은 명확한 것 같다.
1. 코드 품질 향상
테스트 코드를 작성하기 때문에 개발자가 생각할 수 있는 예외라면 안전하게 방어 코딩을 할 수 있다는 것이다. 또 코드는 계속해서 변경되는데, 이때도 이 예외 사항을 잘 처리하고 있는지, 문제가 될 부분은 없는지 확인하고 심리적으로 안정감을 얻을 수 있다는 것은 큰 장점으로 다가오는 것 같다. 실제로 이번 프로젝트에서도 코드를 수정할 때마다 테스트 코드를 동작시켜 본 후 녹색 불을 보면서 흐뭇함을 느낄때가 많았던 것 같다.
2. 협업
일반적으로 업무를 진행할 때 다른사람의 코드를 수정할 일이 많은데, 이 때 더 빛을 볼 수있을 것 같다. 테스트 코드는 어쩌면 코드를 사용하는 방법에 대한 기록이라고도 볼 수 있다. 또 코드를 어떻게 사용하는지에 대해 알려줄 뿐만 아니라, 어떤 예외까지 생각하면서 처리하였는지에 대한 기록으로도 볼 수 있기 때문에 협업을 한 층 더 용이하게 만들어 줄 수 있을 것 같다.
많은 장점에도 불구하고 앞으로 모든 코드를 테스트 주도개발로 할 것이냐고 묻는다면 조금 망설이게 될 것 같다. 왜냐하면 테스트 주도 개발이 주는 단점도 명확하였기 때문이다.
1. 불완전한 설계, 설계의 어려움
프로젝트 초기 단계에서 아무리 열심히 설계한다고 해도 구현 단계에서 변하는 점이 많을 것 같다는 느낌을 지울수가 없었다. 내가 아직 초보자라서 그런지 몰라도 이 작은 프로젝트를 진행하는데에도 많은 변화가 있었다. 회사에서는 많은 개발자가 한개의 프로젝트를 공통으로 진행할 것이고, 기획팀 등 여러 다른 팀과 협업을 진행할 것인데 이러한 TDD가 제대로 적용될 수 있을지 궁금하다.
2. 어려운 구조적 변경
앞선 내용과 비슷한 내용이긴 하다. 만약 설계가 틀어졌을 때 또는 코드를 수정해야할 때 테스트 코드도 같이 수정해줘야 하는 번거로움이 존재한다. 메서드가 하나 사라진다고 해도 모든 테스트 코드를 한 번씩 살펴줘야 하는 번거로움이 있었다. 테스트 코드가 늘어날 때마다 코드 하나 하나를 변경하는 시간이 늘어나는 것을 느낄 수 있었다.
장점도 명확하고, 단점도 명확하였으나 최종적으로 느낀 생각은 그래도 TDD가 좋다는 것이었다. 좋은 것과 별개로 실제로도 많은 곳에서 TDD로 개발을 진행하는지 너무 너무 궁금하다.
getter를 사용하는 대신 객체에 메시지를 보내자
처음에는 메시지를 보내자는 의미가 와닿지 않았다. 살펴보고 살펴보니 메시지를 보내자라는 의미는 객체를 객체답게 사용하자는 의미였다. 객체의 값을 꺼내서 사용하지 말고, 객체내부에서 일을 할 수 있도록 여건을 만들어주자 라고 이해하였다. 왜 이렇게 하는 것이 좋을까? 라고 생각을 하였지만 이는 '디미터 법칙을 위반한 코드 예시'를 살펴본 후 금방 수긍할 수 있었다.
이를 바탕으로 하여 getter를 사용하는 코드 일부분을 수정해 보는 시간을 가져 보았다. 아래는 사람들의 주문 내역에서 평일 할인 내역을 계산하는 코드 일부분이다. Order 클래스의 calWeekDayDiscountPrice 메서드를 살펴보면 orderMenu에 있는 count를 직접 가지고 와서 계산하는 로직이 존재한다.
public class Order {
private final List<OrderMenu> orderMenus;
...
public Integer calWeekDayDiscountPrice(Day day) {
int sum = 0;
for (OrderMenu orderMenu : orderMenus) {
if (day.isWeekday()) {
sum += DAY_DISCOUNT_PRICE * orderMenu.getCount();
}
}
return sum;
}
}
public class OrderMenu {
private final Menu menu;
private final Integer count;
private final String koreanMenuName;
...
public Integer getCount() {
return count;
}
}
getter를 사용하는 대신에 OrderMenu 클래스에게 "주간 할인 금액을 계산해줘" 라는 메세지를 보내는 형태로 변경해 보았다. 메세지를 보내는 형태로 변경을 하였더니 덤으로 indent도 줄어드는 것을 확인할 수 있었다. 아무래도 메세지를 보내는 형태로 변경하는 것이 곧 역할과 책임을 분리하는 것이기 때문에 이러한 효과를 같이 얻을 수 있었던 것 같다.
public class Order {
private final List<OrderMenu> orderMenus;
...
public Integer calWeekDayDiscountPrice(Day day) {
return orderMenus.stream()
.mapToInt(orderMenu -> orderMenu.weekDayDiscountPrice(day))
.sum();
}
}
public class OrderMenu {
private final Menu menu;
private final Integer count;
private final String koreanMenuName;
...
public int weekDayDiscountPrice(Day day) {
if (menu.isWeekDayDiscount(day)) {
return DAY_DISCOUNT_PRICE * count;
}
return ZERO_PRICE;
}
}
연관성이 있는 상수는 static final 대신 enum을 활용.
enum이 있다는 것은 알고 있었지만 자주 사용하지는 않았다. 이번 3주차 피드백에서는 static final 대신 enum을 활용하는 것을 추천하고 있었기에 enum을 적극적으로 활용해보는 시도를 해보았다.
이번 프로젝트에서는 두 곳에서 enum을 활용해보았다. enum 각각의 조건을 apply 메서드에 명시를 해주고 reward 메서드를 통해 배지를 획득하는 방식으로 구현해보았다. 연관성이 있는 상수를 묶을 뿐만 아니라 각각의 조건까지 같이 명시해 줄 수 있어서 더욱 만족스러운 코드가 아니었나 생각이 든다. 만들고 나서 아주 흡족했던 결과물 중에 하나였던 것 같다.
프리코스를 진행한지 벌써 4주라는 시간이 흘렀다. 4주라는 시간은 절대 짧은 시간이 아니다. 각각의 프로젝트를 되돌아 보면 구현을 하는데 있어서 그리 어렵지도 않은 프로젝트인데, 어떻게 하면 더 좋은 구조를 가질 수 있을까, 어떻게 하면 우테코에서 준 피드백을 적용할 수 있을까?, 남들은 코드를 어떻게 작성했을까? 살펴보다 보니 4주라는 시간이 눈 깜짝할 새 지나간 것 같다.
프로젝트를 완성할 때마다 "와 진짜 잘한 것 같다" 라고 생각하였지만 남들이 작성한 코드를 살펴볼 때마다 작아지는 느낌도 든 적이 있었다. 그러나 분명한 건 일주일이 지날 때 마다 조금씩 더 성장하는 것을 느낄 수 있었으며, 모두 제각각의 발전 속도가 있기에 중요한 건 남들을 의식하지 않고 나의 템포에 맞게 계속해서 앞으로 나가는 것이라고 생각한다. 우테코를 통해 짧지만 좋은 경험을 할 수 있었던 것 같다. 좋은 사람들과 좋은 경험을 나눌 수 있는 기회를 주셔서 너무 행복했다. 앞으로도 꾸준히 공부하여 발전하는 사람이 되도록 해봐야겠다.