What have we built so far for our social media platform? We have the ability to upload and delete pictures. However, a key piece of any social media platform is to allow users to interact with each other. This is commonly done by either commenting on the social media content or chatting directly with each other.
Let's start by adding the ability to comment on images. But before we get going, let's stop and discuss the architecture.
For years, people have used the layer approach to split up applications. Fundamentally, we don't want a big application with all the classes in one package because it's too hard to keep up with everything.
So far, we have everything located in com.greglturnquist.learningspringboot. Historically, the pattern has been to split things up in a domain layer, a services layer, and a controllers layer, as shown in the following screenshot:
In this structure, we would put every service into the services subpackage and create further sub-subpackages if need be. We'd put all the domain objects in domain and all the controllers would go into controllers.
The idea was that controllers call services and services return domain objects. It prevented entanglements such as services invoking controllers, which made sense at the time.
But with the rise of microservices (something we'll dig into in Chapter 7, Microservices with Spring Boot), these layer-based approaches become an issue when the application gets really big. When refactoring is in order, services found in the same package that are functionally unrelated can get tricky due to needless coupling we may have created.
A more slim and trim approach is to break things up using vertical slices instead of horizontal layers:
With the structure shown in the preceding screenshot, we have split things up into images and comments, a more function-based nature.
We would put everything related to handling images in the former and everything related to comments in the latter. If the need arises, either of these packages can be further split up into subpackages, as follows:
Worried that this will cause an explosion of the domain/services/controllers trio all over our code? Don't panic! We only do this as needed, and given that each domain subpackage will be relatively small in scope as compared to the old layer approach, the functionality should be highly cohesive, that is, have much in common with each other.
Since we are about to create a separate piece of functionality (comments), it would make sense to go ahead and break up our application into images and comments. So let's do that!
First, let's create the images and comments subpackages. With that in place, the most obvious change is to move Image, ImageRepository, and ImageService into the image subpackage. Easy enough.
That leaves us with the following:
- LearningSpringBootApplication
- HomeController
- LearningSpringBootHealthIndicator
LearningSpringBootApplication embodies the entire app, so it should stay at the top level. This isn't just a semantic statement. That class contains our SpringBootApplication annotation, which enables the application's autoconfigured behaviors like component scanning. Component scanning should start at the top level and search all subpackages.
HomeController represents an interesting concept. Even though it calls into ImageService, since it serves the application's top-level view, let's leave it at the top level as well.
As for LearningSpringBootHealthIndicator, a similar case could be made to keep it at the root. Since we are shooting to keep things light at the top, why don't we create a separate module to encompass all Ops-based features that aren't specific to any one module, ops.
Given all these decisions, our new structure now looks like this: