Motivation
Would you ever asked yourself why we are creating packages in our projects, or what are possible ways to organize your classes and modules, is this packing way came by luck or there is a science behind it we will discuss all these questions here.
Designing good software structure
As software grows maintaining and organizing it became more difficult, and in order to keep the software more organized you have to design its structure in good way.
Designing good software structure requires some characteristics like intention revealing, components decoupling and ease of component replacement
Intention Revealing
By this we mean that when I look at the software components I can get some knowledge about what this software does.
Components Decouple
Here we should reduce coupling between components which offers to us ease of component replacement without a lot of problems.
In order to achieve these goals there are multiple architectural styles you can go with, and these architectural styles are meant by how you should organize your classes, packages and modules.
Package by layer
This is most popular and easy way to organize and style your software, in this style you have packages like controller, service, repository, model/entity or any components that represents layers like Presentation layer, Business Logic layer and Data Access Layer. Layers or components are built on top of each other and each layer is allowed to use direct below layer only as below image
and this is represented in your project as below
In order to achieve components decoupling it's common practice to start by using interfaces between layers like (JPA repositories) between Data Access Layer and Service/Business Logic layer. and interfaces between Service/Business Logic layer and Controller/Presentation Layer so you can easily swap between components and implementation.
This style is easy to implement, easy to understand and also easy to follow, but in another hand this style has some issues like it violates intention revealing, you can not get what is software does by just looking to its structure, you have to go deep dive with code to understand it, also there is another problem it's easy to follow but it's also easy to break, with deadlines and lack of experience you can bypass layers, and maybe some developers use Data Access Layer(Repositories) in Presentation Layer (Controllers) directly and this violate the entire style as below.
Package by feature
With this style you are repeating Presentation, Business logic and Data access layers with each feature you have, and you follow same rules that you have in package by layer style as below.
and this is represented in your project as below
By using this style your are gaining intention revealing for your software, by just looking to project structure you can gain good knowledge about what this software does, you also gain some focus when you are try to look at specific feature, now you know where exactly you should go and don't bother your self about other features, you may also suffer from bypassing layers but it's less than in Layered Architecture.
Package by component
In this style you are creating separate units of deployments like jar files in java or separate projects and combine this style with one of previous styles in each of these components/projects as below.
By using this style you are gaining flexibility of deploying features/modules as you wish, you can add or remove features and modules when you are delivering the software to the client and give your client flexibility to choose what modules he needs only.
Hexagonal style
This style is elegant and makes you focus on core business logic and defer implementation to another components that provides you implementation details, and most benefit from this style comes when you have multiple implantation providers.
As below image describes you are just writing the main core business logic and let other parts to complete the component or picture with specific implementation, then you can switch between them in easy way.
Ports and Adapters
Let's take an example to explain how this style can be achieved, let's say you have core functionality in your system that the manager can browse employees data after some manipulation done upon them, but also you have multiple clients and each client have its own data source, someone uses relational database some others uses excel sheets and so on.
So these are steps
you write generic code without pay attention to details and this can be done by depending on interfaces, these interfaces is called Ports (you are exposing them to defer implementation to another modules) and this will be the core functionality as below
Off course this code will not work with current state it is lacking of implementation of how we will get the employees, and to complete the functionality you need the adapters.
The Adapters representing the implantation of your Ports that exposed in your core logic so as per our example these are our adapters.
Relational DB adapter
Excel sheet adapter
And now with any Dependency Injection provider you are able to let your client to choose which adapter suits him and combine it with your logic then deliver your system in easy beasy way.
Resources
IF YOU LIKED THE POST, THEN YOU CAN BUY ME A COFFEE, THANKS IN ADVANCE.