5 things I wish I knew before building my first Springboot app
Doing something old with a new technology is never easy. Especially once you realize that most of your prior knowledge is irrelevant, while some of it might even be harmful.
In 2019 Fiverr started a large remodel of its infrastructure. The decision was to stop developing new backend microservices with Ruby and Rack and start developing them, instead, with Kotlin and Springboot. In my long struggle of coding my first Springboot microservice I’ve learned countless of lessons, and today, I will share some things you should know before developing your first Springboot application.
Spring Boot Layering
When I coded microservices in ruby there was no real separation between the database and the APIs. My API handlers could directly access ORMs, just like the business logic, everything was just one layer and different concerns were always tightly coupled to one another.
In Springboot you are expected to have logical separations between the layers to reduce tight coupling and allow business changes to be as independent as possible from infrastructure changes. This means, given a correctly layered code, you are free to change your APIs and your databases without impacting the business.
Follow SRP by creating sublayers in the Business Layer
You can utilize layering in order to decouple business logic components and, as a result, each component is going to do only one thing. Let’s look at the following example diagram showing a payment flow executed by calling our apps API to authorize payment via Stripe.
By splitting the business layer into 3 different layers of services we ensure that:
- We follow DRY in case some code needs to change for all payment providers
- We follow SRP. When communication with Stripe changes, only Stripe communication related service changes
- We decouple infra from the business. When we decide to change our Rest client, no changes in Stripe or Pay service files are necessary
Understand how Dependency Injection works
Dependency injection is a fundamental aspect of the Spring framework. Since this is something that does not exist in Ruby, I found myself deep in a rabbit hole of Spring DI.
The concept is pretty simple. You have Inversion Of Control which means letting the framework manage part of your program (specifically, building objects). Then you use Dependency Injection to implement the code needed for the framework to manage your program.
Spring framework allows you to use the @Bean annotation to create your own constructor based DI as Singleton. Once a Bean is defined, your application will create an instance once and cache it, injecting it into each component requiring it as a dependency.
Understanding the main annotations
Once you got the hang of IoC and DI, the next step in writing and understanding Springboot code is learning the basic Annotations. This will allow you to gain deeper understanding of how exactly your components function, what’s their scope, how they are configured and more.
You can read about many annotations here, but to save you the trouble of reading everything, here are the most used annotations from my own experience: @Autowired, @Qualifier, @Configuration, @Bean, @Value, @Component, @Service, @Repository.
Mocking external APIs with WireMock
Since my code calls a bunch of external APIs for different payment services, I found myself having to mock them in my integration tests. This proved to be a nuisance since I had to build my own testRestTemplate and override multiple layers of DI manually to make sure it reaches the proper bottom layer.
The solution I found was to use an external library named WireMock which sets up a mock server locally and allows to easily define requests and responses. After setting this server up and defining the mocks, all that needs to be done is changing the url path for the test, and you are done!
For my tests I’ve used the JUnit 5 extension for WireMock for which you can find the documentation here.