How to Design Good Microservices Architectures

It may be difficult to know exactly what constitutes a well-designed microservice on your first assignment working with microservices. Many teams have fallen into the same trap of making their microservice too small or too tightly coupled.In this article, we will talk about the characteristics of a well-designed microservice and provide additional guidance to follow to overcome any common mistakes.

Characteristics of a Well-Designed Microservice

Don't fall into the trap of using arbitrary rules like “you should have x lines of code” or “turn your function into a microservice", etc. These rules often prove insufficient when it comes to determining the boundaries for your microservices.If you've read about microservices, you've no doubt come across advice on what makes a well-designed service. Simply put, high cohesion and loose coupling. While it's sound advice, these concepts are quite abstract.So how can you set the right boundaries for your microservices?I will guide you step by step, so let’s talk first about the true characteristics of microservices:

1: A well-designed service doesn't share database tables with another service

When it comes to designing a microservice if you have multiple services referencing the same table, that’s a red flag, as it likely means your DB is a source of coupling.Each service should rely on its own set of underlying data stores. This allows us to centralize access controls, audit logging, caching logic, etc.

2: A well-designed service has a minimal amount of database tables

The ideal size of a microservice is to be small enough, but no smaller. And the same goes for the number of database tables per service, "one or two database tables for a service."An example of an ideal microservice is one that handles and keeps track of millions and billions of entries around suppressions, but it's all very focused just around suppression so there's really only one or two tables there.

3: A well-designed service is thoughtfully stateful or stateless

Always ask yourself whether your service requires access to a database or if it's going to be a stateless service processing terabytes of data like emails or logs. Be clear about this upfront and it will lead to a better-designed service.

4: A well-designed service's data availability needs are accounted for

When designing a microservice, you need to keep in mind what services will rely on this new service and what’s the system-wide impact if that data becomes unavailable. Taking that into account allows you properly design data backup and recovery systems for this service.Here are some keys to maintaining a high level of data availability:- Have a plan – include RPO (recovery point objective) and RTO (recovery time objective) targets that define, respectively, exactly which data must be restored.- Employ redundancy – Having backup copies of your data ensures that you won’t result in permanent loss of information.- Eliminate single points of failure.- Take advantage of virtualization.

5: A well-designed service is a single source of truth

Always keep in mind whenever you design a service to be the single source of truth (SSOT) for something in your system. Deployment of an SSOT architecture is becoming increasingly important in enterprise settings as a way of greatly minimizing the risk of retrieval of outdated, and therefore incorrect, information. A common example would be the electronic health record, where it is imperative to accurately validate patient identity against a single referential repository, which serves as the SSOT.The benefits of getting to a single source of truth, of course, are enormous.1. It can catapult an organization to become one that is truly data-driven.2. The quality of data increases, fewer mistakes in communication are made.3. Costs of errors are decreased.After applying the characteristics, what to look at?Once you’ve applied the above characteristics, you should take a step back and determine whether the service you’ve created is too small or not properly defined.During the testing and implementation phase of your microservice system, there are a number of indicators to keep in mind:

  • Look out for is any over-reliance between services. If two services are constantly calling back to one another, then that's a strong indication of coupling and a signal that they might be better off combined into one service.
  • The overhead of setting up the service outweighs the benefit of having it be independent. There's a huge foundation of things that have to exist in order for an app to just run. For instance, you need to have a standard procedure to run when things break and how you can properly handle it.

What was the impact of microservices on a company like Amazon?Amazon is a perfect example of a large organization with multiple teams. Jeff Bezos issued a mandate to all employees informing them that every team within the company had to communicate via API. Anyone who didn't would be fired.This way, all the data, and functionality was exposed through the interface. Bezos also managed to get every team to decouple, define what their resources are, and make them available through the API. Amazon was building a system from the ground up. This allows every team within the company to become a partner of one another.

Example of a successful microservice:

Let’s consider this project with the Following structure that we will create:

src main java window

Let’s break it down :

  • StudentController.java - Rest controller exposing all the three service methods discussed above.
  • Course.java, Student.java, StudentService.java - Business Logic for the application. StudentService exposes a couple of methods we would consume from our Rest Controller.
  • StudentControllerIT.java - Integration Tests for the Rest Services.
  • StudentControllerTest.java - Unit Tests for the Rest Services.
  • StudentServicesApplication.java - Launcher for the Spring Boot Application. To run the application, just launch this file as Java Application.
  • pom.xml - It contains all the dependencies needed to build this project. We will use the Spring Boot Starter Web.

Then we will create a REST service with Spring Initializr. We will use Spring Web MVC as our web framework. (Spring Initializr http://start.spring.io/ is a great tool to bootstrap your Spring Boot projects.)

navigation menu

Now we need to implement Business Service for the application. All applications need data, but instead of talking to a real database, we will use an ArrayList - a type of in-memory data store.A student can take multiple courses. A course has an id, name, description and a list of steps you need to complete to finish the course. A student has an id, name, description and a list of courses he/she is currently registered for. We have StudentService exposing methods to:

  • public List<Student> retrieveAllStudents() - Retrieve details for all students
  • public Student retrieveStudent(String studentId) - Retrieve a specific student details
  • public List<Course> retrieveCourses(String studentId) - Retrieve all courses a student is registered for
  • public Course retrieveCourse(String studentId, String courseId) - Retrieve details of a specific course a student is registered for
  • public Course addCourse(String studentId, Course course) - Add a course to an existing student

Then we will add a couple of GET Rest Services

  • The Rest Service StudentController exposes a couple of Get-Services.
  • @Autowired private StudentService studentService : We are using Spring Autowiring to wire the student service into the StudentController.
  • @GetMapping("/students/{studentId}/courses"): Exposing a GET Service with studentId as a path variable
  • @GetMapping("/students/{studentId}/courses/{courseId}"): Exposing a GET Service for retrieving a specific course of a student.
  • @PathVariable String studentId: Value of studentId from the URL will be mapped to this parameter.
programming script

Let’s execute the Get-Service Using Postman, we will fire a request to http://localhost:8080/students/Student1/courses/Course1 to test the service. The response is as shown below.[pastacode lang="cpp" manual="%7B%0A%0A%22id%22%3A%20%22Course1%22%2C%0A%0A%22name%22%3A%20%22Spring%22%2C%0A%0A%22description%22%3A%20%2210%20Steps%22%2C%0A%0A%22steps%22%3A%20%5B%0A%0A%22Learn%20Maven%22%2C%0A%0A%22Import%20Project%22%2C%0A%0A%22First%20Example%22%2C%0A%0A%22Second%20Example%22%0A%0A%5D%0A%0A%7D" message="" highlight="" provider="manual"/]You can use a tool like Postman to execute this service :

builder authorization type body

Adding a POST Rest Service: a POST Service should return a status of created (201) when the resource creation is successful.@PostMapping("/students/{studentId}/courses"): Mapping a URL for the POST Request@RequestBody Course newCourse: Using Binding to bind the body of the request to Course object. ResponseEntity.created(location).build(): Return a status of created. Also, return the location of created resources as a Response Header.

programming script

Let’s execute a POST Rest Service, it contains all the details to register a course to a student:[pastacode lang="cpp" manual="%7B%0A%0A%22name%22%3A%20%22Microservices%22%2C%0A%0A%22description%22%3A%20%2210%20Steps%22%2C%0A%0A%22steps%22%3A%20%5B%0A%0A%22Learn%20How%20to%20Break%20Things%20Up%22%2C%0A%0A%22Automate%20the%20hell%20out%20of%20everything%22%2C%0A%0A%22Have%20fun%22%0A%0A%5D%0A%0A%7D" message="" highlight="" provider="manual"/]The URL we use is http://localhost:8080/students/Student1/courses

programming script

Recap

Designing microservices can often feel more like an art than a science, and a lot of the advice out there is fairly abstract, leading to confusing discussions.The microservice architecture enables the rapid, frequent and reliable delivery of large, complex applications. It also enables an organization to evolve its technology stack.If you have additional questions, feel free to leave comments under this post.

Related posts

The latest articles from Andela.

Visit our blog

Overcoming the Challenges of Working With a Mobile FinTech API

Andela community member Zzwia Raymond explores why, despite the potential of the MTN Mobile Money platform and its API, there are technical hurdles, from complex documentation to enhancing functionality.

How Andela Transformed Tech Hiring in 10 Years

Celebrating 10 years of transforming tech hiring by unlocking global talent across Africa, Latin America and beyond, Andela has surpassed its original goal by training nearly 110,000 technologists and assembling one of the world's largest remote tech talent marketplaces.

What GPT-4o and Gemini releases mean for AI

The latest generative AI models from OpenAI (GPT-4) and Google (Gemini 1.5 Pro, Veo, etc.) promise improved capabilities, lower costs, and transformative applications across various industries by integrating advanced AI technologies into business operations.

We have a 96%+
talent match success rate.

The Andela Talent Operating Platform provides transparency to talent profiles and assessment before hiring. AI-driven algorithms match the right talent for the job.