Monolith to Microservice

TosinJsTosinJs
5 min read

I recently completed the Udacity cloud developer course where I learned about microservices, CI/CD, AWS, Serverless, Docker, and Kubernetes. I have decided to put all the things I learned into practice by splitting up a project into microservices, deploying the application to AWS using Elastic Kubernetes Service (EKS), implementing observability, and finally making the entire application serverless. Join me on this journey.

Introduction to Microservices

Microservices are a software architecture pattern where an application is built as a collection of small, independently deployable services, each with its own unique business logic and independent data storage. This pattern allows each individual service to be developed, tested, deployed, and scaled independently.

Application development is made easier and more flexible with the microservice pattern as we can use different technology stacks for different parts of the application, this way each service can be built with the most appropriate tools required. Also, the services can be built and refactored independently without having to worry about breaking other parts of the project.

The fact that the services are independently deployed allows us to scale each service based on their requirements, allowing us to save computing power and cost. This independence also implies that the failure of one service does not necessarily bring down the entire application.


The Project

Taskman: This is a task management service that allows users to perform basic CRUD operations on tasks. It also has the functionality to send notifications to users when their tasks are due. Also, as you would expect, it allows users to be onboarded unto the platform. This project was initially built using the monolith architecture with all the code written in Golang.

Project Flow.

Users signup on to the application, and get an access token. This token can be used to access all CRUD task operations on the platform. Each task has a due date and the user also has the option of setting a reminder date. The Notifications service is responsible for sending Notifications to the users when a task is expired or on the reminder date set by the user. Check it out here.


Splitting the Monolith into Microservices

Define each microservice: In this stage of the project, this is where the concerns, responsibilities, and scope of each service are explicitly defined. Each service is supposed to handle a unique set of tasks. For my project, there are three obvious services. These are:

  1. Users Microservice: This service is responsible for all things related to user onboarding. It contains functionality to create users, user email verifications, password resets, and role base access.

  2. Tasks Microservice: This microservice is responsible for all the CRUD task operations, this service is the heart of the project as this is where all the core business logic is done.

  3. Notifications service: This service is responsible for sending notifications to the users based on their reminders or when they have a due task.

Refactor the Application: This involves decoupling each of the services and placing them in their respective directories.

Evaluate the tools/stack for each service: In this stage, the tools and stack used to build each service are evaluated and optimized depending on the requirements of the service. The Microservice approach allows us to use different stacks and tools for the different services, so you get to optimally pick your tools based on the needs of each service. The stack chosen for each of my microservices is discussed below:

  1. Users Microservice: This service was built using NodeJs (NestJs). MongoDB was chosen as the database for this service as there are no complex queries required here so a NoSQL database would do just fine. Redis was also used to cache the user refresh tokens.

  2. Tasks Microservice: The tasks service was built using Golang (Gin) and PostgreSQL for the database. This service was built using the domain-driven design approach.

  3. The Notifications Service: The notifications service was built using Golang (Gin), Firebase Cloud Messaging (FCM), and MongoDB. For a detailed overview of why MongoDB was used for this service check out this article that explains the notifications service.

Define a means of communication: Ideally, each of these services is standalone and independent, but you need them to come together as one unit for you to achieve your business goals. Hence you must find a way to tie up all these services together. There are various ways to tie up your microservices together, such as Rest APIs, gRPC, Webscokets, Message Brokers, and Event Queues.

In this project, the users' service serves as the entry point to the application and it supplies the users with the right credentials required to access the rest of the application.

The Task service and the notifications service are tied together via an AMPQ message broker. Each time a user's task is due the Users service publishes a message to the message broker, while the Notifications Service listens for new messages from the message broker and dispatches the notifications as need be. This is an asynchronous mode of communication such that the Tasks service does not need to wait for a response from the Notification service.

Define the APIs: In this part of the project you define which services are going to be available to the public (i.e the users of your application). These serve as the entry points of the public into your applications. It is important to note that not all services need to have user-facing APIs.


Splitting your application into microservices can make your application easier to develop and test but deployment can become rather tricky. Rather than deploying one single root application, now you have to deploy each of the services individually while ensuring that the services can still communicate effectively from end to end. Next up I will be deploying this application to AWS servers using docker and EKS.

0
Subscribe to my newsletter

Read articles from TosinJs directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

TosinJs
TosinJs

I am a software engineer who enjoys learning new stuff