mariossimou.dev
HomeBlogContact

Introduction to Modern Application Development - inspired by AWS conference

Published on 6th November 2022

Front-end DevelopmentBack-end Development

Introduction

On 15th of October 2020, AWS was organising a Dev Day conference that I attended to. The conference's agenda was splitted in three different sessions, with each attendee to pick one of them. I chose to attend on "I am Building Applications" session, however, the introductory presentation, which was shared between all three sessions, triggered my interest for writing this post. The topic of the presentation was around microservices and monolithic applications, and since AWS has experience running softwares in a large scale, they encourage developers to decompose monolithic applications to smaller independent, easy to deploy, scalable units. However, these changes come with a cost, and we will discuss them later in the article. Therefore, in this post I will be talking about microservices and monolithic applications, as well as to point pros and cons of each architecture.

Distributed Systems

In simple words, a distributed system is any application composed from more than one services, which most likely will be sitting on different machines or containers. However, even if distributed systems run in different processes, they are coordinated to deliver a coherent system to the end-user. Some common architectures of distributed systems are:

  • 3-tier-architecture: The typical structure of a 3-tier-architecture comprises the Presentation, Application and Data layer. The former one refers to the UI interface and it's the part of the software that the user can see and interact. The Application layer includes a server running on the back-end, which usually gathers most of the business logic, and is the connection link between the UI interface and the data stored to the database. The Data layer consists of a database system, where data is stored either with a structured or unstructured manner.  

  • Client-server: The presentation and application layers are separated and can be thought as a two-tier architecture.

Both monolithic applications and microservices fall within the category of distributed systems.

Monolithic Applications

A monolithic application has been the most common type of application you would see in the industry the last two decades, and in it simplest form includes a client and server-side application and a database. If you are thinking of 3-tier architecture, then you are right. The 3-tier architecture it's the simplest example of a monolithic application, and this can even packed down into two layers, considering that client and server are combined to a server-side rendered application.

But, you may be thinking as well, why monolithic since there are at least 2 components in the architecture and mono gives you the impression of a single unit? The meaning of monolithic targets the service that handles the business logic and this is the server-side application. The server-side application is responsible to fetch data from the database, handles HTTP calls from the client and performs any domain-specific logic.

Although this design works well in small-scale applications, things get a bit difficult when the application grows and changes happen frequently. For example, developers will be working on the same codebase, which may result in code changes that may overlap one to another. Although, this can be avoided by introducing modules to your codebase – this may mean to split your business logic in different modules and assign a specific module to each member of the dev team – , which adds a layer of separation between different parts of the code, this separation is still imaginary and can be offended. In addition, to deploy new features, you need to re-deploy the whole application, which means that deployments are less frequent and need to be orchestrated.

Monolithic applications also require to use the same technology stack, making less likely for you to pick the right tool based on the work you are aiming for. For instance, if you decide to use a relational database system, this system will be used for any data you store.  Lastly, since the whole logic is bundled in a single program, new developers in the team will need more time to understand and perform changes to the code. This may slow down productivity, which means mooney.

Nonetheless, a monolithic application is the simplest form of application and includes the fewest moving parts. This means that the first version of your application will be delivered much faster, however, when it starts to grow, this advantage starts to fade. In addition, there will be fewer services for you to pay and maintain, and for an application that has just been launched, this is the right approach. Moreover, applying patterns like splitting your application's structure into modules and maintaining these decision boundaries, can prolong the duration and the benefits adopted from this design.

Microservices Architecture

While a monolithic application has a single service to handle the business logic, a microservice architecture follows a different direction. In this architecture, the aim is to decompose the business logic into multiple, independent services that have a single responsibility. The diagram below shows how an application can be organised using a microservice architecture.

However, it's not an easy task to split your application into smaller services. In addition how do you ensure that you are doing microservices the right way? Fortunately, Sam Newman reports on his book 7 key principles that will at least point you to the right direction:

  • Model Around Business Concepts: We have mentioned that microservices is all about splitting your business logic into smaller services, but how you determine the boundaries between them? Experience has shown that services structured around business-bounded contexts are more stable than structured around technical concepts. For that reason you will also see microservices been called as a domain-driven design (the application design comes down to subdomains).

  • Adopt a Culture of Automation: Since microservices add a lot of complexity, it is wise to automate everything, starting from testing your application to deploying it to production. No human intervention should be involved in any phase.

  • Hide Implementation Details: Since multiple services will exist to support the application, each service should have it's own API and should be the only way for someone to access it. This also means that each service should have it's own data storage and will be responsible for storing and updating information. If anyone else wants to access it, he/she should go through the API endpoints. In addition, it's a good practise for services to use a consistent format for exchanging data – most common option is JSON –

  • Decentralise All The Things: Distribute the services ownership to teams and make them feel that the service belongs to them. This structure is really helpful for distributing workload to teams, with each team to own a service.

  • Deploy Independently: A service is responsible for testing and deploying itself in production. This brings to the table concepts like Continuous Integration (CI) and Continuous Delivery (CD). This principle also ensures that each service can be deployed at any point in time, without been dependent on other services. In addition, more deployments with more features will be delivered in smaller intervals as well.

  • Isolate Failure: Although we split the application into multiple services, this doesn't ensure that dependencies between services won't evolve. If you identify a point of coupling, try to resolve it because a failure in one service will cascade to the other. Adding timeouts and circuit breakers will help you mitigate this issue.

  • Highly Observable: A microservice architecture cannot work without a monitoring system. Log and aggregate your information to a dashboard so that you understand the behavior of your services.

As you may notice, building a microservice architecture is not an easy task and requires a lot of effort and work to add the right tools at the right place. There are far more moving parts compared to a monolithic application, however, if you do it right, the benefits that you get are worth the time invested.

Summary

In summary, a monolithic application consists of a single unit of software that does all the work for all the tasks related to it. This ensures simplicity, low costs of maintenance and deployments. However, as the application grows, those benefits start to fade. On the other hand, microservices have a lot more complexity and require more effort and time to get them right. However, it's a design that will benefit you in the long-run, distributing the workload into multiple smaller services. Each service can act independently, meaning that each service has it's own development, testing and deployment cycle.

Sources:

Designed by
mariossimou.dev
All rights reserved © mariossimou.dev 2023