Posts

Showing posts from 2019

EWF Service Decomposition Pattern

Image
EWF is another microservice decomposition pattern that I like to use when building services. It stands for Entity, Workflow & Functional services. In simplest terms, it’s an extension of Single Responsibility principle and allows for building independent testable services. To understand this pattern better, let’s start with an example. Imagine I want to write a signup service that allows user to signup to a website using their Google account. The service would perform the following:  Let user login into google account and fetch user’s basic information from Google upon successful sign-in. Apply more default settings associated to creating new user.  Persist the user in the database.  After successful registration, redirect the user to the homepage.  At a high level, this works just fine and gets the job done. But if you think about testability first and wants to test this service in isolation we have a problem! The entire testing paradigm relies on the fact that the O

Prefer Consumer over Integration Tests

Image
Recently I attended an RCA meeting for an incident that happened in prod few weeks back. The issue was somewhat of a 2nd degree failure. To put it in simple terms, lets say a workflow composed of two services - A and B. When user performed an action from the UI, it made a call to Service A which then internally called service B with some parameters based on user preferences. In this case, due to some unusual combination of preferences, Service-A ended making call to Service-B with parameters that Service-B didn’t fully understood. Solution - Write an integration test to cover this scenario. Reasoning - Since this involved 3 different components (User Preferences, Service A and Service B), it should be covered by an integration test. More Reasoning: This is sort of the usual way of thinking about the integration tests - meaning whenever there are multiple services involved, we immediately think about writing an integration test. But is this the right approach specially in microserv

Break functional and orchestration responsibilities for better testability

Image
Microservice architecture paradigm fits well within the Unix’s first principle/philosophy: “Make one program do one thing well”.  We love creating small services which has identity of its own (within a bounded context). These services have their own CI/CD pipelines and provides loose coupling b/w components which significantly improves our ability to deliver code to production. In reality, a workflow can span multiple services. Its very common to find scenarios like below: In the above example, a workflow spans 3 services (Service-1, 2 and 3). Service1 receives the original request. In order to process this request, it GET(s) some data from its dependent services(d1/d2/d3). It further runs some business logic and produces an intermediate response #A. It then makes a state mutable call (POST/PUT/DELETE/PATCH) to Service-B using #A as input and waits for its response. Service-B follows the same paradigm and the workflow ends when all services returns.  The scenario above

An Effective TTL-Caching Pattern

Image
Microservice architecture comes with a high cost of service dependencies which impacts the overall performance of the system. In a typical setup, when a request hits the service, it first needs to grab data from its dependent apis and after which it will perform more operations and return the final result back to the caller. Dependent apis may further call other apis or talk to a DB in order the return the requested data and hence creating a complex graph of dependencies.  Caching is an effective way to improve the performance of such system. In many cases, you might be able to cache the response of the dependent apis locally and avoid making those extra calls specially if the data is somewhat static in nature. TTL is a great feature which allows you to cache a data for certain duration after which it expires. The pattern looks something like this: First check if the data is cached. If not, get the data from the original source and cache it for future calls. Recently, I worke