구현하면서 가장 많이 고민했었던 세 가지를 중심으로 써봤다.
최전선에서 입력값을 받아 바로 검증을 하는 게 단순하고 여러 로직을 거칠 필요가 없어 효율적이라고 생각했다. FormatUtil을 만들고 입력값을 도메인 객체 생성에 필요한 값으로 변환하는 메서드를 만들었다. 이를 통해 View에서 유효성 검증을 할 때와 도메인 객체를 생성할 때 중복을 피하고 의도한 대로 View에서 모든 검증을 하고 도메인에서는 예외 발생 코드가 없는 깔끔한 로직 구현을 할 수 있었다. 하지만 예외 케이스가 늘어날 때마다 동시에 View가 점점 커졌다. 그래서 하나의 페이지마다 클래스를 생성해서 나눠봤지만 여러 개의 입력값을 동시에 받는 페이지에서는 의미가 없었다.
도메인 객체들을 일급컬렉션으로 만들고 원시값을 포장해서 스스로 검증할 수 있도록 만들어보자! View가 굉장히 깔끔해졌다. 동시에 도메인 객체들이,,, 그래도 객체들을 잘 나누면 깔끔하게 될 줄 알았지만 실패.
결국 View, 도메인객체에서 모두 검증을 해줬다. 물론 같은 검증은 아니고 따로 양식을 변환할 필요 없는 값들(빈값, 타입체크)은 View에서 해줬고 나머지는 도메인 객체에서 했다.
처음 View에서 모든 유효성 검증하려고 했던 이유가 이것 때문이었다. 검증과 동시에 예외 처리를 쉽게 하기 위해서! 하지만 View에서 모든 검증을 하긴 어렵다는 걸 깨닫고 도메인 객체가 던진 예외를 어디서 처리할 것인지 고민하다가 사용자 요청과 컨트롤러를 연결하고 있는 main메서드에서 해줬다.
처음에는 main 메소드에서 컨트롤러와 뷰를 맵핑 시켜줬는데 길어진 코드를 보면서 main메소드의 역할을 다시 한번 생각해봤다. main메소드는 엔트리 포인트 역할만을 한다고 생각하고 adapter라는 새로운 객체를 만들어 맵핑과 도메인객체에서 던진 예외를 처리하는 역할을 위임했다.
(만약 사용자가 화면을 선택하는 기능이 있다면 선택 입력값과 맵핑해주는 로직을 가지는 열거타입을 만들어 구현하면 깔끔하겠다는 생각이 들었다. 다음에 적용해보기로)
반환되는 동전이 최소한이 되는 자판기를 구현한다.
IllegalArgumentException
를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 해당 부분부터 다시 입력을 받는다.