File structure is a significant part of the overall architecture and organisation of an application, though it often seems to get overlooked. Developers typically stick to organising their files/directories according to the type of code or class it hosts. For example, there might be one directory for Controllers, one for Events, one for Models, and so on.
This style of organising a project is called package by type. It is usually the default style for frameworks because there’s really no other style a framework could provide as a template. After all, frameworks are designed to be general-purpose and suit the needs of all kinds of projects. They don’t know whether you’re building a student management app, an e-commerce app, or a video-on-demand SaaS platform, so they can’t structure your project according to specific concepts like Students, Videos, Products, and Orders. (Chances are you’re building yet-another-todo app, though…). Further, they sometimes come with command line utilities for quickly generating templated code, and these utilities often rely on the framework’s conventions so that code is generated in the correct directory and with the correct namespace. It’s no wonder then that developers often stick with this approach and don’t know any different.
The problem with this approach is that the code for each use case within your app is spread out among a number of different directories, and each directory contains a tonne of files relating to all the different concepts and features that your app represents. As such, working on any given feature requires navigating back-and-forth through a scattered code base, thus slowing the developer’s productivity.
Wouldn’t it be nice if, when working on a feature, all the code for that feature was nested under one directory specific the that feature? If we didn’t have to jump around between directories so much? If CSS would just work uniformly across all browsers?
The picture below demonstrates this idea (well, not the bit about browser compatability):
See how much easier this structure is to find what you’re looking for? Not only is the directory structure neater, but it is easier to see at a glance the higher-level concepts that make your application, your application — it more successfully screams its architecture.
Package by layer
In truth, the picture above only shows one layer of an application: the web/presentation layer. If you are using a layered or hexagonal approach (which you should be), you would benefit from this kind of project structure within each layer/package where it makes sense to organise the code base into features. For example, let’s perform a similar refactoring of a DDD-style domain layer.
Note that it may not always make sense to do this if the code doesn’t so obviously lend itself to a feature-based approach. For example, you may have a persistence layer with only repositories and configuration code, and the idea of splitting the layer according to which type of entity a repository deals with seems like overkill. In such cases, you could just stick with the more conventional package-by-type approach for this area within your code base, and only re-arrange it according to feature if it becomes beneficial to do so.