To Micro or Mono – Pros and Cons of Both Service Architectures

DZone 's Guide to

To Micro or Mono – Pros and Cons of Both Service Architectures

Learn the advantages of both popular software architectures and their associated tools and frameworks.

· Microservices Zone ·
Free Resource

Over the last few years, discussions about building the right kind of solution for Internet-based applications often come up with a comparison between Monolithic applications and Microservices. Building the perfect solution and tooling around virtualization and clouds have accelerated the adoption of the cloud-based technologies. Some examples :

With the launch of Amazon Web Services (AWS) in 2006, we can get compute resources on demand from the web or the command-line interface.

With the launch of Heroku in 2007, we can deploy a locally-built application in the cloud with just a couple of commands.

With the launch of Vagrant in 2010, we can easily create reproducible development environments.

With tools like the ones above in hand, software engineers and architects started to move away from large monolith applications, in which an entire application is managed via one code-base. Having one code-base makes the application difficult to manage and scale.

Over the years, with different experiments, we evolved towards a new approach, in which a single application is deployed and managed via a small set of services. Each service runs its own process and communicates with other services via lightweight mechanisms like REST APIs. Each of these services is independently deployed and managed.

Let's go into the details:

Image title

Era of Monolith

Monolith is a technical term used to identify a particular type of application. A monolithic application has all of its components residing together as one unit. A web application is a software program running on a web server. An application consists of three main components, user interface(UI), database, and server.

The monolithic application contains all three of these components and is written and released as a single unit. Internally, the codebase might be modular, but the components are all deployed together and are only designed to work within that same application.

Let’s go back to the dawn of “internet” time, which was somewhere around 1995. At this time, you may have found yourself hoarding AOL CDs in order to connect to the internet, check your email, and for making crafts. As the years moved on and the internet evolved, the AOL CDs you were hoarding only became good for making crafts. The AOL CD contained an application, and that application was a monolith. It was a self-containing piece of software that was able to run independently on its own. In order to upgrade the version of AOL, you had to obtain a completely new CD and replace the program. This is how a monolith handles its software release cycle (the process of which an application is upgraded or modified) - the entire program must be replaced, and this is also how the first web applications were designed.

Fast forward to now and the purchase of a brand-new computer. This computer is preloaded with all sorts of great software and, upon connecting to the internet, you spend the first hour downloading and installing updates to that software. This software being updated is no longer a monolithic application, because parts of it can be updated piece by piece. This is an example of how the application changed from the days of the AOL CD.

Pros of monoliths:

  • Similar to desktop applications that were designed to be shipped via media like floppy disks or compact disks, and then installed to the desktop, monolithic web-based applications were designed at first to be self-contained and have everything the user needed to get their work done.
  • It can be easier to develop a monolithic application because all the functionality is in one place. And when tests are performed, even if the internals of the application are modular, externally there is only a single entity to test.
  • It is less complicated to make the application run on a server. The process of moving the application from a developer's laptop to a testing environment, and eventually to production, is generally defined as deploying software.
  • If there is increased demand for the application, then more copies can be deployed behind a system called a load balancer. The load balancer will then distribute requests to any available server.

Cons of monoliths:

  • As the application grows in complexity, in the lines of code, and in the number of features, the developers that have been around the longest can be the most effective to make changes. Yet, new developers take the longest to bring on board, because they need to learn a large system to be effective.
  • Since the application is so large now, the ability to make important changes become harder to do. A developer needs to test any change they are working on and test the entire system before they are confident to release their changes to production. As a result, it can be harder to adopt new technologies, because it would affect the entire system.
  • When the size of the application was smaller, it was quicker to deploy. Now that the application grew to a larger size, and started running on multiple servers, the time it takes to deploy is longer. Every change, large or small, requires that the entire application gets deployed again.
  • Time does not just increase when a release goes to production. Because it needs to be tested first. If it is already slower to deploy to production, it is slower to deploy to every environment that is used to test it before deploying it to production.
  • Monolithic applications certainly have their place when you have a simple application that serves a basic purpose. When your application needs to grow, change, and perform, the monolith will no longer be a good fit, and it will be time to investigate microservices.

Enter the Microservices

Individual parts of the application need to be divided into their independent functions. They also need to be able to connect with each other. Each of these small services (or microservices, as they became known) are small applications which contain well-defined pieces of what was once a monolith.

To work together, services will need to talk to each other. The rules for interaction between components are called an Application Programmer Interface, or API for short.

With monoliths, the various pieces of the application typically share a single database. Microservices normally do not share databases. Each microservice is responsible for its own storage. Communication between microservices is done via the API, rather than through a shared database.

Having a separate database for each service ensures loose coupling, which allows each service to fit together well. With this separation, you may decide some services need different databases than others.

Applications which have been divided across multiple services (and thus multiple servers) are called distributed systems. Some services are visible to the user, while others are only used internally by other services. The latter are called back-end services.

Pros of microservices:

  • Decomposing the application into more manageable chunks makes the entire codebase easier to understand, develop, and maintain. As your application grows, you can dedicate entire teams to particular services. These teams each focus on a single service, rather than your entire application.
  • As long as each component can stay loosely coupled with other services in the system, each team is free to develop as it sees fit. Thus, the barrier to adopting new technologies, frameworks, or languages is lowered.
  • Now, each deploy can be controlled at the service level, not at the system-wide level. By breaking apart the large, monolithic deployment into separate, smaller deployments, developers have an easier time to make a change, run the tests, and send it to production.
  • Even scaling each of the services is easier now. Each component can be monitored and have the correct amount of resources, instead of adding an entire server just to provide capacity for a few features. There is no language or technology lock-in. As each service works independently, we can choose any language or technology to develop it. We just need to make sure its API endpoints return the expected output.
  • Each service in a microservice can be deployed independently.
  • We do not have to take an entire application down just to update or scale a component. Each service can be updated or scaled independently. This gives us the ability to respond faster.
  • If one service fails, then its failure does not have a cascading effect. This helps in debugging as well.
  • Once the code of a service is written, it can be used in other projects, where the same functionality is needed.
  • The microservice architecture enables continuous delivery.
  • Components can be deployed across multiple servers or even multiple data centers.
  • They work very well with container orchestration tools like Kubernetes, DC/OS and Docker Swarm.

Cons of microservices:

Just like any other technology, there are also challenges and disadvantages to using microservices:

  • It can be harder to troubleshoot separate services than it is with a monolith. This can be overcome if you have the right tools and technology in place.
  • Each microservice in your system is responsible for its own database or other storage. This creates the potential for data duplication across the services. The solution to this is (a) drawing service boundaries in the right places and (b) always ensuring that any particular data have a single source of truth.
  • Microservice application testing is more complex than testing a monolith. If service A relies on service B, then the team testing service A must either provide an instance of service B to test against or provide a simplified version of B as a placeholder. These placeholders are called stubs.
  • Dividing things into its smaller parts can be taken too far. You will know you have gone too far when the overhead (communications, maintenance, etc.) outweighs its utility. Instead, see if you can combine the service back into another that is similar.
  • While breaking the monolith application or creating microservices from scratch, it is very important to choose the right functionality for a service. For example, if we create a microservice for each function of a monolith, then we would end up with lots of small services, which may bring unnecessary complexity.
  • We can easily deploy a monolith application. However, to deploy a microservice, we need to use a distributed environment such as Kubernetes or Docker.
  • With lots of services and their inter-dependency, sometimes it becomes challenging to do end-to-end testing of a microservice.
  • Inter-service communication can be very costly if it is not implemented correctly. There are options such as message passing, RPC, etc., and we need to choose the one that fits our requirement and has the least overhead.
  • When it comes to the microservices' architecture, we may decide to implement a database local to a microservice. But, to close a business loop, we might require changes on other related databases. This can create problems (e.g. partitioned databases).
  • Monitoring individual services in a microservices environment can be challenging. This challenge is being addressed, and a new set of tools, like Sysdig or Datadog, is being developed to monitor and debug microservices.
  • Even with the above challenges and drawbacks, deploying microservices makes sense when applications are complex and continuously evolving.

Both the development and delivery of web applications have changed over the last twenty years. To deliver modern web applications, developers are delivering to the cloud. And that requires what is called a cloud-native approach. All that means is that the system will be split into many parts, then distributed to multiple pieces, and communicated over the internet.

cloud native ,microservices ,monolith ,software architecture

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}