Package By Feature

Package by feature folder structure

File organisation plays an important role in the discoverability of code and the overall cohesiveness of your application. It determines how easily developers can find the relevant pieces of code, and can make it clear at a glance which code relates to which.

There are two principle methodologies when organising a file structure for an application.

In package by type, code is grouped together on the basis of what role the code plays at a general level. For example, all web controllers are placed into a Controllers folder, events are placed into an Events folder, and so on.

This is a common way to get started, since it doesn’t require any specific knowledge of your application’s functionality. As such, it’s a natural way to start categorising code when building a new project. Further, frameworks usually default to this type of file structure because its independent of the type of application you’re building, so it works equally well for e-commerce apps as it does for social media apps. Since frameworks are built for general purpose, this is a sensible thing to do.

However, the problem as your app starts to grow and accumulate more code files is that developers have to jump around the file structure searching for relevant files, and forming a mental model of which code relates to which becomes complicated. The sheer mass of files slows the developer down, and becomes burdensome when adding a new feature, or revisiting an existing one.

Package by type example.

In package by feature, files are instead grouped together in terms of the feature they provide to the application. For example, all files relating specifically to the student registration feature are grouped into the same folder — perhaps a RegisterStudentController, a RegisterStudentHandler, a RegisterStudentRequest, a RegisterStudentResponse, and a StudentRegisteredEvent.

As such, when working on a particular feature, it’s easier for developers to know where to find relevant code, since it’s all in the same folder. Greater code discoverability also makes it easier for developers to form a mental model of all the moving parts pertaining to the same feature. Further, removing a feature often means simply deleting the feature folder and it’s contents, without having to hunt down the scattered pieces of code throughout the codebase.

Package by feature (web/presentation layer).

For feature-independent code (i.e. code that is shared between features), it still makes sense to use a conventional packaged by type approach. For example, it makes sense to group all web middleware together, since middleware isn’t tied to any particular feature. Further, it might still be useful to organise your application into separate layers such as a Web layer, a Domain layer, etc. In this case, a feature-based file structure could be employed within each individual layer, where appropriate.

The bottom line is that when building applications we are usually working on one specific feature or another, and so reflecting this in the file structure increases code discoverability and developer sanity.