Cloud Design Pattern: Backends for Frontends pattern

It’s one of the “Design and Implementation” category patterns. This pattern was first described by Sam Newman. The definition of this pattern is given below.

Create separate backend services to be consumed by specific frontend applications or interfaces. This pattern is useful when you want to avoid customizing a single backend for multiple interfaces.

Diagram of the Backends for Frontends pattern

Consider that you have an application and it’s initially targeted for Desktop web UI users, so you develop a backend service that provides the features needed for that UI. After few months or years, your application’s user grows and now you want to develop a Mobile application which is going to access the same back end service.

Desktop Application UI and mobile application UI both have different capabilities so you might have different display limitations and due to those, you might want to display more data on the Desktop Web UI and less data on the Mobile application UI. So you are going to update the existing backend service to support both Desktop UI and mobile application UI behaviors. This will make the backend service be a bottleneck in the development process because it has to support various types of requirements. So to avoid this kind of problem, we can create a separate backend service for Desktop UI and separate one for Mobile UI.

Code duplication across services is highly likely when using this pattern. So think about keeping the common logic and business logic in a separate layer.

Advantages of this pattern:

Each backend is specific to one interface. So the code base becomes smaller and easily maintainable.

We can use different languages or frameworks to develop the back end services.

If there are lots of users accessing mobile UI, then we can selectively scale the Mobile backend service alone.

When not to use this pattern:

If your application has both Desktop UI and mobile application UI and both of those use the same backend service and no custom backend code specific to display, then you should avoid using this pattern.

When only one interface is used to interact with the backend.

Cloud Design Pattern: Ambassador pattern

It’s one of the cloud design pattern. The definition of this pattern is given below.

It’s a helper service that sends network requests to another service on behalf of consumer service or application. It’s a service that can be thought of as an out-of-process proxy that is co-located with the client.

If you look at the above diagram, we have a main application and it needs to access another remote service. We can have the application directly accesses the remote service but, if we do so, then we have to handle a lot of things such as monitoring the remote service, retry logic and security in the application code itself. If there is any change such as configuration or URL change, then we have to keep modifying the application code.

So if we have a proxy service, then we can keep everything there itself without modifying anything in the consumer service/application.

When to use this Pattern:

  • Need to access another service in a Legacy application but we do not want to implement all the client code in the Legacy application itself.
  • Need to build a common proxy service that can be used for multiple languages or frameworks.
  • Need to offload cross-cutting connectivity related stuffs to another service.

When not to use this Pattern:

  • Having a proxy service always introduces some network overhead. Even though it’s minimal and some times, it’s going to affect the application performance. So if network latency is critical, then we should avoid using this pattern.
  • If your service is going to be consumed by only application or multiple applications those uses the same language, then instead of creating proxy service, we could create a client library and distribute that to other application developers. So that they can use that instead of accessing a proxy service.

Example:

If you look at the above diagram, we have a “User Service” which provides user-specific information and there are two different applications: one is written in Java and another one is written in .NET and both of them want to access the User Service. This is a proper example to have a proxy service to access the user service on behalf of another service.

The Proxy service is responsible for following things.

  1. Determine the location of User Service
  2. Receive the request from the client and call the remote service
  3. Check Circuit breaker state
  4. Measure request latency
  5. Monitoring
  6. Logging
  7. Metrics
  8. Adding tracing information
  9. Return the response to the client service

So if there is any URL change or configuration change in User Service, then we need to change only the Proxy Service and Application 1 and 2 are not going to be impacted.

We have to consider the below things when using this pattern:

The Proxy Service needs to be co-located with the consumer service.

We can have one shared instance for all the clients or an instance for each client. We need to decide this based on the application load.

Retry logic needs to be handled properly. If one application does not want to have a retry feature or limit the number of retries, then it could pass a header in the HTTP Request and the proxy service needs to read that header and do the needful.

Reference: https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador