Today I would like to suggest a less-common but in my opinion a much better way to organize our codebase. Meet the Feature Folders.
For ages we have been (at least in the .NET environment) used to thinking about our code structure taking into account the technical aspects. For example MVC application project templates assume the division our objects into separate directories - Controllers, Views, Scripts and so on. We can see the same in many tutorials. If we need add new feature, following this approach we should add all objects in different places.
This approach is found not only on the application layer but on others too. I have seen many times in the business logic layer the big folders called Aggregates, Entities, Domain Events with a lot of classes unrelated to each other. But what does it mean “unrelated”?
We can specify 2 types of relationships between objects - technical and business.
Technical relationship tells whether two objects have similar meaning from technical perspective. That is, whether they have the same usage. Two controllers are technically related, but controller and application service are not related - their purpose is different.
Business relationship tells whether two objects support the fulfillment of the same use case. These can be definitely different objects from a technical point of view - for example: a validator and a command handler.
Let’s see how technical folders can look like:
What is the problem with this design? As you can see, we have three modules: Commands, Handlers and Validators. Each of these modules has very low cohesion because as Wiki says:
cohesion refers to the degree to which the elements inside a module belong together
For example the new requirement appears and we need add new attribute which can be editable. We need change all of three objects associated with editing so in this particular design we need change all three modules as well. The same if we would like to move all functionality to a separate service. This is not good. We have to try achieve as high cohesion as possible.
The solution is to stop thinking about the technical aspects of our objects and focus instead on the business relationship. It will provide high cohesion with all its benefits (maintainability, reusability, less complexity and so on).
For every feature/use case we should create separate Feature Folder with all related from business perspective objects:
The same rule applies for business logic layer and I think it is even more important here. We should design our domain model per aggregates:
This is very simple approach but improves our design and especially in projects with many features makes work definitely easier.
There is an extra bonus. With this design we create templates for later requirements. For example if we need add implementation for adding a new product, we can copy paste whole feature folder, rename objects and we know exactly what we have to implement. Great!
In this post I showed what Feature Folders are. By good codebase organization we can achieve more better and elegant design. If you still use “technical folders” I encourage you to try this solution - you will not regret it. :)