Using Service and Driver layers to decouple your business code from third-party dependencies

Bruno Quaresma
2 min readOct 30, 2017

--

The Service layer can be used in different ways and cases but here, I will share with you how you can use this concept to avoid coupling with external dependencies.

In many applications, we need to connect with third-party services like email, queue and media services. However, we do not want to merge the third services logic in our business logic, right? It makes testing and future changes more difficult.

A good way to do that is to separate the external service logic in a Service layer.

For example, if your application depends on an email service you can create an email service layer (you can use a service class or module) that will wrap this logic. The important thing to do is to create a separation between your business and service logic to avoid coupling.

Services layer

To better demonstrate the solution we can use an example of an email service that sends emails using MailGun third-party service. The code is something like this:

class EmailService {
constructor(config) {
this.driver = MailGun.setup(config);
}
send(data) {
return MailGun.sendEmail(data)
}
}

A little tip before we continue. You should aways use generic names in your methods. You do not need to follow the same names that your libs use.

Now, if you need to change your email service to use another provider or support multiples, what do you do? There are many options and solutions to do that but I usually extract the logic to drivers.

Drivers are responsible for encapsulating specific provider logic in a default interface enabling extensibility and facilitating tests.

Layers with drivers

This changes will be reflected in our code in this way:

class EmailService {
constructor(Driver, config) {
this.driver = new Driver(config);
}
send(data) {
return driver.send(data)
}
}
class MailGunDriver {
constructor(config) {
this.mailgun = MailGun.setup(config);
}

send(data) {
return this.mailgun.sendEmail(data)
}
}
// Usageconst config = { domain: 'me.com', ... };
const emailService = new EmailService(MailGunDriver, config);
emailService.send({
message: 'Hello!'
});

So, what do you think? Do you have some other way to encapsulate third-party services? Thanks for your time and I'd love know your thoughts.

--

--

Bruno Quaresma

Co-Creator of TweetPik and Sr. Software Engineer at Coder