8장. 경계 간 매핑하기

Seungjae·2022년 6월 21일
0

우아한 스터디

목록 보기
9/10

‘매핑하지 않기' 전략


  • 포트 인터페이스가 도메인 모델을 입출력 모델로 사용하면 두 계층 간의 매핑을 할 필요가 없다.

  • 즉, 웹 계층과 애플리케이션 계층, 영속성 계층 모두 도메인 모델인 Account에 접근하는 것이다.

    • 물론 책의 그림상으로는 연결되어 있지 않지만, 실제 코드를 작성하면 어쩔 수 없이 웹 계층과 애플리케이션 계층도 Account를 알게 된다.
  • 결과는?

    • 도메인과 애플리케이션 계층은 웹이나 영속성과 관련된 특수한 요구사항에 관심이 없음에도 웹과 영속성 관련 요구사항을 다뤄야 한다.
    • 기술적 요구사항이 아니더라도, 특정 계층에만 필요한 필드로 도메인 모델이 더럽혀질 수 있다.
    • 즉 Account는 웹, 애플리케이션, 영속성 계층과 관련된 이유로 변경된다!
      • SRP 위반
  • 하지만 이 “No Mapping 전략”이 딱 들어맞을 때가 있다.

    • 간단한 CRUD 유스케이스에서 같은 필드를 가진 웹 모델을 도메인 모델로, 혹은 도메인 모델을 영속성 모델로 매핑할 필요가 있을까?
    • 그럴 필요 없다.
  • 즉 모든 계층이 정확히 같은 구조, 같은 정보를 필요로 한다면 “No Mapping 전략”은 완벽한 선택지이다.

  • 물론 애플리케이션 계층이나 도메인 계층에서 웹과 영속성 문제를 다루게 되면 곧바로 다른 전략을 고려해야한다.

  • 중요한 점 → 어떤 매핑 전략을 선택했더라도 나중에 언제든 바꿀 수 있다!

‘양방향’ 매핑 전략


  • 각 어댑터가 전용 모델을 가지고 있어서 해당 모델을 도메인 모델로, 도메인 모델을 해당 모델로 매핑할 책임을 가진다.

  • 각 계층은 도메인 모델과는 완전히 다른 구조의 전용 모델 보유

  • 웹 계층 → 웹 모델을 인커밍 포트에서 필요한 도메인 모델로 매핑, 인커밍 포트에 의해 반환된 도메인 객체를 다시 웹 모델로 매핑

  • 영속성 계층 → 웹 계층에서 이뤄지는 매핑과 유사

  • 이때 두 계층 모두 양방향으로 매핑하기 때문에 → ‘양방향’ 매핑 전략

  • 각 계층의 전용 모델을 변경해도 다른 계층에 영향 X

    • 각각의 웹 모델, 도메인 모델, 영속성 모델이 자신의 목적에 부합하는 최적의 구조를 가질 수 있다.
  • ‘양방향’ 매핑 전략의 사용은 웹이나 영속성 관심사로 오염되지 않은 깨끗한 도메인 모델로 이어진다.

    • SRP 만족
  • 매핑 책임이 명확하고, 안쪽 계층이 해당 계층의 모델만 알면 되기 때문에 매핑 대신 도메인 로직에 집중할 수 있다!

  • 하지만! 아래와 같은 단점 보유

    • 너무 많은 보일러플레이트 코드
    • 도메인 모델이 계층 경계를 넘어서 통신하는데 사용 → 포트의 파라미터, 반환값으로 도메인 모델이 사용되어 바깥쪽 계층의 요구에 따른 변경에 취약
  • 매핑 전략 고려시 주의점!

    • 은총알은 없다! → 모든 상황에 맞는 완벽한 해결책은 없다!
    • 어떤 매핑 전략도 철칙처럼 여겨져서는 안 된다!
    • 각 유스케이스마다 적절한 전략을 선택할 수 있어야 한다!

‘완전’ 매핑 전략


  • 각 연산마다 별도의 입출력 모델을 사용한다.

  • 웹 어댑터와 애플리케이션 계층 각각이 자신의 전용 모델을 각 연산을 실행하는데 필요한 모델로 매핑

  • 웹 계층은 입력을 애플리케이션 계층의 커맨드 객체로 매핑할 책임을 가진다.

    • 커맨드 객체는 애플리케이션 계층의 인터페이스를 해석할 여지 없이 명확하게 만든다.
  • 각 유스케이스는 전용 필드와 유효성 검증 로직을 가진 전용 커맨드를 가진다.

  • 애플리케이션 계층은 커맨드 객체를 유스케이스에 따라 도메인 모델을 변경하기 위해 필요한 무엇인가로 매핑할 책임을 가진다.

  • 앞에 것들보다 더 많은 코드가 필요하지만, 구현하고 유지보수하기는 매우 쉽다.

    • 유효성 검증을 SendMoneyCommand같은 전용 커맨드 객체에서 수행해줄 수 있다!
  • 이 전략은 애플리케이션 계층과 웹 계층 사이에서 상태 변경 유스케이스의 경계를 명확하게 할 때 가장 빛을 발한다!

    • 애플리케이션 계층과 영속성 계층 사이에서는 매핑 오버헤드 때문에 사용하지 않는 것이 좋다!

매핑 오버헤드?

  • 왜 애플리케이션 계층과 웹 계층 사이의 매핑은 추천하면서 애플리케이션 계층과 영속성 계층 사이에서의 매핑은 매핑 오버헤드라고 할까?

  • ⇒ 웹 어댑터 계층과 유스케이스 계층 사이에서는 유효성 검증이라는 분명한 책임이 있지만, 애플리케이션 계층에서 영속성 계층으로 넘겨줄 때에는 전용 모델을 따로 두고 매핑할만한 명확한 이유, 책임, 효용성이 없다. 그렇기에 매핑 오버헤드라 표현했다고 생각한다.

  • 어떤 경우에는 연산의 입력 모델에 대해서만 이 매핑을 사용하고 도메인 객체를 그대로 출력 모델로 사용하는 것도 좋다!

  • 즉, 여러가지 전략을 섞어쓸 수 있고, 섞어 써야만 한다! → 어떤 매핑 전략도 모든 계층에 걸쳐 전역 규칙일 필요가 없다!

‘단방향’ 매핑 전략


  • 동일한 상태 인터페이스를 구현하는 도메인 모델과 어댑터 모델을 이용하면 각 계층은 다른 계층으로부터 온 객체를 단방향으로 매핑하면 된다.

  • 상태 인터페이스는 관련 있는 특성에 대한 getter 메서드를 제공! → 도메인 모델의 상태 캡슐화

  • 도메인 모델 → 풍부한 행동 구현 가능하고 애플리케이션 계층 내의 서비스에서 이러한 행동에 접근 가능

  • 도메인 객체를 바깥 계층으로 전달하고 싶으면 매핑 없이 가능!

  • 행동이 상태 인터페이스에 의해 노출돼 있지 않기 때문에 실수로 도메인 객체의 상태를 변경하는 일은 발생X

  • 애플리케이션 계층에서는 바깥에서 전달한 이 상태 인터페이스를 도메일 모델로 매핑해서 도메인 모델의 행동에 접근

  • 상태 인터페이스를 받아서 해당 계층에서 이용할 수 있는 다른 무엇인가로 매핑해 사용할 수 있기 때문에 한 방향으로만 매핑하는 ‘단방향’ 매핑 전략인 것이다!

  • 매핑이 계층을 넘나들며 퍼져있기 때문에 다른 전략에 비해 개념적으로 어렵다!

  • 하지만 계층간의 모델이 비슷할 경우 사용하면 효과적이다. 예를 들어 읽기 전용 연산 처럼 상태 인터페이스가 필요한 모든 정보를 제공해줄 경우에는 웹 계층에서 전용 모델로 매핑할 필요가 없어진다.

언제 어떤 매핑 전략을 사용할 것인가?


  • 답은 ‘그때 그때 다르다’

  • 매핑 전략은 모두 각각의 장단점을 가지고 있다! 그렇기에 어떤 한 전략을 코드 전체에 대해 적용하면 안된다!

  • 또한 SW는 시간이 지나며 변화하기 때문에, 어제는 최선이었던 전략이 오늘은 아닐수도 있다.

  • 고정된 매핑 전략을 유지하기보다는 빠르게 코드를 짤 수 있는 간단한 전략으로 시작해서 계층 간 결합을 떼어내는 데 도움이 되는 복잡한 전략으로 갈아타는 것도 좋은 방법이다.

올가미를 미리 두지 말자! 첫번째 총알은 맞고, 다음 번에 날아올 총알에 대비하자!

  • 추상화에 대해서 나온 이야기지만 매핑 전략에 관련되서도 어느정도 적용되는 이야기인 것 같다.
  • 일어나지도 않은 변화를 미리 예상하고 걱정하여 올가미를 두는 행동은 코드 악취로 이어질 수 있음을 경고하는 이야기이다!
  • 이런 전략의 사용에 대해 팀 내에서 합의하기 위해 가이드라인을 정해둘 필요가 있다!

  • 가이드라인은 아래와 같은 질문에 답할 수 있어야한다.

    • 어떤 상황에서 어떤 매핑 전략을 가장 먼저 택해야하는가?
    • 왜 해당 전략을 최우선으로 택해야하는가?

유지보수 가능한 SW를 만드는 데 어떻게 도움이 될까?


  • 인커밍 포트, 아웃고잉 포트는 서로 다른 계층이 어떻게 통신해야하는지 정의

  • 좁은 포트를 사용하면 유스케이스마다 다른 매핑 전략을 사용할 수 있다.

  • 즉, 다른 유스케이스에 영향을 미치지 않으면서 코드를 개선할 수 있다. → 특정 상황, 특정 시점에 최선의 전략 선택 가능!

  • 상황별로 매핑 전략을 어떻게 설정할지 정의한 매핑 가이드 라인을 통해, 코드가 정확히 해야 하는 일만 수행하면서도 더 유지보수하기 쉬운 코드가 될 것이다.

profile
코드 품질의 중요성을 아는 개발자 👋🏻

0개의 댓글