작성
·
312
0
안녕하세요 강사님 강의 잘 듣고 있습니다
다름이 아니라 프로젝트 회의를 하던 와중에 다음과 같이 토론을 하게 되었는데 강사님 생각은 어떤지 궁금해 질문드립니다!
오늘 이야기를 하면서 장황하게 3~4시간 정도는 토론을 하였는데
내용은 다음과 같습니다.
1.
도메인 주도 설계 를 하는 것이 가장 옳은 길일까?
=> 페이지 별로 설계를 했을 때 너무나 불편한 점이 많았다. 페이지들 자체에서 공통적으로 필요한 컨트롤러들은 따로 빼서 공통으로 관리한다던지... 유지보수가 너무 어려웠던 것 같다. 아무래도 도메인 주도 설계가 맞다는 결론을 냈다.
2.
클라이언트와 서버의 DTO와 엔티티의 변환, 혹은 DTO와 DTO의 변환은 자주 이루어지는 것이 맞는 방법일까?
1번에서 도메인 주도 설계를 하는 것이 가장 유지 보수 및 코드 재사용성이 가장 뛰어날 것 같다는 결론을 내리고 나서 기존의 코드들을 보니 클라이언트 - 컨트롤러 통신에서 발생하는 DTO에 너무 의존하고 있다는 느낌을 가졌다.
예를 들자면)
기존 코드에서는 회원가입을 하는 api 가 있다고 가정을 하고 컨트롤러에서 요하는 DTO는 닉네임과 비밀번호를 받아드린다고 했을 때
Service계층에서 MemberService.save(RequestDTO) 형식으로 되어 있다 보니 컨트롤러 - 서비스 간의 통신이 1:1로 맞게 되는 (해당 컨트롤러에서만 이 save메서드를 사용하게 되는 문제점이 발생하게 되었다) 즉, 코드의 재사용률이 매우 떨어진다.
물론 여기서에서는 MemberService.save(Member)를 사용하면 되는 것 아니냐라는 결론이 도달하게 되었으나
프로젝트 로직중에 어떤 도메인을 저장해야하는데 도메인 저장시에 DTO에 주어진 값으로 연관되어있는 다른 도메인을 추가로 생성해야 할 때는 MemberService.save(Member)로 해결 할 수가 없고 서비스 계층으로 다른 도메인을 추가 할 수있게끔 추가적인 정보를 주어야 하는 상황에서는 도메인만 매개변수로 줄수가 없는데?
=> 그러면 컨트롤러에서 주는 DTO를 Service.save 매개변수에 직접 넣어야하는거야?
=> 그러면 또 1:1관계가 되어버리는데? ( 서비스가 컨트롤러에 너무 의존하게 되는데? )
이런 식으로 꼬리에 꼬리를 물게 되었다.
약간 이런 고정관념을 깨게 된게 기존에는 DTO가 그냥 클라이언트 - 컨트롤러 단에서 데이터 중복을 막기 위해서 사용하는 것인 줄만 알았는데 Controller - Service간의 통신이나 어떤 계층 간의 통신 모두 DTO를 적용시키는 경우도 많다는 이야기를 듣고 다시 생각 해보게 되었다.
=> 그래서 내린 결론이 1:1 관계를 깨버리기 위해서는 request의 DTO를 Service에 전달할 것이 아니라 추가적으로 Controller, Service간의 DTO를 추가적으로 결정하여서 더이상 Service가 Controller 측의 DTO에 의존하지 않게 만들게 하면 어떻겠느냐의 결론이 들었다.
=> 그런데 이제 DTO를 남발하게 될 경우에 Controller 쪽에서는 결국 클라이언트 요청에 대한 DTO를 Service에게 요청을 보낼 DTO로의 변환이 많아지게 되며 코드를 쉽게 알기 어렵다는 추가적인 고민이 발생 했다.
=> 그러면 매개변수가 3개 이하로 필요한 메서드에 대해서는 DTO를 만들지 말자는 결론이 났고 매개변수의 종류로는 도메인과 Primitive, Wrapper 타입만을 정의하고 다른 계층 통신에 사용되는 DTO는 절대 넣지 않는 것으로 결론이 났다.
3. 생성자가 남발되는 것에 대한 고민
DTO 마다 도메인을 건들이게 될 경우 수많은 생성자들이 생기게 된다. 기존 프로젝트는 그래서 진짜 도메인에 많게는 생성자가 5~6개는 있었습니다 보면 볼 수록 이게 맞나 싶었지만 그 때는 설계나 디자인 패턴 같은 것에 대해 알려줄 사람도 없고 일단 굴러가기만 하면 된다는 입장이여서 이게 맞나 싶은 것들은 다 넘어갔지만...
=> 빌더 패턴이라는 것을 알게 되었는데 지금처럼 생성자가 5~6개정도 될 경우에 더욱 깔끔해진 코드를 볼 수 있게 된다. 특히나 현재로써는 롬복에 @Builder를 지원하니 사실상 표면적으로 드러나는 생성자가 없다고 생각해도 무방하다.
후에 빌더 패턴에 대해서 다룰 예정이다.
4. repository에서 조회시에 어쩔 수 없이 DTO를 반환하게 되는 경우
respository계층에서 fetch join으로 모든걸 해결 할 수는 없으니 DTO로 반환하는 이슈가 있다. repository에서는 가능한 도메인 객체로 반환을 해야하는 것이 옳다고는 생각하는데 이 경우는 특히나 대처하기가 어려운것 같다.
=> 분명히 이런 DTO로 반환의 경우에는 조회 로직이 대다수 일텐데 그럴 경우에는 그냥 Controller에서 repository를 바로 참조해도 되는 거 아닐까? Service 계층을 굳이 거쳐야 할까?
=> 아까도 비슷한 내용에 대한 토론이였는데 그러면 이번에는 응답과 관련이다.
=> 응답은 그런데 하위 계층을 의존해도 될 것 같다. 하위에서 받아온 응답데이터를 요청보다는 가공하기가 더 쉬우니까 말이다.
=> 그래서 Controller에서 repository로 바로 데이터를 주고 받아도 될까? 안될 껀 없지만 계층구조에 너무 어긋나는 것 아닐까 생각이 든다. 이부분은 결론을 짓지 못했다.
저희가 생각한 논리 흐름이 맞는지와 이에 생각하는 강사님 생각이 너무너무 궁금합니다
추가로 결국 내린 결론은 다음과 같은데 강사님 생각은 어떠하신가요???
1. 도메인 주도 설계가 가장 controller - service - repository 계층 구조에 적합한 것 같다.
2. 하위 계층의 요청에 대한 DTO는 절대 상위 계층의 DTO를 의존해서는 안된다.
3. 프로잭트 규모가 커질수록, DB가 커질 수록 생성자의 갯수는 비약적으로 늘어나게 되는데, 빌더 패턴을 도입해서 생성자 갯수를 줄이자 요즘에는 lombok 라이브러리로 코드의 양을 더욱이 줄일 수 있다.
4. 상위계층 로의 응답은 하위계층에서의 응답에 대해 의존성을 가져도 된다.
답변 1
0
안녕하세요. hsg0208님
죄송하지만 질문 안내에 있는 것 처럼 학습에 관련된 질문을 올려주시길 부탁드립니다.
저도 마음으로는 도움을 드리고 싶지만, 하루에도 수 많은 분들이 질문을 올려주십니다. 그래서 학습과 관련된 질문에 초점을 맞추는 것이 맞다 생각합니다. 다시한번 이해를 부탁드립니다.
감사합니다.