[우아한 테크 코스 5기] 레벨1 - 사다리 게임 미션을 통해 배운 점
사다리 게임 회고록
- 1. 원시값 포장 (책임 분리)
- 2. 유효성 검증의 분류 (Domain과 View)
- 3. 컨트롤러와 도메인간의 적절한 데이터 전달
- 4. 테스트를 할 만한 로직의 구별
- 5. Null Pointer Exception 방지
개인적인 질문사항은 메일로 주시면 답변드리겠습니다😄
email : tjdtls690@gmail.com
일단 이번 사다리 게임 이전에 자동차 경주 구현 미션이 있었지만 시간이 너무 없어서 글을 작성하지 못했다.
이번 미션에 대한 글을 먼저 정리한 후 이후에 이전 미션에 대한 글을 정리해보려 한다.
수많은 피드백과 그에 대한 토론이 있었지만, 인상 깊었던 부분들을 골라 정리해보자.
1. 원시값 포장 (책임 분리)
일급 콜렉션인 GameResults 에선 여러개의 String(GameResult)를 갖고 있다. 처음에 구현할 땐, 기능적으로만 생각했기 때문에 여러 GameResult 전체를 관리하는 일급콜렉션인 GameResults만 기능이 존재하고, 각각의 GameResult 는 딱히 가지고 있을 기능이 없을 것으로 여겼다.
그래서 위 피드백에대한 나의 답변처럼 오버엔지니어링이 될 수 있겠다는 생각에, 굳이 각각의 String 을 GameResult 클래스로 포장하지 않았었다.
하지만 ‘유효성 검증 또한 비즈니스 로직 중 하나라는 것을 간과’ 했다. 그래서 더 작은 단위의 유효성 검증 책임을 나누어 줄 수 있다는 점에서, String 이라는 원시값을 포장할 근거가 충분하다 생각하고 클래스 분리를 했다.
2. 유효성 검증의 분류 (Domain과 View)
유효성 검증은 어떤 클래스에 맡기는 것이 적절할까??
이번에 피드백을 받으며 다시한번 유효성 검증의 책임에 대해 공부해보며 정립하는 계기가 되었다. 유효성 검증의 종류는 크게 2가지로 분류할 수 있다. View와 Domain이다.
- Domain : 요구사항에 기재되어있는 명확한 제한 사항
- View : Domain 유효성 검증 종류 외에, 사용자가 실수로 잘못 쳤을 경우의 예외 사항
만약 요구사항에 있는 비즈니스 로직과 관련된 검증 즉, 길이 검증같은 것이 view에서만 해주게 되면 view가 콘솔에서 다른 것으로 변경될 때 검증 자체가 사라지게 된다. 혹은 사용자가 입력했을 때 입력 값 자체가 잘못된 경우의 유효성 검증을 도메인에서 해주게 된다면, 해당 도메인 객체와 전혀 상관이 없는 로직이 뒤섞이게 된다.
3. 컨트롤러와 도메인간의 적절한 데이터 전달
이 부분은 컨트롤러에서의 도메인 객체 메서드의 호출을 줄이려고 해서 그랬다. 미리 정제된 값을 전달하려면 컨트롤러에서 각 도메인이 협력하여 정제를 시키는 로직을 넣어야하는데, 컨트롤러의 역할에 맞는 것인가?? 하는 생각이 들었다.
내 개인적인 컨트롤러의 역할에 대한 생각은, ‘View와 Domain 간의 중개자 역할’ 이라고 생각하기 때문이다.
그래서 최대한 입력받은 값은 그대로 도메인 객체에 넘겨주는 식으로 구현하려고 했던 것 같다. 한편으론, 리뷰어님 의견을 보고 ‘입력받은 값을 split만 해서 값을 정제하는 로직’ 도 하나의 비즈니스 로직으로 보고 컨트롤러에서의 사용을 꼭 절제해야하는가?? 에 대한 의문이 남는 것 같다.
4. 테스트를 할 만한 로직의 구별
사실 여기서 말하는 테스트를 한 비즈니스 로직은 이렇다.
public boolean isExistBar(){
return this.isExistBar;
}
사실 로직 자체는 getter와 완전이 같다고 생각한다. 하지만 그 쓰임새가 getter보단 해당 Bar가 존재하는지 안하는지 확인하는 비즈니스 로직의 성격에 훨씬 가깝다고 생각한다. 그래서 테스트를 추가하긴 했는데, 리뷰어님 의견을 보니 좀 더 고민이 되었다.
getter 메서드 명 말고 이러한 메서드명을 부여해 준 의도는 사실 ‘Bar라는 클래스 안에 어떤 값이 필드로 들어있는지’ 와 ‘어떤 과정을 통해서 Bar가 들어있는지 없는지를 확인하는지’ 를 숨길 수 있다고 생각했다.
만약 getter 로 메서드명을 작성했다면, 해당 객체의 필드가 무엇인지가 드러나게 된다고 느꼈다. 그렇기에 어찌보면 말장난처럼 보일 순 있지만, 메서드명으로 getter가 아닌 비즈니스 로직임을 나타내고, 핵심 비즈니스 로직으로 취급하면서 테스트까지 추가해줬던 것 같다.
이런식으로 답변을 한 후, 이후에 리뷰어님 피드백이 또 왔었다. 여기서 느꼈던 점은 ‘역시 개발에 정답은 없다’ 였다. 해당 로직이 얼마나 중요한 비즈니스 로직인지, 후에 어떤 특정한 로직이 포함될 수 있는 로직인지 에 따라 테스트를 만들어줘도 괜찮다는 것으로 결론이 났다.
5. Null Pointer Exception 방지
이 부분은 사실 좀 충격 먹었었다. 굉장히 심플한 부분이지만 지금까지 생각지도 못했던 부분이기도 하다. 메서드를 호출하는 주체를 Null 이 확실하게 아닌 문자열로 바꾸는 것만으로 Null Pointer Exception을 방지할 수 있다는 사실에 감격한다…