[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?
This work is licensed under a
Creative Commons Attribution 3.0 License.
Print This Post
Add New Comment
Viewing 13 Comments
Thanks. Your comment is awaiting approval by a moderator.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Have you tried having the features in the same packages but distributed on different projects/modules(osgi) for each layer?
Do you already have an account? Log in and claim this comment.
"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? :)
Do you already have an account? Log in and claim this comment.
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?
Do you already have an account? Log in and claim this comment.
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?
Do you already have an account? Log in and claim this comment.
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.
Do you already have an account? Log in and claim this comment.
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.
Do you already have an account? Log in and claim this comment.
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!
Do you already have an account? Log in and claim this comment.
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.
Do you already have an account? Log in and claim this comment.
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?
Do you already have an account? Log in and claim this comment.
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.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
Do you already have an account? Log in and claim this comment.
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 :)
Add New Comment