diff --git "a/8\354\236\245_\352\262\275\352\263\204_\352\260\204_\353\247\244\355\225\221\355\225\230\352\270\260.md" "b/8\354\236\245_\352\262\275\352\263\204_\352\260\204_\353\247\244\355\225\221\355\225\230\352\270\260.md" new file mode 100644 index 0000000..1b2a587 --- /dev/null +++ "b/8\354\236\245_\352\262\275\352\263\204_\352\260\204_\353\247\244\355\225\221\355\225\230\352\270\260.md" @@ -0,0 +1,67 @@ +# 8장 경계 간 매핑하기 + +## 매핑하지 않기 전략 + +- 포트 인터페이스가 도메인 모델을 입출력 모델로 사용하면 두 계층 간의 매핑을 할 필요가 없어진다. +- 모든 계층이 같은 모델을 사용하니 계층 간 매핑을 할 필요가 없다. +- 하지만 매핑하지 않기 전략을 사용했을 경우의 결과는 아래와 같다. + - 웹 계층과 영속성 계층은 모델에 대해서 특별한 요구 사항이 발생할 수 있다. + - 이럴 경우 도메인과 애플리케이션 계층은 웹이나 영속성과 관련된 요구사항에 관심이 없음에도 불구하고 도메인 클래스는 모든 요구사항을 다뤄야한다. + - 이 경우 Account 클래스는 웹, 어플리케이션, 영속성 계층과 관련된 이유로 인해 변경돼야 하기에 단일 책임 원칙을 위반한다. +- 각 계층이 Account 클래스에 특정 커스텀 필드를 두도록 요구하게 되면 오로지 한 계층에서만 필요한 필드들을 포함하는 파편화된 도메인 모델로 이어질 수 있다. +- 매핑하지 않기 전략은 모든 계층이 정확히 같은 구조의, 정확히 같은 정보를 필요로 한다면 완벽한 선택지이다. + - 하지만 애플리케이션 계층이나 도메인 계층에서 웹과 영속성 문제를 다루게 되면 곧바로 다른 전략을 취해야한다. + +## 양방항 매핑 전략 + +- 각 계층이 전용 모델을 가진 매핑 전략을 양방향(Two-Way) 매핑 전략이라고 한다. +- 각 어댑터가 전용 모델을 가지고 있어서 해당 모델을 도메인 모델로, 도메인 모델을 해당 모델로 매핑할 책임을 가지고 있다. +- 각 계층은 도메인 모델과는 완전히 다른 구조의 전용 모델을 가지고 있다. +- 웹 계층에서는 웹 모델을 인커밍 포트에서 필요한 도메인 모델로 매핑하고, 인커밍 포트에 의해 반환된 도메인 객체를 다시 웹 모델로 매핑한다. +- 영속성 계층은 아웃고잉 포트가 사용하는 도메인 모델과 영속성 모델 간의 매핑과 유사한 매핑을 담당한다. +- 두 계층 모두 양방향으로 매핑하기에 양방향 매핑이라고 부른다. +- 각 계층이 전용 모델을 가지고 있기에 각 계층이 전용 모델을 변경해도 다른 계층에는 영향이 없다. +- 이 매핑 전략은 웹이나 영속성 관심사로 오염되지 않은 깨끗한 도메인 모델로 이어진다. + - 단일 책임 원칙을 만족한다. +- 개념적으로 매핑하지 않기 전략 다음으로 간단한 전략이다. 매핑 책임이 명확해진다. +- 하지만 너무 많은 보일러플레이트 코드가 생긴다. 매핑 프레임 워크를 사용하더라도 두 모델 간 매핑을 구현하는 데는 시간이 많이 걸린다. +- 또한 도메인 모델이 게층 경계를 넘어서 통신하는 데 사용되고 있다는 것이다. + - 인커밍 포트와 아웃고잉 포트는 도메인 객체를 입력 파라미터와 반환값으로 사용한다. + - 이럴 경우 도메인 모델은 도메인 모델의 필요에 의해서만 변경되는 것이 이상적이지만 바깥쪽 계층의 요구에 따른 변경에 취약해진다. + +## 완전 매핑 전략 +- 각 연산이 전용 모델을 필요로 하기에 웹 어댑터와 애플리케이션 계층 각가이 자신의 전용 모델을 각 연산을 실행하는 데 필요한 모델로 매핑한다. +- 완전 매핑 전략에서는 각 연산마다 별도의 입출력 모델을 사용한다. 계층 경계를 넘어 통신할 때 도메인 모델을 사용하는 대신에 포토의 입력 모델과 같이 각 작업에 특화된 모델을 사용한다. +- 웹 계층은 입력을 애플리케이션 계층의 커맨드 객체로 매핑할 책임을 가지고 있다. +- 애플리케이션 계층은 커맨드 객체를 유스케이스에 따라 도메인 모델을 변경하기 위해 필요한 무엇인가로 매핑할 책임을 가진다. +- 한 계층을 다른 여러 개의 커맨드로 매핑하는 데는 더 많은 코드가 필요하지만 이 방식은 여러 유스케이스의 요구사항을 함께 다뤄야 하는 매핑에 비해 구현하고 유지보수하기가 쉽다. +- 이 방식은 웹 계층과 애플리케이션 계층 사이에서 상태 변경 유스케이스의 경계를 명확하게 할 때 가장 적합하다. + +## 단방향 매핑 전략 +- 동일한 상태 인터페이스를 구현하는 도메인 모델과 어댑터 모델을 이용하면 각 계층은 다른 계층으로부터 온 객체를 단방향으로 매핑하기만 하면 된다. +- 단방향 매핑 전략에서는 모든 계층의 모델들이 같은 인터페이스를 구현한다. + - 이 인터페이스는 관련 있는 특성에 대한 getter 메서드를 제공해서 도메인 모델의 상태를 캡슐화한다. +- 도메인 모델은 풍부한 행동을 구현할 수 있고, 애플리케이션 계층 내의 서비스에서 이러한 행동에 접근할 수 있다. +- 도메인 객체가 인커밍/아웃고잉 포트가 기대하는 대로 상태 인터페이스를 구현하고 있기에 매핑 없이 도메인 객체를 바깥 게층으로 전달할 수 있다. +- 그럼 바깥 계층에서는 상태 인터페이스를 이용할지, 전용 모델로 매핑해야 할지 결정할 수 있다. + - 행동을 변경하는 것이 상태 인터페이스에 의해 노출돼 있지 않기에 실수로 도메인 객체의 상태를 변경하는 일은 발생하지 않는다. +- 이 전략에서의 매핑 책임은 명확하다. + - 한 게층이 다른 계층으로부터 객체를 받으면 해당 계층에서 이용할 수 있도록 다른 무언가로 매핑하는 것이다. + - 그렇기에 각 계층은 한 방향으로만 매핑한다. + +## 언제 어떤 매핑 전략을 사용할 것인가? +- 당연히 그때그떄 다르다! +- 각 매핑의 장단점이 있기에 한 전략을 변하지 않는 전역 규칙으로 정의하려는 건 삼가해야된다. +- 고정된 매핑 전략으로 계속 유지하기보다는 빠르게 코드를 짤 수 있는 간단한 전략으로 시작해 계층 간 결합을 떼어내는 데 도움이 되는 복잡한 전략으로 갈아타는 것도 좋다. + +- 변경 유스케이스와 쿼리 유스케이스에 서로 다른 매핑 가이드라인, 웹 계층과 어플리케이션 계층 사이에서 사용할 매핑 전략과 애플리케이션 계층과 영속성 계층 사이에서 사용할 매핑 전략을 다르게 세웠다고 가정. + - 변경 유스케이스를 작업하고 있다면 웹 계층과 애플리케이션 계층 사이에서는 유스케이스 간의 결합을 제거하기 위해서 완전 매핑 전략 -> 유스케이스별 유효성 검증 규칙이 명확해지고 특정 유스케이스에서 필요하지 않은 필드를 다루지 않게 된다. + - 변경 유스케이스를 작업하고 있다면 애플리케이션 영속성 계층 사이에서는 매핑 오버헤드를 줄이고 빠르게 코드를 짜기 위해서 매핑하지 않기 전략을 첫 번째 선택지로 둔다. + - 쿼리 작업이라면 매핑하지 않기 전략이 웹 계층과 애플리케이션 계층 사이, 애플리케이션 계층과 영속성 계층 사이에서 첫 번째 선택지가 되어야한다. + - 하지만 애플리케이션 계층에서 영속성 문제나 웹 문제를 다뤄야 하게되면 웹 계층과 앱 계층, 앱 계층과 영속성 계층 사이에서 양방향으로 바꿔야한다. + +## 유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까? + +- 인커밍, 아웃고잉 포트는 서로 다른 계층이 어떻게 통신해야 하는 지를 정의 한다. + - 계층 사이에 매핑을 수행할 지 여부와 어떤 매핑 전략을 선택할지가 포함된다. +- 각 유스케이스에 대해서 좁은 포트를 사용하면 유스케이스마다 다른 매핑 전략을 사용할 수 있고, 다른 유스케이스에 영향을 미치지 않으면서 코드를 개선할 수 있기에 특정 상황, 특정 시점에 최선의 전략을 선택할 수 있다. \ No newline at end of file