내용을 요약하면,,,
data class 만드는걸 주저할 필요가 전혀 없다.
클래스가 많아서, 파일이 많아서 지저분해질거 같다면 요청/응답 전용 data class들만 따로 패키지를 만들어서 거기에 몰아넣고 열어보지 않으면 될 일이다. 그러므로 맵보단 data class를 만들어 쓰자.
이름을 제외한 나머지 속성들이 모두 비즈니스 로직에서 전혀 쓰이지 않는다면, data class 안만들고 Map으로 관리하고, 이름만 들고다니다가 Map에서 꺼내서 request에만 사용하는 방식은 괜찮은 듯.
* Model은 보통 Business layer에서 사용하는 Domain Model을 의미한다.
* 기타 layer에서 사용하는 Data Class는 Data Class라고 불렀다.
Controller에서 Parameter : Map으로 받는 것과 별도의 Data Class를 만들어 받는 것?
- 별도 Data Class를 만들어 받으면 애너테이션 사용 가능
- `` @Valid`` 가능!
- 좀 더 type safety 하다
- 클라이언트로부터 어떤 필드를 받는지 한 눈에 파악 가능
- 사실 이 것 때문에 웬만하면 만드는 것이 좋음.
- searchParam을 Map으로 받는 경우를 예로 들면, select문 까지 따라가야 어떤 파라미터가 Map으로 넘어오는지 확인이 된다.
- 유지보수하기 나쁨.
Conrtoller에서 Response : Map을 내려주는 것과 별도의 Data Class를 만들어 받는 것?
admin으로 부터의 요청은 a필드가 필요한데, service로부터의 요청은 민감 정보라 a가 없어야 한다.
또는 그 반대 상황이거나, service로부터의 요청은 추가적인 필드 정보가 더 필요하다거나.
등등 다양한 상황을 마주하게 되는데
Domain Model Class 하나로
- business layer
- admin요청 응답
- service요청 응답
모두 커버하기에는 애매한 경우가 종종 생긴다.
이런 문제를 해결하기 위해 떠오르는 방법은 보통 3가지인데,
- 컨트롤러에서 삭제하고 싶은 민감 정보 필드에 null 할당
& 추가적인 필드를 응답으로 내려주기 위해 Model Class에 필드 추가- 단점은 같은 Model Class가 내려가는데 어느 요청에는 필드가 있고, 어느 요청에는 없고... 이게 애매하다.
- 추가 field가 필요한 경우 모델 클래스에도 추가해줘야 해서, 모델 클래스가 계속 비대해질 수 있다는 것도 문제점.
- 그냥 `` Map<>``으로 내려주는 방법
- 비즈니스 로직에서는 계속 모델 클래스로 들고다니다가, 컨트롤러에서 응답 직전에만 Map으로 바꿔서 내려주는 식으로 Map 사용 구간을 최소화하면 유지보수에 크게 문제가 되지는 않음.
- 추가 field가 필요한 경우 그냥 Map에 추가하면 되고. 삭제가 필요한 경우도 그냥 Map에서 빼버리면 됨.
- 한 눈에 어떤 데이터가 내려가는지는 컨트롤러에서 map에 할당하는 로직을 보면 확인이 되기는 함.
- JS에서 객체 리터럴로 json 만들어서 내려주는 느낌으로...
- 근데 컨트롤러 로직이 좀 지저분해지기는 한다.
- 재사용하는 부분이 있으면 그 것 대로 문제가 되기도 하고.
각 컨트롤러 마다 Map에 넣기도 그렇고 이 로직을 다른곳으로 빼기도 좀 그렇고.
- 단점은 annotation을 사용할 수 없다는 점. 그래서 swagger를 못쓴다.
- 응답용 데이터 클래스를 아예 별도로 만드는 방법.
- `` OverseasCardAdminResponse`` 라던가.
- 제일 추천하는 방법
결론) Model은 어떻게 만드는게 좋나?
결론은, 정석대로 간다면 비즈니스 로직에서 쓰는 Domain Model 클래스와, 요청/응답에서 사용한 Request/Response Data 클래스를 분리하는 것이 좋다. (DDD)
그래서 Map보다는, Request/Response Data Class를 사용하게 되는 것이지.
- 비즈니스 레이어에서 사용하는 모델 클래스는 단순 필드 뿐만 아니라 로직도 가지고 있게 된다는 점도 그렇고.
- 책임을 생각하면 요게 맞다. 코드가 더 깔끔해 지는 경우가 다수 있음.
- 클래스를 또 만들어? 라는 생각이 들 수 있지만, 사실 그게 제대로 하는 것.
같은 맥락에서, 각 layer 별로 Data Class를 따로 만드는 것이 정석이긴 하다.
- 비즈니스 레이어에서 사용하는 Model은, 비즈니스 레이어에서 필요한 정보를 반영해서 만들어야 한다.
- (Domain-Driven approach)
- 즉, 서버가 가진 자원 자체를 나타내야 함.
- front-end, DB 등 다른 layer에서 요구하는 데이터 모음 그대로를 Model로 만들면 안됨.
- 사실 제일 좋은건, 각 layer 별로 Data Class를 다 따로 사용하는 것이다.
예를 들면?
front가 요구하는 데이터로 비즈니스 레이어의 Model을 만들어버리면, layer를 나눠 놓은 의미가 없어진다.
Presentation layer, Business layer, Persistence layer 를 나눠놓은 이유가 각자의 의존성을 떨어트리기 위함인데,
이렇게 되면 서버가 가진 자원 자체가 아니라, 프론트가 어떤 데이터를 출력하고 있는지를 바탕으로 모델을 만들어버리게 된다.
- 자원 자체를 나타내지 않으니 REST하지 않게 된다.
- 뷰가 변경되어 해당 뷰에서 가져와야 되는 속성이 하나 늘어나면 그를 담을 수 있는 Model도 수정해야하고, 그걸 가져오기 위한 Repository도 수정해야 한다.
약간 더 구체적인 예?
뷰의 datatable에서 발주번호, 제품이름, 입고날짜를 요구한다고 이거 세개를 조합한 하나의 모델을 만들어버리면, 뷰가 변경되어 업체이름이라는 속성을 추가해야 할 때,
1. 모델에도 추가해야되고, DAO도 수정해야되고 아주 복잡해지며
2. 모델이 딱 그 뷰에만 연결되어 있기 때문에 재사용성이 떨어지며 재사용성이 떨어지니까 비슷한 모델을 또 만드는 결과로 이어질 수 있다.
결론은?
Model은 비즈니스 레이어에서 필요한 데이터 타입으로 생각하고
다른 layer에서 커버가 안된다면, 해당 layer에서 사용할 Data Class를 만들거나 Map을 사용하는게 맞다.
- 엄격하게 한다면 Persistence layer Data Class와 Business Model은 분리하는 것이 좋지만 보통은 이 Model 하나로 가는 경우가 많다.
- DB 설계할 때 비즈니스 로직을 반영하기 때문에, 굳이 나누지 않아도 문제 없는 경우가 많아서.
- 보통은 (DTO, VO)는 테이블 대로 사상하거나 약간 더 복잡한 수준으로, DB layer의 추한 부분을 추상화 한다는 생각으로 만들게 되는 듯.
- DB 가져와야 할 데이터를 1차원적으로 쫙 펼쳐서 모델로 만들지 말고, 발주 안에 List<발주업체>가 있고, 발주업체 안에 List<발주물품>이 있는, 구조화된 형식으로 모델로 사상하게 된다
쿼리가 너무 복잡하게 되고 재사용성이 떨어지면 Persistence layer DTO와 Model을 분리하는 것을 고려해본다.
'Languages & Frameworks > Spring' 카테고리의 다른 글
[Spring] MVC : Controller와 Service의 책임 나누기 (0) | 2020.07.06 |
---|---|
[Spring] MVC : Model 클래스와 요청/응답 Data 클래스, 그리고 Map (0) | 2020.06.25 |
Java Servlet 이란 (0) | 2020.06.15 |
RestTemplate은 어떻게 response Object를 DataType <T>로 변환하는가 (0) | 2020.03.27 |
[Spring] DB 관련 : Mybatis (0) | 2020.03.04 |
[Spring] profile로 beta, real 빌드 구분하기 (0) | 2020.03.03 |