Feature-first or Layer-first

Choose the approach based on project requirements and team size.

Feature-first or Layer-first

At this stage, let's talk about Project Structure. When a team or an engineer starts to build an application or system, no matter if engineer is alone or there are several of them in a team, there should be setup some rules to keep the codebase clean, maintainable and scalable.

Table of contents:

  1. Why do we need Project Structure?
  2. Layer-first approach
  3. Feature-first approach
  4. Conclusion
  5. What's next?

1. Why do we need Project Structure?

We told above that some rules should be setup when developing an application. The question is why we need them? Okay, there maybe several cases for system failure if some rules are not followed.

Firstly, a single junior engineer starts building an application, delivering features in a way he wants, not structuring properly, as fast as possible. The company is satisfied with the engineer's delivery of features. After a year of progress, business asks to change particular functionalities. The engineer has to go back to code he wrote a year or two ago and change it, but he can't remember why there's some part of the code, sees it is used in several places. He tries to change the code, but finds the second part broken, fixes the second part, first part is broken. Or maybe, he cannot find some class used in the feature. The thing is, he has been fast at delivering features for a year or two, but now he sees the codebase is out of control, very messy, not fixable - should be re-written. The system is neither maintainable nor scalable.

Secondly, let's say some maintainable issues are not faced yet. The company sees that development is starting to slow down and hires new engineer into project to speed up the development. However, the new comer clones and opens the project code, he understands nothing. He finds that classes used by feature are scattered around the project, those classes are re-used everywhere, finds some classes with thousands of lines of code that do many things. The outcome of the situation is, new engineer does not speed up the development.

There are many reasons to keep the codebase clean and that can be gained by structuring the codebase properly. Let's talk about two approaches for this: Layer-first approach and Feature-first approach.

2. Layer-first approach

Assume, you are developing small-mid application alone or in a small team. Then this approach is probably right for you.

When this approach is applied, we group the files based on their layer.

All Response/Request models from/to backend, API files, Local Storage files, Database files are stored in data directory.

All core entities, Use Cases, Repositories, Manager Classes, Exceptions into domain directory.

All screens, viewModels and their widgets into presentation directory.

These are just examples for each directory, of course, they are not limited with the provided example, there can be more. The folders and files can be named based on self preference as well.

Benefits:

  • straightforward: when a feature to be implemented, an engineer just creates files in data, domain, presentation layers; connect them; deliver feature.
  • less code: compared to feature-first approach, no extra data, domain directories for each feature are created.
  • clean: clear what files to expect from the directories.

Drawbacks:

  • code conflicts: since working in the same directories and files, sometimes conflicts arise in PRs.
  • difficult to navigate: we expect what files to find in directories, but it takes time to find files of a particular feature.

3. Feature-first approach

This approach is more beneficial for mid-large applications with many features with big team size, so that team can be divided into sub-teams and work on features separately.

To note, some engineers mistakenly think that each screen is a separate feature and they sometimes face bad headaches because of this wrong direction. So before proceeding, let's define what a feature actually is.

A feature is an action or set of actions to complete a task or flow. In terms of UI: it is not limited to a shown screen on the device, but can range from a small widget to a couple of connected screens that form a flow.

Example in a case of Yandex Go application:

  • authentication flow
  • destination selection flow
  • payment flow
  • history of last rides
  • contact support

When Feature-first approach is applied, we group the files based on the feature - each feature will have corresponding feature folder where data, domain, presentation folders exist.

Benefits:

  • almost no code conflicts: since working on different features in different directories with different files for each feature, it is difficult to create PRs that interfere with each other.
  • focus on feature: sub-team or engineer can be parted to work on a feature, so they'll have their corresponding directory (their world) to work on a feature; no need to worry about that new implemented feature may break somewhere else.
  • more clean: with this approach it is very easy to find necessary files; just open necessary feature-directory and apply changes.
  • separately testable: team working on a particular feature can write different types of tests on the feature without interfering the other part of the codebase.

Drawbacks:

  • more code: for each feature creating necessary directories and files maybe time-consuming, but for large codebase, it definitely worth it.

If necessary, Feature-first approach can be converted to Modular Architecture with more ease; I will write article dedicated to modular architecture in the future.

Conclusion

There is no strict go-to option when choosing between Layer-first or Feature-first approach for project structure. But considering the inputs like: application size, team size, number of features, we can choose one of the approaches that would be more beneficial for us that could help to ease navigation, reduce PR conflicts and increase maintainability and focus, increase the speed of development. At first glance, Feature-first is always more clean and elegant, but maybe overkill for a small application with limited features.

What's next?

In next articles, I will start building Google Browser application replicate applying layer-first approach and clean architecture.