Spring Boot Best Practices for Developers

Spring Boot is a widely used and very popular enterprise-level high-performance framework. Here are some best practices and some tips you can use to improve your Spring Boot application and make it more efficient. This article will be a little longer, and it will take some time to completely read the article.

Proper packaging style

  • Proper packaging will help to understand the code and the flow of the application easily. 
  • You can structure your application with meaningful packaging.
  • You can include all your controllers into a separate package, services in a separate package, util classes into a separate package…etc. This style is very convenient in small-size microservices.
  • If you are working on a huge code base, a feature-based approach can be used. You can decide on your requirement.
Based on type

Based on feature

Use design patterns

  • No complaints. Design patterns are already best practices. 
  • But you must identify the place where you can use them. 
  • Please check this article to understand “how to use the Builder design pattern” in our Spring Boot applications.

Use Spring Boot starters

Image: https://www.merriam-webster.com/words-at-play/names-of-appetizers
  • This is a cool feature of Spring Boot.
  • We can very easily use starter dependencies without adding single dependencies one by one. These starter dependencies are already bundled with the required dependencies.
  • For example, if we add spring-boot-starter-web dependency, by default it is bundled with jackson, spring-core, spring-mvc, and spring-boot-starter-tomcat dependencies.
  • So we don’t need to care about adding dependencies separately.
  • And also it helps us to avoid version mismatches. 

Use proper versions of the dependencies

  • It is always recommended to use the latest stable GA versions.
  • Sometimes it may vary with the Java version, server versions, the type of the application…etc.
  • Do not use different versions for the same package and always use <properties> to specify the version if there are multiple dependencies.

Use Lombok

  • As a Java developer, you have probably heard of the Lombok project.
  • Lombok is a Java library that can be used to reduce your codes and allowing you to write clean code using its annotations.
  • For an example, you may use plenty of lines for getters and setters in some classes like entities, request/response objects, dtos…etc. 
  • But if you use Lombok, it is just one line, you can use @Data, @Getter or @Setter as per your requirement. 
  • You can use Lombok logger annotations as well. @Slf4j is recommended.
  • Check this file for your reference. 

Use constructor injection with Lombok

  • When we talk about dependency injection, there are two types.
  • One is “constructor injection” and the other is “setter injection”. Apart from that, you can also use “field injection” using the very popular @Autowired annotation.
  • But we highly recommend using Constructor injection over other types. Because it allows the application to initialize all required dependencies at the initialization time. 
  • This is very useful for unit testing. 
  • The important thing is, that we can use the @RequiredArgsConstructor annotation by Lombok to use constructor injection.
  • Check this sample controller for your reference. 

Use slf4j logging

  • Logging is very important. 
  • If a problem occurs while your application is in production, logging is the only way to find out the root cause.
  • Therefore, you should think carefully before adding loggers, log message types, logger levels, and logger messages.
  • Do not use System.out.print()
  • Slf4j is recommended to use along with logback which is the default logging framework in Spring Boot. 
  • Always use slf4j { } and avoid using String interpolation in logger messages. Because string interpolation consumes more memory.
  • Please check this file for your reference to get an idea about, implementing a logger. 
  • If you are in a micro-services environment, you can use the ELK stack.

Use Controllers only for routing

  • Controllers are dedicated to routing.
  • It is stateless and singleton.
  • The DispatcherServlet will check the @RequestMapping on Controllers
  • Controllers are the ultimate target of requests, then requests will be handed over to the service layer and processed by the service layer.
  • The business logic should not be in the controllers.

Use Services for business logic

  • The complete business logic goes here with validations, caching…etc.
  • Services communicate with the persistence layer and receive the results.
  • Services are also singleton.

Avoid NullPointerException

  • To avoid NullPointerException you can use Optional from java.util package.
  • You can also use null-safe libraries. Ex: Apache Commons StringUtils
  • Call equals() and equalsIgnoreCase() methods on known objects.
  • Use valueOf() over toString()
  • Use IDE based @NotNull and @Nullable annotations

Use best practices for the Collection framework

  • Use appropriate collection for your data set.
  • Use forEach with Java 8 features and avoid using legacy for loops.
  • Use interface type instead of the implementation. 
  • Use isEmpty() over size() for better readability. 
  • Do not return null values, you can return an empty collection.
  • If you are using objects as data to be stored in a hash-based collection, you should override equals() and hashCode() methods. Please check this article “How does a HashMap internally work”. 

Use pagination

  • This will improve the performance of the application. 
  • If you’re using Spring Data JPA, the PagingAndSortingRepository makes using pagination very easy and with little effort.

Use caching

  • Caching is another important factor when talking about application performance.
  • By default Spring Boot provides caching with ConcurrentHashMap and you can achieve this by @EnableCaching annotation. 
  • If you are not satisfied with default caching, you can use Redis, Hazelcast or any other distributed caching implementations.
  • Redis and Hazelcast are in-memory caching methods. You also can use database cache implementations as well.

Use custom exception handler with global exception handling

  • This is very important when working with large enterprise-level applications.
  • Apart from the general exceptions, we may have some scenarios and identify some specific error cases. 
  • Exception adviser can be created with @ControllerAdvice and we can create separate exceptions with meaningful details.
  • It will make it much easier to identify and debug errors in the future.
  • Please check this and this for your reference.

Use custom response object

  • A custom response object can be used to return an object with some specific data with the requirements like HTTP status code, API code, message…etc.
  • We can use the builder design pattern to create a custom response object with custom attributes.
  • Please check this article for your reference. 

Remove unnecessary codes, variables, methods and classes.

commented code in the production

  • Unused variable declarations will acquire some memory.
  • And also we better remove commented codes and unused methods, classes…etc because it will impact the performance of the application. 
  • Try to avoid nested loops. You can use maps instead.

Using comments

  • Commenting is a good practice unless you abuse it.
  • DO NOT comment on everything. Instead, you can write descriptive code using meaningful words for classes, functions, methods, variables…etc.
  • Remove commented codes, misleading comments, and story-type comments.
  • You can use comments for warnings and explain something difficult to understand at first sight.

Use meaningful words for class names, methods, variables, and other attributes.

  • This looks very simple, but the impact is huge.
  • Always use proper meaningful and searchable naming conventions with the appropriate case.
  • Usually, we use nouns or short phrases when declaring classes, variables, and constants. Ex: String firstName, const isValid
  • You can use verbs and short phrases with adjectives for functions and methods. Ex: readFile(), sendData()
  • Avoid using abbreviating variable names and intention-revealing names. Ex: int i; String getExUsr;
  • If you use this meaningfully, declaration comment lines can be reduced. Since it has meaningful names, a fresh developer can easily understand by reading the code.

Use proper case for declarations

  • There are many different cases like UPPERCASE, lowercase, camelCase, PascalCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case…etc.
  • But we need to identify which case is dedicated to which variable.
  • Usually, I follow classes — PascalCase, methods — camelCase, conststants — SCREAMING_SNAKE_CASE and fields — snake_case

Be simple

  • Always try to write simple, readable codes.
  • The same simple logic can be implemented using different ways, but it is difficult to understand if it is not readable or understandable.
  • Sometimes complex logic consumes more memory.
  • Try to use KISS, DRY, and SOLID principles when writing codes. I will explain this in a future article.

Use a common code formatting style

  • Formatting styles vary from developer to developer. Code style is also considered a change and can make code merging very difficult.
  • To avoid this, the team can have a common coding format.

Use SonarLint

  • This is very useful for identifying small bugs and best practices to avoid unnecessary bugs and code quality issues.
  • You can install the plugin into your favorite IDE. 

This is not the end. There are a lot of small tips and practices. Let’s look at them in the next articles. You can view the same article on my Medium profile.

Spring Boot Best Practices for Developers Spring Boot Best Practices for Developers Reviewed by Ravi Yasas on 4:35 PM Rating: 5

No comments:

Powered by Blogger.