인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

nilgil님의 프로필 이미지
nilgil

작성한 질문수

토비의 스프링 6 - 이해와 원리

도메인 오브젝트 테스트

도메인 오브젝트 메소드 주입에 대해 질문있습니다. (의존성 관련)

작성

·

230

0

안녕하세요 토비님.
질문드리기 전 먼저 오랜만에 너무 즐겁게 공부하고 있어 감사하다는 말씀을 드리고 싶습니다!

질문은 다름이 아니라 '도메인 오브젝트 테스트' 편에서 마지막에 메소드로 ExProvider를 주입하는 방식을 언급해 주셨는데, 이렇게 되면 PaymentExProvider에 의존하게 되는 것 같아서 고민이 되었습니다.

Payment는 도메인 오브젝트로서 순수하게 Payment에 관련된 응집만 추구해야 할 것 같은데, 그걸 넘어서는 건 아닐까라는 생각도 들었고, Payment 테스트 시 ExPriovider 주입이 필요하게 되는 점도 걸렸습니다.

기존처럼 BigDecimal을 받도록 의존성을 끊어주는 게 더 낫지는 않을지 고민이 됩니다.

비슷한 경험으로 이전에 SpringSecurityPasswordEncoder를 도메인 오브젝트에 메소드로 넘겨볼까 하다가 의존성을 생각해 포기하고 String으로 받았었는데, 이와 동일하지는 않겠지만 앞으로도 고민이 될 수 있는 부분인 것 같아 꼭 질문을 드리고 싶었습니다.

도메인 개념적으로 PaymentExProvider와 묶여있는 게 자연스럽다 생각하셔서 그렇게 설계하신 걸까 싶은데, 이에 대해 어떻게 생각하시는지 궁금합니다.

답변 1

1

토비님의 프로필 이미지
토비
지식공유자

좋은 질문을 주셨네요.

Payment 도메인을 어떻게 바라보고 설계할 것인지에 따라서 여러가지 접근 방법이 있다고 생각됩니다.

여기서는 전제를 Payment의 책임으로 적용할 환율 정보를 이용해서 결제용 통화의 금액을 계산하고, 유효한 시간을 제어하는 것까지로 잡았습니다. 이 경우 환율값을 외부에서 넘겨주는 방법이 가장 간단하겠지요.

그런데 만약 통화 종류와 환율 계산 알고리즘 등이 복잡하고, 그게 Payment의 중요한 기능이 된다면 환율 정보를 가져오는 ExRateProvider를 도메인 서비스 인터페이스로 정의하고 이를 엔티티인 Payment가 이용하게 하는 방법도 가능합니다. 어떤 방식이 더 낫다는 건 여러가지 고려할 점이 있겠죠.

만약 환율을 결정하는 기준과 알고리즘이 더 복잡하다면 ExRatePolicy 와 같은 도메인 서비스를 만들어서 외부에서 환율을 결정하는 로직을 따로 적용할 수도 있겠죠. 이 경우 적용환율을 결정하는데, 전체 금액이나 사용자의 레벨, 기존 히스토리 등이 반영이 되어야 한다면 더 복잡해질 수도 있겠습니다.

이런 여러 도메인 로직을 모아서 적용하고 Payment를 초기화하는 작업을 수행하는 도메인 서비스가 따로 만들어질 수도 있습니다.

강의 예제에서는 엔티티의 로직 메소드 호출에 값만이 아니라 어떤 기능을 담당하는 오브젝트를 주입하는 것도 가능하다는 예를 보여드린 것입니다. 그런 결정에 대한 장단점 분석이나 판단은 실제 케이스를 가지고 코드를 만들면서 해볼 수 있을 것입니다.

 

그런데 ExRateProvider와 관계를 끊어야 하는 이유가 DB나 API를 이용하는 오브젝트로 구현되기 때문이라면, 그에 대해서는 동의할 수 없습니다. ExRateProvider 자체는 다른 기술이나 환경에 의존하지 않는 순수한 무상태 도메인 서비스의 인터페이스일 뿐입니다. 코드 레벨에서 도메인 로직의 하나로 표현되어질 수 있겠죠.

 

SpringSecurity의 PasswordEncoder를 도메인 내부에 주입해서 사용하는 것에 대해서 고민하셨다고 했는데요. 왜 고민하신 것인지 궁금하네요. PasswordEncoder가 단지 스프링 라이브러리에 포함된 인터페이스기 때문인가요? 그래서 스프링에 의존하기 때문에, 나중에 스프링을 안 쓰게 되면 곤란해진다는 것인지요? 혹은 그 인터페이스의 메소드가 뭔가 암호화 작업의 일반적인 방식으로 구현되기 힘든 어떤 요소, 예를 들면 스프링 시큐리티의 특정 예외를 던진다거나, 스프링 시큐티에 정의된 이넘을 써야 한다거나, 그런 이유인가요?

 

코드의 의존관계는 코드 레벨에서 먼저 생각해야 합니다. 어쨌든 스프링의 특정 기술에서 정의된 인터페이스이니, 그게 부담스럽다면 관계를 좀 더 느슨하게 끊어주면 됩니다. 예를 들어 스프링의 PassswordEncoder 빈에 대한 어댑터를 하나 만드는 거죠. 그리고 스프링 시큐리티와 무관한, 개발하는 애플리케이션 내에서 도메인 서비스의 하나로 정의된 PasswordEncoderService 인터페이스를 하나 만들고, 이 구현 중 하나오 스프링의 PasswordEncoder를 사용하게 하면, 의존관계를 끊을 수 있습니다. 물론 기능이 수행될 때는 스프링 시큐리티의 인코드가 동작하겠지만, 그런 런타임 의존관계는 이 코드가 변경될 때 방해하지 않습니다. 메소드를 이용한 주입 방식을 일종의 DI라고 취급하는 것이 그런 이유이죠.

 

여러가지 고려해볼만한 흥미로운 질문인 것 같아서 더 얘기를 해봐도 좋겠습니다. 제 답변을 보시고, 다른 의견이 있으시거나 다른 질문이 있으시다면 남겨주세요. 감사합니다.

nilgil님의 프로필 이미지
nilgil

작성한 질문수

질문하기