0

We've extracted our email sending into an EmailService - this is a microservice that provides resiliency and abstracts the email logic into an Infrastructure service. The question is how the interface to the EmailService should be defined, with respect to the information it requires about the [User] domain

Approach 1:
EmailService exposes an interface that takes all the fields of the [User] domain that it requires.

Approach 2:
The EmailService interface takes only the UserID. The EmailService then queries the UserService using this ID to fetch the fields that it requires

There are some obvious pros/cons with each approach.
Approach1 requires the calling service to know everything about a User that the EmailService requires, even if its not part of the callers Domain representation of a User. On the other hand the contract between the services is explicit and clear.

Approach2 ensures that the [User] fields are fetched as late as possible, minimising consistency problems. However this creates an implicit contract with the UserService (with its own problems)

I've been doing a lot of research here and on SO, but I haven't been able to find anything around this specific interface design problem. Keeping DDD principles in mind, which approach is correct?

  • 1
    Watch out for chaining, which approach 2 could cause, since it needs one more jump to get user information (there are also other reasons approach 2 is bad though). Every time you call a service, you add latency and reduce reliability. So never start those big chains where service A calls service B, which calls service C and so on. Keep the number of call jumps to a minimum. – Noceo Jul 18 at 5:24
1

I would lean towards Approach 1, with one modification. EmailService does not need to know the concept of a User.

Two points to further clarify:

  • By forcing EmailService to know about the concept of User, you are potentially opening yourself to the high-effort task of keeping the service in sync with potential changes across different bounded contexts. EmailService may end up depending on all entities in your domain.

  • EmailService should only excel at providing email services. It should deal with headers, to/from, message body, bounces, etc. Ideally, it should not even be concerned with what template to use in what business context. UserService can give just enough business context (only the fields that need to be replaced in the email body, for example, along with who to address the email to) and a pointer to the correct email template to use.

1

Neither approach achieves a suitable level of decoupling. As you correctly point out in your first sentence, an EmailService should be given the responsibility of abstracting the formatting and transfer of an email (collectively known as "email logic"). As such, an EmailService should be concerned with information about emails (headers, body, etc), not users!

I would expect the UserService (i.e. the caller) to provide the information necessary to the EmailService to send an email containing User information. That is, supply the appropriate headers, message body, etc. In this way approach 1 is more suitable than approach 2. In either case, the interface of the EmailService should present only email-related contracts.

0

As with most design questions, there isn't a single "correct" approach here. I've seen both patterns used in large enterprise systems, and I can list some more pros/cons that may help you make a decision:

  • Approach 1 lets clients provide their own user information, and this information may not exist or match what is contained in UserService. This may or may not be desirable (flexibility vs. security concerns).
  • Approach 1 can offer better performance if a client's unit of work involves sending multiple emails to the same user. The client can cache the user information and pass it to EmailService instead of EmailService having to fetch it on each call.
  • If you have many clients, approach 2 minimizes the number of integration points with UserService.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.