Software Engineering
api microservices development-process development-environment
Updated Thu, 28 Jul 2022 16:29:31 GMT

Service changes for local development environment


I am developing a web app along with a backend API. The backend however must talk to other services, some of which are internal and others are not.

In an ideal scenario we would spend time and have a local copy of all services running, but this is not possible due to; some services being 3rd party and other internal services are not accessible for all team members.

I would therefore like to know how best to handle this when we cannot have a copy running locally, and interacting with the actual hosted services is not a good idea due to data sync issues.

I would really like to avoid peppering the codebase with if(local) executeMockCall(); but I am not clear what other options there are.




Solution

Invert your dependencies: make the external service into a plugin to your application. Then, attach different implementations depending on whether you're running in a production environment or a development environment.

First, define an interface through which your application communicates with the third party service. With interface I mean anything from a bunch of functions in your code to a REST API, the important point is just that you can select an implementation of this interface at run time. For example, you could provide an environment variable that contains an URL that points to a microservice that provides the expected interface. Or, you could have an if/else at the beginning of your program that selects one of two classes.

Then, create two implementations of your interface:

  • The real implementation that translates your operations to the third party service.

  • The testing implementation that produces dummy results.

The point is that instead of choosing the real or mock implementation throughout your code, that your main code remains agnostic to which implementation it is talking with. This is more testable, and also much less error-prone. The decision to use a particular implementation is made once, and preferably outside of the app. Instead, the choice should be made by the environment in which the app is being run.

Related concepts:

  • Configuration and backing services in the 12-Factor App, a guide for developing SaaS style software.
  • The idea to avoid dependencies from your business logic to external components is also part of the idea of the Onion Architecture: Inner layers define interfaces. Outer layers implement interfaces. This style of architecture has substantial overlap or is equivalent with hexagonal architecture (ports and adapters) and clean architecture.
  • On a lower level, replacing repeated if/else with multiple classes is known as the replace conditional with polymorphism refactoring.