작성
·
204
1
안녕하세요 토비님, 강의 너무 재미있게 듣고 있습니다.
인터페이스를 도메인 계층에 둘지, required 포트에 둘지 결정하는 기준이 있을까요?
Splearn의 코드를 예로 들어보면, 도메인 서비스 인터페이스인 passwordEncoder
는 어댑터 계층에서 구체적인 기술로 구현된다는 점에서 EmailSender
, MemberRepository
같은 required 포트의 인터페이스와 유사하게 느껴집니다. 이들 모두 외부 세계(또는 특정 기술)와 애플리케이션을 분리하는 역할을 하기 때문입니다.
만약 애플리케이션 서비스에서 passwordEncoder
를 사용해 비밀번호를 암호화한 후, 암호화된 비밀번호(passwordHash
)를 Member.register
메서드에 인자로 직접 넘겨준다면, passwordEncoder
역시 required 포트에 위치할 수 있지 않을까요? 도메인 계층도 애플리케이션 서비스에 의존하지 않게 되고요.
그런데도 불구하고 passwordEncoder
를 도메인 계층의 인터페이스로 두신 이유가 궁금합니다.
감사합니다.
답변 2
3
안녕하세요. 강의 들어주셔서 감사합니다.
PasswordEncoder를 어디에 둘지 결정할 때 사용한 기준은 도메인 모델을 이야기할 때 이게 등장하는가 입니다. 도메인을 탐구하고 모델로 정리하면서 "회원의 비밀번호는 혹시 DB가 유출되더라도 회원의 비번이 노출되지 않도록 암호화해서 저장해둔다"라고 했죠. 그래서 도메인 계층에 비밀번호를 암호화한다라는 모델을 반영해서 PasswordEncoder 인터페이스를 정의해둔 것입니다.
또, Member라는 엔티티가 이 PasswordEncoder에 의존(사용)하기 때문이기도 하죠. 이런 경우 PasswordEncoder를 애플리케에션 계층에 두면 도메인이 그 밖에 있는 애플리케이션 계층에 의존하는, 계층 아키텍처의 의존 규칙을 위반하게 됩니다. 그걸 피하려면 비밀번호를 인코딩하는 걸 서비스 계층에서 하고, 그렇게 얻은 해시값을 다시 Member에 넘겨야 하는데, 이렇게 코드가 만들어지면 도메인 로직이 두 계층에 흩어지는 문제가 있기도 하죠.
그런데 말씀하신 대로 PasswordEncoder의 구현은 특정 기술이나 환경에 의존적이라 헥사곤 밖에 있는 어댑터에서 구현 또는 연동(비번 인코딩 서비스가 외부에 있다면)을 해야 합니다. 그렇다면 PasswordEncoder는 required interface가 아닌가라고 생각이 되겠죠.
맞습니다. PasswordEncoder는 헥사곤(애플리케이션) 입장에서 볼 때 기능 요구 인터페이스(required interface)가 맞습니다. 원래 헥사고날 아키텍처는 내부에 도메인 계층을 분리하는 것을 지정하지 않았습니다. 그건 우리가 내부에 다시 계층을 하나 더 넣기로 결정한 것일 뿐이죠. 그렇게 보면 도메인 계층에 있는 PasswordEncoder도 결국 헥사고날의 포트가 되는 겁니다. 포트는 헥사곤 내부에 정의해 두고, 그 밖에서 구현한다라는 헥사고날의 원칙을 지키는 것이죠.
다만, 도메인 모델 패턴을 적용하기 위해서 계층을 하나 더 내부에 만들었기 때문에 도메인 계층에 정의된 인터페이스는 required 패키지에 직접 둘 수는 없을 뿐입니다. 이게 처음에는 살짝 혼동이 될 수도 있습니다만, 계속 개발을 해보면 자연스러워질 것입니다.
인터페이스로 정의한 도메인 서비스의 구현은 어떤 경우엔 도메인 계층 안에 구현이 들어가기도 하고, 어떨 때는 애플리케이션 서비스에 구현을 둘 수도 있습니다. 그 구현 코드 성격에 따라서 결정되는 것이죠. 이번처럼 도메인 로직 밖으로 분리하는 것이 적당한 경우라면 외부로 빼둔 것이고요.
이에 대해서 설명을 했다고 생각했는데 좀 부족했던 것 같습니다. 더 궁금하신 게 있으시면 알려주세요.
0