How to apply SOLID Software Design Principles to Spring Boot Application (Part 1)
(skip first paragraph if you have already read other parts of this blog series)
This article is the first part of the blog series, dedicated to well-known software design principles, that evolved over time and were finally summarised by Robert C. Martin with initials of the corresponding principles. These principles guide us how to build well-designed software systems, giving best practices for arranging classes, functions, building blocks. We will look at each principle in depth and apply it to the Spring Boot Application. The idea is refactoring existing software based on these principles from architectural point of view.
The word S.O.L.I.D. stands for:
- SRP: Single Responsibility Principle
- OCP: Open-Closed Principle
- LSP: Liskov Substitution Principle
- ISP: Interface Segregation Principle
- DIP: Dependency Inversion Principle
This first part is about SRP. Before jumping to concrete example, let’s have some theory.
A module should be responsible to one and only one actor. Robert C. Martin.
Well, basically SRP states that, let’s say in java world each class should be responsible for doing one thing, accordingly it should change only for one reason. Isolating classes based on their responsibility area increases decoupling.
Decoupling is: two or more systems somehow work or are connected without being directly connected.
The class that is responsible for only one functionality is easy to understand, test and maintain. By “doing one thing” it is not meant that this class should do literally one thing. The class can do multiple tasks and have numerous methods (not too many!), but at the end of the day, all these should serve to one actor/stakeholder/use case/functionality etc.
This kind of highly cohesive class eliminates two potential problems in daily software development:
- Avoiding duplicates
- Decreasing merge conflicts
Cohesion is: the degree to which the elements of a certain module belong together
So let us look at concrete example, where a Spring Boot Application of cash flow management is presented. At the beginning, the app is just showing list of incomes and expenses, but in following parts of these blog series, we are going to add different functionalities to our program.
Below is given the class diagrams of cash flow management application in before/after modus. On the left side, there is initial form of application where classes like Controller, Service are doing multiple tasks, which is direct violation of Single Responsibility Principle by handling both incomes and expenses at same class environment. By refactoring these units based on single responsibility principle, the classes are structured to handle each only one single actor: In this situation: based on use cases. Income and expense are taken as separate use cases. At the end, we have got two streams of dependency/data flow based on income and expense.
For better understanding the structure and refactoring of above given class diagrams, I have linked the relevant git repository here. Basically, if you take a look at commits into master, the branch feature/srp-initial corresponds to initial form, whereas the second branch feature/srp-refactored is the refactored form.
The cash flow management application is based on Spring MVC module which adds REST capability to application to handle http requests. On the other side of the data flow, the application is using JPA specifications to connect to database. Take into account that, I constructed database connection based on local MySQL server. If you want to clone this repository and make it work locally, you need to configure database connection and additionally by creating some database tables on values using cashflow.sql file.
The second part is dedicated to OCP, open-closed principle.