포트 인터페이스가 도메인 모델을 입출력 모델로 사용하면 두 계층 간의 매핑을 할 필요가 없다.
즉, 웹 계층과 애플리케이션 계층, 영속성 계층 모두 도메인 모델인 Account에 접근하는 것이다.
이 결과는?
하지만 이 “No Mapping 전략”이 딱 들어맞을 때가 있다.
즉 모든 계층이 정확히 같은 구조, 같은 정보를 필요로 한다면 “No Mapping 전략”은 완벽한 선택지이다.
물론 애플리케이션 계층이나 도메인 계층에서 웹과 영속성 문제를 다루게 되면 곧바로 다른 전략을 고려해야한다.
중요한 점 → 어떤 매핑 전략을 선택했더라도 나중에 언제든 바꿀 수 있다!
각 어댑터가 전용 모델을 가지고 있어서 해당 모델을 도메인 모델로, 도메인 모델을 해당 모델로 매핑할 책임을 가진다.
각 계층은 도메인 모델과는 완전히 다른 구조의 전용 모델 보유
웹 계층 → 웹 모델을 인커밍 포트에서 필요한 도메인 모델로 매핑, 인커밍 포트에 의해 반환된 도메인 객체를 다시 웹 모델로 매핑
영속성 계층 → 웹 계층에서 이뤄지는 매핑과 유사
이때 두 계층 모두 양방향으로 매핑하기 때문에 → ‘양방향’ 매핑 전략
각 계층의 전용 모델을 변경해도 다른 계층에 영향 X
‘양방향’ 매핑 전략의 사용은 웹이나 영속성 관심사로 오염되지 않은 깨끗한 도메인 모델로 이어진다.
매핑 책임이 명확하고, 안쪽 계층이 해당 계층의 모델만 알면 되기 때문에 매핑 대신 도메인 로직에 집중할 수 있다!
하지만! 아래와 같은 단점 보유
매핑 전략 고려시 주의점!
각 연산마다 별도의 입출력 모델을 사용한다.
웹 어댑터와 애플리케이션 계층 각각이 자신의 전용 모델을 각 연산을 실행하는데 필요한 모델로 매핑
웹 계층은 입력을 애플리케이션 계층의 커맨드 객체로 매핑할 책임을 가진다.
각 유스케이스는 전용 필드와 유효성 검증 로직을 가진 전용 커맨드를 가진다.
애플리케이션 계층은 커맨드 객체를 유스케이스에 따라 도메인 모델을 변경하기 위해 필요한 무엇인가로 매핑할 책임을 가진다.
앞에 것들보다 더 많은 코드가 필요하지만, 구현하고 유지보수하기는 매우 쉽다.
이 전략은 애플리케이션 계층과 웹 계층 사이에서 상태 변경 유스케이스의 경계를 명확하게 할 때 가장 빛을 발한다!
왜 애플리케이션 계층과 웹 계층 사이의 매핑은 추천하면서 애플리케이션 계층과 영속성 계층 사이에서의 매핑은 매핑 오버헤드라고 할까?
⇒ 웹 어댑터 계층과 유스케이스 계층 사이에서는 유효성 검증이라는 분명한 책임이 있지만, 애플리케이션 계층에서 영속성 계층으로 넘겨줄 때에는 전용 모델을 따로 두고 매핑할만한 명확한 이유, 책임, 효용성이 없다. 그렇기에 매핑 오버헤드라 표현했다고 생각한다.
어떤 경우에는 연산의 입력 모델에 대해서만 이 매핑을 사용하고 도메인 객체를 그대로 출력 모델로 사용하는 것도 좋다!
즉, 여러가지 전략을 섞어쓸 수 있고, 섞어 써야만 한다! → 어떤 매핑 전략도 모든 계층에 걸쳐 전역 규칙일 필요가 없다!
동일한 상태 인터페이스를 구현하는 도메인 모델과 어댑터 모델을 이용하면 각 계층은 다른 계층으로부터 온 객체를 단방향으로 매핑하면 된다.
상태 인터페이스는 관련 있는 특성에 대한 getter 메서드를 제공! → 도메인 모델의 상태 캡슐화
도메인 모델 → 풍부한 행동 구현 가능하고 애플리케이션 계층 내의 서비스에서 이러한 행동에 접근 가능
도메인 객체를 바깥 계층으로 전달하고 싶으면 매핑 없이 가능!
행동이 상태 인터페이스에 의해 노출돼 있지 않기 때문에 실수로 도메인 객체의 상태를 변경하는 일은 발생X
애플리케이션 계층에서는 바깥에서 전달한 이 상태 인터페이스를 도메일 모델로 매핑해서 도메인 모델의 행동에 접근
상태 인터페이스를 받아서 해당 계층에서 이용할 수 있는 다른 무엇인가로 매핑해 사용할 수 있기 때문에 한 방향으로만 매핑하는 ‘단방향’ 매핑 전략인 것이다!
매핑이 계층을 넘나들며 퍼져있기 때문에 다른 전략에 비해 개념적으로 어렵다!
하지만 계층간의 모델이 비슷할 경우 사용하면 효과적이다. 예를 들어 읽기 전용 연산 처럼 상태 인터페이스가 필요한 모든 정보를 제공해줄 경우에는 웹 계층에서 전용 모델로 매핑할 필요가 없어진다.
답은 ‘그때 그때 다르다’
매핑 전략은 모두 각각의 장단점을 가지고 있다! 그렇기에 어떤 한 전략을 코드 전체에 대해 적용하면 안된다!
또한 SW는 시간이 지나며 변화하기 때문에, 어제는 최선이었던 전략이 오늘은 아닐수도 있다.
고정된 매핑 전략을 유지하기보다는 빠르게 코드를 짤 수 있는 간단한 전략으로 시작해서 계층 간 결합을 떼어내는 데 도움이 되는 복잡한 전략으로 갈아타는 것도 좋은 방법이다.
- 추상화에 대해서 나온 이야기지만 매핑 전략에 관련되서도 어느정도 적용되는 이야기인 것 같다.
- 일어나지도 않은 변화를 미리 예상하고 걱정하여 올가미를 두는 행동은 코드 악취로 이어질 수 있음을 경고하는 이야기이다!
이런 전략의 사용에 대해 팀 내에서 합의하기 위해 가이드라인을 정해둘 필요가 있다!
가이드라인은 아래와 같은 질문에 답할 수 있어야한다.
인커밍 포트, 아웃고잉 포트는 서로 다른 계층이 어떻게 통신해야하는지 정의
좁은 포트를 사용하면 유스케이스마다 다른 매핑 전략을 사용할 수 있다.
즉, 다른 유스케이스에 영향을 미치지 않으면서 코드를 개선할 수 있다. → 특정 상황, 특정 시점에 최선의 전략 선택 가능!
상황별로 매핑 전략을 어떻게 설정할지 정의한 매핑 가이드 라인을 통해, 코드가 정확히 해야 하는 일만 수행하면서도 더 유지보수하기 쉬운 코드가 될 것이다.