From Monolithic to Microservice Architecture-The Mindset Change

Nirdosh Gautam
Devnetwork
Published in
7 min readJan 30, 2019
Pic from unsplash

We all have been hearing about Microservices for quite a time now. Sometimes, people often compare companies based on the number of microservices they are running.

Company X has 300 microservices running at any point of time.

Let’s pause for a while and think why do we need so many microservices. Is it necessary? What factors decide that we need X number of services? Why should we break a service(monolith) into multiple services?

Before diving deeper, let’s understand first what exactly are microservices.

Microservices are smaller pieces of softwares which have their own area of concern and only fulfill a specific business need and communicate with each other which make the platform function as a whole.

E.g. For an e-commerce site, the front end for the main landing site can be one service. Similarly, the backend and billing and products search can be three different independent services.

On the other hand, a monolith is a single service/application which serves the need of the entire platform and has all business logic cramped into a single app. It serves all kind of user requests. There is no need to request another internal service for some kind of data. Pretty simple setup as it sounds.

Okay. Now we have a general idea of what microservices are, let’s jump into cases where microservices architecture is useful.

  1. Working across multiple development teams
    It is fine if you have a single monolith app and couple of people working on it. Eventually your app’s codebase grows. It starts serving many business purposes and you need more people to work on various domains of same business(e.g. recommendation system, search engine, new product alerting mechanisms, managing delivery and tons of other problems) when your business is going good.
    It sounds awesome right? But imagine 50–100 people working on a single repository/codebase on hundreds of things. What a mess would it be. One’s work conflicting/dependent with others. In this case, the major benefit of microservices is the decoupling of development and deployment.
  2. Independent scaling
    Imagine if you have an entertainment website which has almost 20–50 games which can be played online. Let’s also assume you also have a meme generator tool in your site which is very famous. Imagine the case where the meme generator gains more popularity resulting to 1 million of API calls per second. However, other fun things in your website are not being used that much. Your server is running out of resources. What do we do in this case? We can separate out the meme generator API and then scale it as much as needed keeping the other functionalities of website at minimal resource configuration.
  3. Working with different Technology Stacks
    E.g. Your primary stack is Ruby but for a specific problem you have decided to use GoLang. There is no other way than having two separate services which are essentially part of the same system.

Don’t Build a Distributed Monolith!

There is also a chance that we might have separated a perfectly working monolithic app into microservices which are not decoupled at all. There are few questions which we can ask ourselves in order to identify if we are working on distributed monolith or not.

  • Are the microservices too chatty?
  • Do they share a common database?
  • Does change/deployment in one requires change/deployment in another?
  • Do they share some code?
  • Are microservices maintaining a cache of each other’s data?

The Microservices Mindset

Things drastically change when we move from monolithic to microservices architecture. We need to think about how the development teams and process need to be structured, how microservices talk to each other and handle all failure cases. More microservices means more points of failure. Things might also get pretty complex depending on the nature and scale of the system. We need a mindset change for easy transition.
Here are the list of things we should be thinking about:

  • Cost: Infrastructure, People, Management
    Yes! The very first thing. Keep in mind that, every decision comes with a cost. One simple example, let’s assume you had a single server setup before which could scale to N instances if needed. Now, you have M microservices with databases and everything which can autoscale to N instances. All of these microservices require some other setups as well. Now, you need more people to work on these. Also, there is management cost for all microservices.
    Don’t make them too micro resulting unnecessary number of microservices.
  • Working Across Teams: Communication
    You will have multiple teams to work on different sets of microservices. Each team will look only into certain business domain and the microservices which fall under the domain. Suddenly there will be less visibility of what other teams are doing. Do a sync up meeting regularly. Focus on documentation and sharing.
  • Re-evaluating priorities across teams
    Team 1 need to built a feature on microservice Product Search on coming sprint which requires a change in the Billing App which falls under Team 2. But Team 2 has other higher priority tasks to work on than the change requested by Team 1. What to do now?
    In this case, we need to zoom out from development teams’ scope and think in terms of business. Select the work which adds the most value to the business at this point of time amongst all. It is necessary to realize that we(all development teams) are all working for a common goal.
  • Working on a Microservice as a Developer
    Previously, there used to be a few apps or may be a single app which would not depend on anything else. We could just boot up one app and test. But now, one microservice can depend on 2–3 other services. So we need to boot them all in our local machine. You can group related microservices in a single cluster and fire up all apps as Docker containers using Docker compose.
    Another approach could be mocking all other services which are not required while doing development on a particular microservice. But sometime mocking does not work because one transaction in service X might trigger database create request in other Y and Z services and we need to fetch the actual data from database from service Y and Z in service X and the data must be in sync across all services.
    Explore different approaches select the best fit for you which makes simple and easy for the developers.
  • Proper Release/API Documentation
    Different teams need to look into what other teams are planning to work, working and have worked on. E.g. In case of API development, we can finalize and release the documentation of APIs earlier to other development teams before we actually start working on it. This way, we will have documentation as well as visibility. Yes you can ignore documentation and deliver work but in coming days your team/org will definitely going to suffer because of assumptions and mis-communications.
  • Setting Standards
    We have different teams working on different microservices and if there is no any guidelines/standard, there could be different versions of microservices which is difficult to manage.The core service setup need to be the same. So, we need to define standards for things like microservice codebase layout, coding standards, conventions and things that should be present in any microservices(authentication, logging, error handling, error formats), so that there is no difference in the foundational elements in all microservices developed by different teams. You can also build a bootstrapping tool for creating a new microservice which can be used by all teams. It will also be easy to onboard new person in any team if we all follow the same standards.

To build resilient microservices, we also need to make sure we have taken care of following things:

  • Interservice Communication
    Microservices are loosely coupled and they still need to talk to each other. Choose appropriate tech stack for Synchronous(eg. REST, gRPC) and Asynchronous(e.g. Messaging systems like RabbitMQ) communication. Consider latency while choosing the protocols.
  • Timeouts
    What if some service is not responding timely? How long to wait?
    E.g. Service X requests service A for something. Service A takes some to build the result and attempts to return back the result to service X. But service X is no longer there. The connection has timed out already.
  • Failure Handling and Recovery Strategies
    What if some service is not able to process request at this point of time due to some error? What if some service is not available? What message do we show to the users?
    We might need to have failure recovery strategies like rolling back to previous working state.
  • Observability
    We should be able to look into how well the microservices are behaving.
    Metrics:
    You will need a place to look into how well the microservices are behaving. Metrics like response time, success rate, request volume, Memory/CPU Usages are super helpful in day-to-day monitoring.
    Tracing: A request has passed through multiple microservices and one of the microservice somewhere in-between is sluggish resulting large round trip time. We should be able to trace the request and see where it is going and how much time it is taking in each microservice to detect the sluggish one.
    There are tons of APMs(Application Performance Monitoring) tools out there which provide these features.
  • Debugging
    A request initiated from service X failed on service Z while passing through service Y. We should be able to look into the logs and determine where and why it failed.
  • Distributed Transactions and Rollbacks
    In a complex system, one event can trigger cascading transactions on microservices one after another. If any transaction fails somewhere in-between, we need a mechanism to identify at what point it failed and what transaction have already completed and then to roll back to previous state cancelling the successfully completed transactions too.

Start Small — Experiment— Evaluate — Decide
Starting with a single monolithic app is the best idea. Break it into just 2–3 services based on the need. You will be able to get a rough idea of what it looks like. Analyze the cost. Microservices architecture is fit for you if it allows developers to work faster, independently and efficiently across teams and also it is easier to package, deploy, manage the services independently and worth the cost. Don’t just switch into microservices because they are the current trend and everyone is doing.

Thank You!

Hope it was helpful! Please comment if you think there are other things which could be added to the list of things above.

References:
- https://blog.newrelic.com/engineering/distributed-monolith-vs-microservices/

--

--

Nirdosh Gautam
Devnetwork

Software Engineer | Go, Ruby, and AWS | My world revolves around Tech, Music, and Bikes.