Package by Feature is Demanded

In the DZone comments under my post about Layered Architecture, there have been voices that layering should be realized as what I call Packaging by Feature. I intentionally delayed writing about this to cover hexagons and onions first but now that we have those behind, we can jump straight into the so demanded architectural style.

What is Package by Feature?

In a typical Layered Architecture, code organization follows the horizontal decomposition created by dividing the system into layers. This is what is often called Package by Layer.

The problem with this approach is that cohesion inside each package is usually low and the coupling between packages is very high. This seems like exactly the opposite of what we want to achieve. At the same time, most people agree that separating the concerns of presentation, application, domain and infrastructure makes sense. Package by Feature capitalizes on both points by moving the layering a level down – to the class level – and focusing on coupling and cohesion at a higher level by keeping all classes related to the same feature in the same package/module:

You might wonder now what is a feature? It’s a valid question. I have seen different implementations and examples, varying from a feature meaning effectively one use case to feature meaning a whole set of operations related to a particular business concern. I have seen more of the latter when doing research for this article, but I don’t think it’s necessarily a good thing.

The Essence of Package by Feature

I see two things that form the essence of Package by Feature: maintaining high cohesion and low coupling at the package/module level and being able to say what an application does by looking at its package/module structure.

In a typical Layered Architecture, the cohesion inside a package is low and the coupling between the packages is high. We rarely change technologies or conventions regarding a particular layer, comparing to how often we add a single feature, hence low cohesion. And, in most cases, each class in a layer (package) depends on at least one class in another layer (package), making the coupling between them high. In Package by Feature style, we ideally change classes only in a single package – the one related to the feature we’re working on – so cohesion is high, and there are only a few dependencies between features, so coupling is low.

The two terms above are useful but, to be honest, these are nerd metrics. The more human side of Package by Feature is that you don’t have to be a nerd that knows every piece of a codebase to be able to say what it does – a quick look at the package/module structure should tell you that. This is one step towards what Uncle Bob calls Screaming Architecture.

Implementing Package by Feature

The name Package by Feature strongly suggests that you should implement this style by putting each feature in a separate package and that’s mostly true. The only caveat that I see is that it could also be a module, namespace or any other mechanism available in your language in case you’re not using Java.

The second important thing about Package by Feature is that when related stuff is in a single package, one can finally make some use of access modifiers i.e. make most of the things package-local instead of public. This way we can limit the public interface of our feature to just the things that we actually want to expose. In the Package by Layer style, this was not possible because related classes needed to communicate across packages, which forces us to make everything public.

Example

Even though I feel like Spring Pet Clinic is not the best resource to learn about software development from, it does a pretty good job at presenting a flavor of Package by Feature. The features, in this case, are sets of operations performed on same domain objects:

As you can see, we have three dominating features here – managing owners, vets and visits. Whether this decomposition into features is good or not, is a very complicated topic. At the moment, we should focus on the fact that classes representing different layers like controllers, repositories, and domain objects are all kept together, and that the package structure is more feature-oriented.

Benefits of Package by Feature

  • More Informative Package Structure – you can deduce some of the system’s main features or behaviors from the code structure
  • High Cohesion & Low Coupling – we explained this point already in the essence part, although a bit idealistically
  • Better Encapsulation – you can make effective use of access modifiers to hide the information that’s ought to stay hidden
  • Better Growth Potential, in the code volume sense – unless you develop too big or too small features, you shouldn’t encounter the problem of too big or too many packages

Drawbacks of Package by Feature

  • Unspecified Feature Size – I found no clear guidance or proof that one understanding of feature is better than the other
  • Learning Curve – the concept is simple, but since you need to find your own way to slice a system into features, mastering it can be really hard
  • Messiness Potential – in a tangled domain, in which everything is connected to everything, the slicing into features might become artificial and the low coupling promise might not be fulfilled

When to use Package by Feature?

Obviously, it can work for smaller applications, in which you can shuffle stuff around and try different things at a very low cost. At the same time, since it carries the promise of higher cohesion, lower coupling, and better growth potential, it seems like a perfect fit for bigger applications, which could actually suffer from the drawbacks of packaging by layer. Given its moderate learning curve i.e. the necessity to sort out the best definition of a feature, I’d be wary of using it for the first time when working on a critical application. I’d opt for dividing the problem into bounded contexts and implementing each one in a layered/hexagonal way instead.

Summary

Packaging by Feature is a really appealing idea and I’m totally not surprised that a lot of people push it forward. Our favorite nerdy metrics like cohesion and coupling seem good, and we can see what the application is doing by simply looking at packages. At the same time, I can see it’s drawbacks and the potential to become a huge mess if someone tries to use an artificial slicing into features in a tangled domain. If you know how to leverage its benefits effectively, go for it. If you don’t, be careful 🙂

About the Author Grzegorz Ziemoński

King of Tidy Java, nerd that thinks about producing perfect software all the time and proud owner of 2 cats.

follow me on:
  • Tim

    I like where this is line of posts is going 🙂
    Question: how should the different features interact with each other? For example, orders and catalog both need to now about products. Can services of one feature call services of another feature? Or do they pass completely through the controller?
    Perhaps I take this article too strict and a combination of hexagonal/onion and feature based is optimal 🙂

    • Me too 🙂
      I’d say that we should think about features as use cases i.e. pure application logic, without dragging in the underlying domain. Then, the features won’t likely need to communicate. They might contain common parts, which are called habits in Lean Architecture. Those might be extracted to separate classes and packages. To all my current knowledge, thinking about features as pairs of domain objects and related services is flawed, as one use case might require you to go through all domain objects in your system. In the end, we the system to guide the user through the use cases, not the user to call each individual object-related service in a way that ultimately leads to his goal.

  • Manu

    Very interesting articles, but you must use the same name and color for the same elements in the différents pictures : red for the infrastructure layer, domain layer for the data, etc… This could help to hunderstand. Thank for these articles.

    • Totally agree, I messed up the colors between the layered post and the others 🙁 Thanks for the comment! 🙂