Spring Boot Microservices Best Practices And Coding Style Guidelines.

Dasath Y V A T
MS Club of SLIIT
Published in
8 min readDec 10, 2023

Microservices architecture has gained significant popularity due to its ability to build scalable and modular applications. Spring Boot, a powerful Java framework, provides a comprehensive set of tools and features to develop microservices. However, to ensure the effectiveness and maintainability of your Spring Boot microservices, it’s essential to follow best practices and adhere to coding style guidelines. In this article, we will discuss some key best practices and coding style guidelines for Spring Boot microservices development.

The Single Responsibility Principle (SRP) and modularization are essential components of creating Spring Boot microservices. Let’s explore these ideas in more detail:

Breaking down your application into smaller, independent modules or microservices is known as modularization. Each microservice ought to be able to run independently and have a clearly defined role. This strategy has various advantages, such as:

· Scalability: Modularization enables you to grow individual microservices in accordance with their unique needs, improving resource allocation and performance.

· Maintainability: It is simpler to comprehend, maintain, and troubleshoot smaller, more focused microservices. Developers can individually work on several microservices without affecting others.

· Reusability: Well-designed microservices can be joined to provide new functionality or reused across several applications.

Single Responsibility Principle (SRP):

According to the Single Responsibility Principle (SRP), a class or component should only have one reason to change. It implies that each microservice should have a particular goal or set of capabilities when applied to microservices. This idea encourages reusability, maintainability, and loose coupling. Following SRP has several advantages, including:

more logical code organization A single responsibility makes the code more concentrated and simpler to comprehend, which reduces complexity.

Easy testing: Since you can test each microservice independently using fewer, more focused microservices, unit testing becomes more manageable.

Independence: Microservices adhering to SRP are flexible and agile because they may be developed, deployed, and scaled separately.

Consider using the following procedures in your Spring Boot microservices to successfully integrate modularization and SRP:

· Based on each microservice’s responsibilities and features, identify, and define distinct boundaries.

· Create well-defined APIs for communication between microservices, preferably utilizing RESTful principles.

· Make sure that each microservice can store its own data, handle its own business logic, and interact with other microservices.

· Align microservices with certain business domains by using domain-driven design (DDD) approaches.

· Use separation of concerns to make sure that each microservice handles a certain piece of the functioning of the entire program.

· You can make your Spring Boot microservices more scalable, manageable, and flexible by embracing modularization and SRP. This will allow for better development procedures and effective team cooperation.

Modular Project Structure

Modular Project Structure

- config: spring Configuration classes for all the modules

- dapr-components: dapr components file, such as for pushhubs, if you are using dapr for your app.

- data: domain data or value objects.

- persistence: entities and responsibilities for the database.

- qa: integration / functional tests

- rest controller: REST endpoints

- service: business logic

It is recommended to follow the following package structure within the module,

- src/main/java — Contains packages and classes of Java source code.

- src/main/resources — Includes resources that aren’t Java, including property files and Spring configuration.

- src/test/resources — Contains non-Java resources like property files and Spring configuration.

- src/test/java — Contains test source code packages and classes.

Use the customary packet sparingly. Make sure that everything is contained in a package with a meaningful name, including the entry point. This prevents wiring and component scan-related surprises.

Project Dependency Standards

· To make it simpler to upgrade and test newer versions, including the version numbers of any third-party dependent libraries that are NOT included in the Spring Boot BOM in the pom file’s properties/> section.

· DO list the versions of each plugin.

· Version numbers of the dependent libraries that are included in the Spring Boot bill of materials should NOT be specified.

· DON’T mix versions of libraries that are transitively dependent and libraries that are directly dependent in the same project. As an illustration, slf4j 1.5 and slf4j 1.6 are incompatible, hence we must prevent the project from compiling with mixed dependency versions. Running mvn dependency: tree to find incompatible versions of dependent libraries is one approach to be certain.

However, it is crucial to follow industry best practices to fully utilize the capabilities of Spring Boot and guarantee the success of your projects. Following these guidelines boosts overall development productivity while also enhancing the maintainability and scalability of your apps.

o Use a custom BOM to maintain third-party dependencies.

We are able to manage these external dependencies thanks to the numerous open-source projects that the Spring Boot project itself utilizes and integrates. However, some are not utilized in the project itself, necessitating the maintenance of the project version. It will be very difficult to sustain a big project with many unfinished modules. How do you do it? Spring IO Platform accomplishes that. It supports additional external open-source libraries while being a part of the Spring Boot project itself. To develop our own basic project platform-BOM, we might take inspiration from the Spring IO Platform. All business module projects should be presented as BOMs. As a result, you simply need to update the dependence’s version when upgrading a third-party dependency.

<dependencyManagement>

<dependencies>

<dependency>

<groupId>io.spring.platform</groupId>

<artifactId>platform-bom</artifactId>

<version>Cairo-SR3</version>

<type>pom</type>

<scope>import</scope>

</dependency>

</dependencies>

</dependencyManagement>

o Use automatic configuration.

The application of auto-configuration is a key component of Spring Boot. This aspect of Spring Boot makes your code simpler and more functional. When a particular jar file is found on the classpath, autoconfiguration is initiated.

To use it, you should rely on Spring Boot Starters. Therefore, you may start by including: if you want to integrate with Redis.

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

If you want to integrate with MongoDB, you need this:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-mongodb</artifactId>

</dependency>

These tedious configurations are properly integrated and function as a unit with the aid of these starters, and they have all been tried and tested. This will help you stay out of the dreaded Jar hell.

o Use Spring initializer to start a new Spring boot project.

(“This best practice is from josh long”)

A new Spring Boot project can be easily created with the help of Spring Initializer, which can also load any necessary dependencies ( https://start.spring.io/ ).

You can be sure that the dependencies you receive when building an application using Initializer are tested and proven to operate with Spring auto-configuration. Even new integrations that you may not have known about could be found.

o Design the code directory structure.

Although you have a lot of freedom in how you build your source code organization, there are some fundamental guidelines to keep in mind.

Stay away from default packages. To prevent surprises during component scanning and assembly, make sure everything is packaged clearly, including your entrance point.

Keep the application’s entry class, Application.java, in the top-level source directory.

Although it is not required, I advise placing controllers and services in function-oriented modules. Several excellent developers advise combining all the controls. Always keep to one style!

o Ensure that the database is independent of the main business logic.

Before, I wasn’t sure how to handle database interactions in Spring Boot in the best way possible. It became much more evident to me after reading “Clear Architecture” by Robert C. Martin.

You want to keep the service and your database logic distinct. In an ideal world, you wouldn’t want the service to know which database it’s communicating with, therefore object persistence needs to be abstracted.

“Robert C. Martin strongly states that your database is a “detail”, which means not coupling your application to a specific database. Few people would switch databases in the past, and I’ve noticed that using Spring Boot and modern microservice development makes things much faster.”

o Keep business logic out of spring boot code.

You should safeguard your business logic by considering the principles learned from “Clear Architecture”. It’s incredibly tempting to combine different types of Spring Boot code. Avoid doing it. Your business logic will remain reusable if you can resist the urge.

Usually, the service includes a library. without having to remove many Spring annotations from your code, and easier to design.

o Constructor injection is recommended.

(“This best practice is from josh long”)

Utilizing constructor injection is one method to protect your business logic from Spring Boot code. The @Autowired annotation on the constructor is not only optional, but it also makes it simple to instantiate beans without Spring.

o Provide global exception handling.

You need to handle exceptions in a consistent manner. Spring Boot offers two primary methods:

1. To define a global exception handling approach, utilize the HandlerExceptionResolver.

2. The @ExceptionHandler annotation, which may be helpful in some cases, can also be added to the controller.

o Use a logging framework.

You presumably already know this, but instead of manually using System.out.println() for logging, you should be utilizing Logger. With little to no setting, this is simple to accomplish with Spring Boot. Obtain only the class’s logger instance:

Logger logger = LoggerFactory.getLogger(MyClass.class);

This is crucial since it enables you to specify various logging levels in accordance with your requirements.

o Use Lombok

You’ve probably heard of the Lombok project if you’re a Java developer.

With the help of its annotations, the Java library Lombok can help you write cleaner, shorter code.

For example, in some classes like entities, request/response objects, dtos, etc., you may need a lot of lines for getters and setters.

However, if you use Lombok, it only takes one line, and you may use @Data, @Getter, or @Setter depending on your needs.

Annotations from the Lombok logger are also available. @Slf4j is advised.

o Test the code.

Test your code! Although this is not exclusive to Spring Boot, it must be emphasized. You write legacy code from the beginning if you don’t write tests.

Your codebase will become dangerous to change if someone else uses it. When several services are interdependent, this can become extremely riskier.

Since there are Spring Boot best practices, you should think about adopting Spring Cloud Contract for your consumer-driven contracts because it will facilitate your service integrations with other platforms.

Writing Spring-based microservices has never been simpler thanks to Spring Boot. I hope that by using these best practices, your implementation process will eventually become more robust and successful in addition to being faster.

--

--