[link] Package by feature
Stand up and be counted. Which one do you think is best of the following?
Package by layer:
- com.app.controllers
- com.app.model
- com.app.repositories
- com.app.exception
Or package by feature:
- com.app.orders
- com.app.invoices
- com.app.products
I recently added a new site to my RSS reader. John O’Hanly just published a though provoking article about harmful java code idioms on JavaWorld. I don’t agree with everything he suggests, but I do find his point about “Package-by-layer: Preventing the use of package-private scope” very intriguing. John expands on this theme on his website. The most important argument to package by feature is the following:
As a direct benefit of being at a high level of abstraction, the application becomes more self-documenting : the overall size of the application is communicated by the number of packages, and the basic features are communicated by the package names. […] The fundamental flaw with package-by-layer style, on the other hand, is that it puts implementation details ahead of high level abstractions […]
A point that he doesn’t cover, but that I would like to add is that if you organize your classes by feature, the task of delivering one specific user story will likely involve mostly one package. This is a very good test of whether the code is organized correctly. Yet, package by layer is by far the most used way to structure code. The question is: Will you dare to break with the herd and opt for a better solution?
Comments:
Stein Kåre - Jul 29, 2008
This is interesting. I’ve been thinking of this å few times. But never done it. Is there research sugesting that this method actually is better?
Have you tried having the features in the same packages but distributed on different projects/modules(osgi) for each layer?
Thomas Kjeldahl Nilsson - Jul 29, 2008
As to the original request of your blog post: “stand up and be counted:” You’ll have to count me twice.
We implement a proprietary technology stack in-house, this code is packaged by layer. Services / features running on top of that however are packaged by “service” as much as possible… except for some small util bits which I can’t be bothered to put in their own projects. ;)
I guess I really just have trouble with the either-or tone of the referenced article. There are no “best practices”, only good ones in a given situation.
Thomas Ferris Nicolaisen - Aug 6, 2008
Count me as package by feature (or group of features). A package is for me merely a way of hiding implementation/internal classes. The book Effective Java 2nd ed. explains this in Item 13: Minimize the accessibility of classes and members.
Although I traditionally followed the by-layer rule just because everyone else did it, this was because I didn’t understand the potential of using package-private (i.e. didn’t know Java). Instead we tended to use Maven multi-module projects to seperate layers. These give you an extra bonus of enforcing directional dependencies between modules (don’t access the web layer from the dao, etc). But it seems that people have become lazy with the use of traditional moduling with packages..
I recently added a new piece of functionality to our project. The use case was evaluating an organization number to decide what sort of insurances your company can buy online. I started off by making a new service, EvaluationService. I put it in its own package called ’evaluation’. I introduced a domain object called CustomerEvaluation (the result of doing an evaluation with the service), which I placed in our ‘domain’ package (by layer), but I would’ve rather put it in the ’evaluation’ package (by feature). We still put all our exceptions in an ’exceptions’ package, btw. These conventions are more for traditional reasons than for any good reason.
Anyway, I then implemented the EvaluationService with lots of underlying bits and pieces like IndustryCodeService, LegacyCodeTranslator and so on, all of which I dumped into the ’evaluation’ package and made them package-private because they were just details needed to get the EvaluationService working. The evaluation package now feels really clean. It has its own Spring-context, its own nice set of tests, and one single public API exposed in the EvaluationService (and the CustomerEvaluation object).
If another piece of functionality ever needs the IndustryCodeService, I’ll probably drag it out of the ’evaluation’ package, make it public and create an ‘industry-code’ package that both existing packages can depend on.
If it became necessary to enforce that the industry-code package would not create circular references by depending ’evaluation’ or another, I would move it into another maven module (project) higher up in the dependency hierarchy. This would be seperating layers for the reason of enforcing good design, I suppose.
Classes could still be in the same package while being in different projects/modules.. Haven’t played around too much with that approach but it feels like it has potential. Wow, long comment better quit my rambling now. Feature package +1 :)
Johannes Brodwall - Jul 29, 2008
Thanks for the comments.
I suggested this structure for a project some time back, but a few others insisted that it was “too weird”. John O’Hanly has made a web framework called Web4j that he claims uses this structure. It might have some more clues.
Domain classes that are used in multiple features: Most examples I think of the classes have one main feature. For example, “product” would probably be used by “order”, but belongs in product. Do you have an example of a domain class that would be hard to place?
Thomas Kjeldahl Nilsson - Jul 29, 2008
Let’s say both “product” and “order” use the same bit of util code for authorization before running any given function?
I suppose I was thinking about crosscutting concerns/“infrastructure code” here, not domain logic. I’m having trouble coming up with a domain class that can’t be its own feature. :)
Anyway. Unless everything in the project problem space is covered exactly by a specific function call to some external library or service - where do I put things like util classes, wrappers, adapters, bridge code …?
If package-by-layer is completely verboten (like the tone of the article implies, e.g no com.app.util package), then doesn’t it follow that every bit of util/infrastructure code (which is used by more than one feature) will have to go into a separate library - giving me more cruft to worry about in my build environment etc?
Espen Dalløkken - Jul 29, 2008
I tried the “package by feature” structure on a very large project a while back. What we experienced was problems when “feature A” and “feature B” required the same classes for things like application flow control and many other things. So we took the classes used in more than one feature and stuck them in a library project.
What we ended up with was a mixture of both approaches, as we had a the library project which was “structured by layer” and the other client projects where “structured by feature”. In retrospect I would not have chose to package by feature as it just made the code base more difficult to maintain, especially for new resources rolling onto the project.
Structuring by feature to me makes little sense and goes against the basic principles of agile. At the start of any project you generally have little knowledge of what you’re going to create and therefor structuring your code base according to this inaccurate knowledge makes little sense to me.
Marcus Ahnve - Jul 30, 2008
I must be totally backwards. Back in my early Java days, I actually organized packages by feature. After reading Eric Evans book on DDD I changed my style to by layer, which I find a lot better.
My problems with the by feature way of doing things normally involved granularity of features - is the thing we are building a new feature with its own package or should it a part of another package. Also, as others have mentioned, some things are cross cutting meaning that you either create the dreaded ‘common’ package, or just chuck it into the package you feel it belongs to the most.
Marius Mathiesen - Jul 30, 2008
Not being a java guy, my vote should probably count as half a vote, but I’d go for packaging by feature. This discussion actually gives me a slight deja-vú from the discussions that appeared when Ruby on Rails started pushing the REST strategy: it can be a means for getting a better design:
If you have code that seems to span several features it could probably make sense to try to look at it as a feature itself. Especially if the code in question is util code - seriously: does anybody regard authorization code as util code these days? - there’s probably a feature you failed to identify as a feature.
At the same time, straightjackets are seldom a good thing, and neat ideas tend to get irritiating after a while. But this discussion seems highly relevant!
Espen Dalløkken - Jul 30, 2008
@Johannes: I was speaking from a theoretical stand point. One of the reasons why you would use an agile approach is because of the idea that you do not know all the details about what it is you are going to create right off the bat. Therefor you iterate and gradually gain more knowledge of the problem domain. Given this theory you do not know a lot when starting a project and therefor naming features could be a challeng, but this might not be such a big issue in reality.
[Eivind Nordby] - Jul 31, 2008
I find it quite natural to organize user interfaces, “service layer” functionality and support packages by feature, but I am not so convinced concerning cross-cutting domain classes. A good architecture should also support your needs for variation. If for instance you need both a rich GUI, a web interface, an XML interface and test routines on top of your domain, would you melt it all into one single package then? Maybe a pragmatic mixture with an open mind might be an option?
Johannes Brodwall - Jul 30, 2008
Thanks to Marcus and Espen for valuable experiences of trying this kind of approach.
I think the most valuable point is that being dogmatic either way (like the original article) is a bad thing. Like Thomas says: “There are no ‘best practices’, only good ones”.
But I find Espen’s comment about not having enough information to create the structure in an agile project to be puzzling. I find I can organize user stories in rough features. Isn’t this sufficient?
Does anyone else have experience on finding feature categories for your code?
Thomas Kjeldahl Nilsson - Jul 29, 2008
From the article:
“Let’s see. I wonder where this item is located….Oh, here it is. And everything else I am going to need is right here too, all in the same spot. Excellent.”
I wonder; where in the package structure does the author of the article propose I put domain classes/functions which are used by more than one feature? :)
[Filip van Laenen] - Jul 30, 2008
I find it odd that so many people are writing code that doesn’t seem to implement a feature. Or maybe more correct: they don’t know which feature they’re working on when they write the code. Authorization code is either an authorization feature, part of the bigger security feature just like the authentication feature, just to give an example. If you don’t think security is a feature, then try to leave the security out and see how your system will do…
The same goes of course for wrappers, adapters, bridges, and whatever: if you don’t know why you’re writing them, then don’t write them, or think a bit harder about why you’re really writing them. I think names like «util» and «common» are more a sign og laziness than anything else.