오늘도 날씨가 엄청 더웠다. 하지만 공부와 운동은 멈출수 없다.(멈추지는 않았다. 다만 늘어졌다.) 오늘의 목표는 사실 도메인 계층의 개발을 모두 마치고, PR을 작성해놓는 것이었다. 하지만 오늘 목표치는 끝까지 달성하지는 못하였다..
요즘에는 신경쓰이는 일이 많아 그런지, 개발 뿐만아니라 일상 속에서 자꾸 실수를 한다. 잠도 잘못자고.. 왜이러나 모르겠다. 내일 친구랑 같이 공부하면서 리프레시하고, 정신 다시 번쩍 차리자!!
Product 도메인 계층 개발
오늘의 목표는 Product 도메인 계층 개발을 모두 마치는 것이었다. 남은 부분은 Application 계층의 UpdateCommandHandler 와 TrackQueryHandler 의 구현만을 남겨놓은 상황이었기에, 충분히 가능할 것이라고 생각했었다.
UpdateCommand는 어렵지 않았다. 지난 Member 에서 경험해본 것과 크게 다르지 않다고 생각했고, 다르지 않았기 때문이다. 다만 이번에는 DTOs 에 대하여 입력 유효성 검사를 추가하면서, 이를 테스트하는 과정으로 인해 이전보다는 조금 귀찮은(하지만 반드시 필요한) 과정을 거쳤다.
나는 지난번에 개발하여 적용한 SelfValidating 클래스의 validateSelf() 를 아주 잘 사용하고 있다. 현재 내 프로젝트에서 DTO(및 다른 객체) 내에는 여러 프로퍼티가 존재하고, 이로 인해 빌더 패턴을 활용하고 있다. 뿐만아니라, 계층에 알맞는 데이터로 변환하기 위해 Mapper를 통해 변환하는 과정이 많이 존재하는데 이전에는 특정 프로퍼티를 누락할 경우, 해당 부분을 확인하는데 오래걸렸다면, 이제는 너무나도 간편하게 이를 찾을 수 있게 되었다.
이를 통해 이번 Product 개발 할 때, 지난 Member 개발 때의 실수로 인한 시간 낭비를 크게 줄일 수 있었다.(지난번과 같은 곳에서의 실수는 줄었지만, 각 변환하는 객체별로 프로퍼티가 다르다보니, 실수를 하게 되더라..) UpdateCommand 까지는 큰 어려움과 고민 없이 뚝딱뚝딱 재미나게 만들었다. 하지만 Track 을 만들기 시작하면서 고민이 시작되었다.
QueryService
나는 유스케이스를 Command로 & Query 로 구분하여 작업의 명확성을 높이고자 하였다. 그리고 유스케이스는 ApplicationService에서 구현하였다.
현재 읽고 있는 클린아키텍처 책을 공부하면서, QueryService 에 대한 아이디어를 얻게 되었다. 나는 유스케이스(각 Command 혹은 Query)를 한곳에서 관리하고 싶었다. 이것이 해당 도메인의 유스케이스를 한번에 파악할 수 있는 방법이 될 것이라 생각했기 때문이다.
개발을 진행하면서 최고 관심사(?)인 책임에 대한 생각을 하다보니, ApplicationService의 책임이 Command와 Query 두개를 담당한다는 사실을 알게되었다. 그리고 고민은 이때부터 시작하게 되었다.
가장 먼저, Query(조회) 기능이 그렇게 많을까? 지금 상황에선 그냥 해도 되지 않을까? 하는 생각이 솔직하게 제일 먼저 들었다. 이는 아주 사악하게 잘못된 생각이다. 유지보수성과 확장성을 고민하며 만들고 있는 이 프로젝트에서는 해서는 안되는 생각이었고, 바로 생각을 고쳐먹었다. ApplciationService 와 QueryService 분리하기로 결정하였다.
다음 각 Service에 대한 고민으로, 신규 기능이 추가될 때, 인터페이스에 해당 메서드를 추가하고, ApplicationImpl에서 구현해야하는게 맞는걸까? 하는 고민에 빠졌다. 이 고민은 QueryService를 만들 때 하게 되었는데, 더 정확하게는 새로 추가되는 메서드에 관하여 Command(Query)를 새롭게 만들어야 하는가? 그렇다면 각 Command(Query)Handler 는 또 새롭게 추가가 되어야하는가? 하는 고민까지 하게 되었다. 그리고 이 부분이 오늘 하루를 집어 삼켰다.
이에 대한 정답은 없겠지만, 내 결정은 각 Command(Query)를 분리하는 것으로 결정하였다. 다만, 필요하는 데이터가 다른 경우에만 이를 분리하는 것으로 결정하였다.
책을 보면서 보았던 구절이 이 결정에 도움을 주었다. 이 결정으로 인해 QueryService는 두 메서드로 나뉘게 되었다.
지금은 ProductCategory에 따른 검색만 존재하여, DTO를 좀 더 구체화(TrackProductWithCategoryQuery) 하여 만드는것이 좋을까? 하는 생각을 잠시 했었으나, 좀 더 큰 범위로 접근하여, 단일 객체를 반환하는가, 혹은 여렇객체를 반환하는가? 로 접근하여 TrackProductListQuery를 만들게 되었다.
좀 더 구체화한 방법으로 개발을 진행할 경우, 각 Handler 또한 추가되게 된다. 여기서 나는 중복이 발생할 수 있겠다는 생각이 들었고, 이를 고려하여 더 큰 범주의 접근을 하게 되었다. 결정은 이렇게 했지만, 고민이되는 것이 있다. 필요한 메서드만 존재하는 인터페이스를 만들어 Handler(혹은 QueryService) 에서 이를 구현하는 것이 맞는걸까? 하는 고민이 된다. 흔히 객체지향 원칙 중 하나인 인터페이스 분리 원칙인데, 나는 인터페이스를 이번에 처음 사용해본것이라그런지.. 어느것이 맞는것인지에 대한 고민을 많이 하고 결정을 잘 못내리는 것 같다. 그래서 지금의 선택을 하게 되었다.
지금 고민이되는 것들을 다른 개발자(동료라면 더 좋겠다..)와 이야기를 나누고 더 좋은 코드를 작성하고싶다. 그리고 프로젝트를 더 좋게 만들고 싶다. 이야기 주제로 이야기하기위해 내 생각을 잘 정리해둬야겠다.
'회고 > TIL' 카테고리의 다른 글
PR 피드백 반영, 편두통 (1) | 2023.07.06 |
---|---|
Product Domain 완료 (0) | 2023.07.04 |
ApplicationService(유스케이스) 구현과 고민 (7) | 2023.06.30 |
Product 도메인 계층 개발, 입력 유효성 검사, 테스트 (0) | 2023.06.29 |
클린아키텍처, 유스케이스 구현하기 (0) | 2023.06.28 |