Microservices architecture has been discussed and practiced, at least for half a decade now. When to use Microservices and when not to, this is something that really troubles a lot of people. A few influencers advocate microservices architecture over traditional monoliths only if your team is having a deep understanding of the domain/ business. But why does the team needs an understanding of business/ domain and is it the only concern that we should be worried about?

I have worked a few projects using a microservices architecture. What I have experienced that microservices architecture is easier said than done. It’s easy to understand but it’s tough to implement.

Often teams end up with SOA architecture or one thick monolith surrounded by SOA style services. We can avoid being there if we keep the basics right. If you are planning to break an existing monolith to smaller services or planning to build a greenfield, brainstorm these topics first.

Service Boundaries: Identifying service boundaries is the essence of everything in a microservices architecture. We argue to evolve system design and architecture but in this world, you need a little drawing board exercise to draw the boundaries. You can model either your business functions or DDD’s bounded contexts as a service boundary.

No alt text provided for this image

Once you draw the rough boundary, evolve each service/boundary as a separate system. While this drawing board exercise sounds so easy but it’s the most crucial part. A wrong boundary could lead you to SOA/monolith style architecture and stops you to achieve desired outcomes. In my experience, identifying boundaries is way easier if you have a deep understanding of the business/ domain.

Persistence Boundaries: While deciding service boundary is the very first step, defining the persistence boundary is second.

No alt text provided for this image

The recommended approach is having one database per service. To get data between services, either make the API calls or duplicate data as and when needed. You can choose the shared DB approach as well where one service is writing and the others are reading. While going with a shared approach, be cautious about DB changes. For Example, changes in write schema of service A could break the read operation of service B. We have to give backward compatibility at DB level to avoid such issues. Shared DB approach can help when you have just started breaking up a monolith. It helps you to get going and buy some time to think about how to achieve your target of one service per DB.

Inter-Service Communication: After defining boundaries of your services and persistence, you have to think about inter-service communication.

No alt text provided for this image

You may choose to have synchronous communication between your services but always consider that it’s going to make your system coupled. Too much chatting between the services would defeat the purpose of having microservices as it would behave like a distributed monolith. Alternate of synchronous communication is asynchronous communication which scales well and keeps services decoupled. It makes your system eventually consistent but adds a lot of overhead of local and global compensation in case of failures and errors.

Testing Strategy: In the old world of MVC frameworks, the only contract exposed by big systems was UI and hence, testing was revolving around it along with your unit and integration test.

No alt text provided for this image

Now with microservices, UI could be considered as just another service. The test pyramid is still relevant in this new world but the definition has changed. While you treat each service as a system and test it as a system, you check the integration of systems using contracts.

E2E still rules the pyramid from the top and ensures the sanity of your ecosystem. Although the scope of E2E tests is always debated. If you write too many tests at the highest level, you will not be able to leverage this architecture. In other words, having a monolith testing framework over microservices architecture may not scale. Acceptance tests should be at the possible lowest level. It will reduce the cost of having too many tests at the top and hence allow you to have faster feedback.

Your testing strategy should be clear from day one otherwise it would be impossible to test a distributed system and tracing impacts of the fast-moving world.

Tools: In the SOA and monolith, tools were there but they weren’t essential. In this microservices age, tools become first-class citizens. Although It all depends on your use cases but you should give a thought about the following.

No alt text provided for this image
  • API Gateway
  • Service Mesh
  • Load Balancer
  • Containers
  • Service Discovery
  • Service Proxy
  • Log Management
  • Monitoring
  • Queues & Topics
  • Config DB & Secret Manager

I am not writing in detail on these topics as it will be a post in itself. My experience is sooner you bring tools in to picture, the better it would be. In the ideal world of microservices, tools should be the first citizen.

Deployment Strategy: With a monolith, we were deploying only an artifact on multiple servers. Now we will need to deploy multiple artifacts on multiple servers. Managing multiple artifacts bring a lot of complexity. For example, one small configuration mistake could cost your system and as well as your business. It will be extremely tough to debug issues like these.

No alt text provided for this image

To avoid issues like these, we should think about baking DevOps culture in teams. Keeping DevOps as an integrated part of your development team, you can bring automated deployments and faster feedback since day one. Without an integrated culture, managing and maintaining deployments would not be less than a nightmare.

Team Structure: Having a monolithic team and having microservices architecture would be difficult to work out.  Conway’s law suggests, “Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.” Microservice architecture follows it closely. If teams are aligned with architecture, delivery will be smooth. The recommendation most of the company follow is

“One service should be managed by one and only one team. A Team can manage more than one service.”

As one team is managing one service, other teams do not need to worry about it. Independent teams can decide their own practices and deployment cycles and hence faster delivery.

Dev Setup: All right, so we have thought about service boundaries, DB context, and team structure. We have thought about testing strategy, DevOps and tools as well. So now we can think about the actual development. If we go traditionally, we can set up everything locally on a dev/ QA box or alternatively we can set up a dev environment.

No alt text provided for this image

We could always argue in favor of the traditional approach that services are running on docker, could be easily run on local but think again, microservices architecture is not just about services running on the container/ server, it’s more about the whole ecosystem. Managing the whole system in a local box could be a real challenge. For one of the projects, my team had tried setting up the local stack(an open-source tool to mock AWS locally). We had a mixed amount of success but eventually, we gave up the idea and built the dev environment. We also noticed that not only setting up was difficult but ramping up a new folk was also an uphill task. Investing in the dev environment upfront could negate a lot of things up front and gives a great dev experience.

Those were my two cents. Brainstorming these points could give you an answer either to begin your journey or not. As each and every solution solves a few problems and introduces a few more, microservices architecture is not an exception. If it’s used in the right way with the right tools, it allows you to deliver faster than ever. But if not, it can introduce problems that can end up very costly to the development team, project, and off-course to the business.

*Image Sources: MicrosoftNginx, LyndaByndyusoftDzone