2

I have previously asked a question on this forum linked here. In short, I wanted to not call 3rd party APIs when developing locally.

Based on the wonderful answers received I have opted for the following:

// /common/infra/emailer/emailer.ts

export interface IEmailService {}

// /common/infra/emailer/implementations/sendgrid-mailer.ts

export class EmailService implements IEmailService {
  private client;
  public async send ();
}

// /common/infra/emailer/index.ts

import { Sendgrid } from 'sendgrid'
import { EmailService } from './implementations/sendgrid-mailer.ts'

const emailService = new EmailService(new Sendgrid());

export { emailService };

So this all works well, my question is how best to implement switching out to a dummy/fake/mock version when developing locally and / or testing.

My idea would be in /common/infra/emailer/index.ts, to have something along the following lines:


// /common/infra/emailer/index.ts

import { Sendgrid } from 'sendgrid'
import { EmailService } from './implementations/sendgrid-mailer.ts'

const emailService = process.env.NODE_ENV === 'production' ? new EmailService(new Sendgrid()) : new DummyEmailService()

export { emailService };

Is this a good approach keeping in line with DDD and Clean Architecture?

2 Answers 2

3
const emailService = process.env.NODE_ENV === 'production' ? new EmailService(new Sendgrid()) : new DummyEmailService()

That pattern I recognize as a feature flag

A simple approach which at least allows feature flags to be re-configured without re-building an app or service is to specify Toggle Configuration via command-line arguments or environment variables. This is a simple and time-honored approach to toggling which has been around since well before anyone referred to the technique as Feature Toggling or Feature Flagging.

If you are a believe in the benefits of Twelve-Factor Apps, then using environment variables is a reasonable choice:

An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).... The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

process.env.NODE_ENV === 'production'

This specific spelling hints at "grouping"; which Twelve-Factor frowns upon. An alternative: use environment variables specific to each feature

process.env.EMAIL_SERVICE === 'live-email-service'

In other words, the environment variable doesn't tell us which environment we are in, but instead names the strategy that we are going to use for creating the email service.

0

As a first step, this is a reasonable approach (I can't vouch for DDD or Clean Architecture, just common sense and experience).

However, in the long run you might want to keep the connection between the environment in which you run and the services that you use more flexible, which can best be achieved using configuration files.

Such a file could look like this in dev environment:

[emailer]
service = dummy

and like this in production:

[emailer]
service = external
provider = Sendgrid

If you have a service that accepts any simple SMTP server with authentication (for example, if you run your own mailserver and use that for testing), it could be configured similarly (note that 123456 is the most common password, so it's likely yours):

[emailer]
service = smtp
provider = mail.example.com:465
security = TLS
username = you@example.com
password = 123456
2
  • Thanks Hans! So I am not sure where I would hook up the reading of the config files? Could you add a little more information there? Also my thinking was that 12 factor suggested individual env vars VS environment files as this scales better with more environments :)
    – dendog
    Jan 19 at 18:08
  • The typical place to read config files is at the start of your program. Often enough it's not necessary to react to changes while the program is running (unless you have a service that's running 24/7 for months). Env vars may be a reasonable alternative, that depends on your use case. Some configuration libraries support alternative or mixed use of config files, environment variables, and command line switches, so if you find such a library for your language that might be the best option. Jan 19 at 20:15

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.