프로젝트

TIL-221108- VALUE OBJECT를 적극!활용하자

혹등고래1호기 2022. 11. 8. 23:48

모델의 field값이 너무 많아 져서 뭐가 뭔지 알아보기 힘든 고통스러운 상황이 되면 어떻게 해야할까? 

1. 그냥 참고한다.

2. 뭔가 이상함을 느끼고 방법을 찾아본다.

 

이때까지는 1번으로 하고 있었지만 2번의 방법을 오늘 알게 되었다. 

 

 

Product가 가지고 있는 필드 값들이다. 뭐가 뭔지 알아 보기가 힘들고 Long타입으로만 되어있는 것은 사실상 알아 볼 수 가 없다.

 

이 문제를 해결할 수 있는 방법은 무엇일까? 바로 값 객체를 사용하는 것이다. 가격과 관련된 필드값들은 VO(Value Object)로 

만드는 것이다. 

 

VO란 무엇인가?

 

DDD(Domain Driven Development)에서는

 

개념적 식별성을 갖지 않으면서 도메인의 서술적 측면을 나타내는 객체를 VALUE OBJECT라고 한다. Entity를 가지지 않는 객체 이다.

 

VALUE OBJECT는 도메인 모델의 설계 요소를 표현할 목적으로 인스턴스화 되는데 , 이러한 설계 요소가 어느 것인지에 대해서는 관심이 없고 오직 해당 요소가 무엇인지에 대해서만 관심이 있다.

 

모델에 포함된 어떤 요소의 속성에만 관심이 있다면 그것을 VALUE OBJECT로 분류하라. VALUE OBJECT에서 해당 VALUE OBJECT가 전하는 속성의 의미를 표현하게 하고 관련 기능을 부여하라. 또한 VALUE OBJECT는 불변적(immutable)으로 다뤄라. VALUE OBJECT에는 아무런 식별성도 부여하지 말고 ENTITY를 유지하는 데 필요한 설계상의 복잡성을 피하라.

 

VALUE OBJECT를 구성하는 속성은 개념적 완전성(conceptual whole)3을 형성해야 한다. 이를테면, 도, 시군구, 읍면동, 우편번호와 같은 속성은 한 Personal 객체에서 개별 속성이 되어서는 안 된다. 그러한 속성은 하나의 완전한 주소를 구성함으로써 더 단순한 Person과 더 응집력 있는 VALUE OBJECT를 만들어낸다. 4

 

위의 Product모델에 어떤 식으로 적용을 할 수 있을까? price나 deleveryFee같이 가격과 관련이 있는 필드값들은 VALUE OBJECT로 뺴내는 것이 좋다. 

 

만약 배송비나 상품가격에 대해서 할인을 해야한다고 하면 위에 있는 사진의 상태에서는 모델에서 뭔가 로직을 만들어야 하고 할 것이다.

 

하지만 MONEY VALUE OBJECT를 사용하면 MONEY객체 내에서 로직을 처리해 줄 수 있기 때문에 설계상의 복잡성을 피할 수 있다.

 

한국에서만이 아니라 미국에서도 판매를 해야 한다면 KoreanWon이라는 밸류 오브젝트에 달러 환율을 적용하면 상품의 가격들이 

 

이러한 이유로 ENTITY의 설계상의 복잡성을 줄 일 수 있다는 의미인 것 같다.

 

그리고 또한 의미가 명확해 지는 효과가 있다. Product에 있는 field값들을 사실 전부 다 VALUEOBJECT로도 뺴줄 수 있을 것 같기는 하다. 

 

하지만 그래도 field값이 많은 것은 똑같다. 그럴 떄는 fake()메소드로 가짜 객체를 만들어 줘서 테스트에서 알아보기 쉽게 사용을 하도록 하자

 

설계를 본인이 완벽하게 했다고 하면 VALUE OBJECT로 처음부터 만들어서 사용을 하면 되겠지만 완벽한 설계라는 건 사실 있는 지 모르곘다. 

 

아니면 하면서 아 이거는 VALUE OBJECT를 사용을 해야겠는데 아니면 오히려 이건 도메인 모델로 사용을 해야 겠다. 라는 식으로 진행을 하면서 설계를 변경하는 방식을 Agile한 방식이라고 하지만 단점은 어렵다. 

 

그러면 뭐냐? 어려운 걸 해야 한다라는 것이다. 

 

 

 

컨트롤러는 가벼워야 한다. 리팩토링을 하기 전에는 Controller에서 Dto를 조합을 해주는 방식으로 해서 컨트롤러가 꽤나 많은 코드를 차지하기도 하고 Product컨트롤러이지만 Image나 option같은 객체들도 나오는 식으로 있는 구조 였는데 그 로직들을 모두 서비스안으로

넣었다.

 

DTO를 변환해주는 로직은 Controller에 있어야 하는 줄 알았지만 DTO의 위치는 UI Layer와 Application Layer의 경계라고 하는데 

 

Controller나 application Layer(service)둘 중 어느 곳에 있든 크게 상관은 없는 것 같다. 하지만 중요한 건 결국 ProductContoller는

 

Product에 대해서 관심을 가져야지 다른 게 있으면 안된다. 다른 것들은 service안에서 다른 Repository를 호출하는 식으로 진행을 해야한다.

 

현재 단계에서는 Service가 Service를 참조하거나 Controller에서 여러개의 service를 호출하는 방식은 금기하도록 하자