Skip to content

Not everything is a service.

Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


I need to create an email service within my system. The service’s responsibility is to send out customer emails for things like Order Confirmation or when Billing information is changed. But how do we communicate with this email service when we need to send an email? There’s another intuitive option that starts when you realize that not everything is a service.

YouTube

Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.

Event-Driven

The first option would be using an event-driven architecture and the publish-subscribe pattern. In this scenario we have an “Email Service” that listens for specific events to trigger sending out emails.

For example, let’s say an OrderPlaced event occurred, and that’s when we wanted to send out an email confirmation. The Email Service would be a consumer of the OrderPlaced event and then compose and send the email. This email service would be aware of all the different events across the entire service and how it handles and composes the email for each.

Commands

Another option is using Commands. This means explicitly telling the email service to send out a specific email.

If you follow any of my YouTube/Blog you’ll know that I’m not in love with RPC in various situations, so you might be surprised by the above diagram. I’m just doing this for the simplicity of the example, but yes, I’d often prefer to be using a queue instead of RPC in this situation. Either way, RPC or Queues, the point is you’re telling the email service to send out a specific type of email, for example the Email Confirmation.

Composition

Both of the above options, using events or commands, have the same underlying problem. They require the Email Service to compose the email.

The above image is an example of a shipment notification email I received for an order. The shipment, payment, and order information are likely owned by different services.

So, in order to generate this email, there are multiple different services that are required to get data about this order.

The Email Service has to do all this composition and communicate with other services in order to generate the email.

Regardless of whether the email was triggered by an event or if it was explicitly by a command, the email service would have to reach out to all the different services to get data so it composes it together to generate the email.

Producer is the Consumer

Another option, which might be intuitive but not obvious, is that the producer is the consumer. What I mean is that the service in the examples above that want to send out an email already have most of the data, or the primary data that pertains to the email that needs to be sent.

In my example above of my order being shipped, it’s not that an Email Service is responsible for composing that email; it’s the Shipping Service. It already has all my shipping information.

However we likely still require a ton of coupling if we need data from other services. We have a few of options there.

First, the service should already have all the data it needs to compose the email without having to call other services. To do this, most often choose to keep a local cache copy of data for this exact purpose. This is called Event-Carried State Transfer. I’m not a fan of Event-Carried State transfer for transactional data. I think it has utility, but distributing transactional data all over the place will leave you scratching your head as to why data is stale or incorrect. So I’m not a fan of this option, but it is an option.

The second option is that you’re OK with calling other services to get the data to compose the email. If the email composition was occurring/initiated from a message in a queue, then if you fail to make the request to another service, it does not interfere with any user interactions. Hence, I prefer queues in this type of situation because they add resilience to your system.

The third option is not to do any composition in the first place. You’ll notice more and more that a lot of the emails you receive simply direct you to a website/app, which then shows you all the relevant details. There aren’t very many details even included in the email at all. The email is really a very narrow, limited notification. This can be for privacy concerns as well, but saves you from having to do composition.

What’s a Service

So what’s the point of the email service then? If the shipping service is responsible for composing the email, is the email service just a gateway to whichever email provider we’re using? Pretty much. But that’s not a service, by my definition.

A service is the authority of a set of business capabilities. Those business capabilities have data ownership behind them. Meaning a service requires data ownership.

But that doesn’t mean the email service isn’t a service because all kinds of things related to emails require data ownership. If you’ve done any work with emails, you know there are things like delivery and open events you might track, bounces and spam handling for reputation, unsubscribing, etc.

I’m not suggesting the Email Service doesn’t exist; on the contrary, it does exist because handling emails for all the above reasons is painful. The point is that it doesn’t need to generate the email and do all the data composition because it doesn’t own that data. The service that owns the data related to what the emails about can do the composition. Let the Email Service be responsible for handling email-related concerns. Data composition isn’t one of them.

Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.

Leave a Reply

Your email address will not be published. Required fields are marked *