As I’ve built out several applications in Java and Scala, I’ve spent time musing on and researching different approaches to package structure.
The two main approaches are “package by layer” and “package by feature”. These are exclusive in the sense that you have do one of them first, at the top level of your structure, though you can do the other at a lower level.
Package by layer
Package by feature
Like many architecture discussions, things can tend to get a little religious. We’re talking about a strategy for breaking down a very large and complex problem; it’s actually viable to do either one. But I do think that in general, package by layer is a preferable approach. Here are some of the better references I found:
Package by feature: http://www.javapractices.com/topic/TopicAction.do?Id=205 and http://shaunchilders.com/node/15
The main reason I prefer package by layer is this: layers are fundamental to most architectures, and package by layer puts the core architectural division at the first level. I agree with “Directory structure is fundamental to your code” section in the “javapractices.com” site that the “first strokes” are important. But I disagree that the fundamental division is features rather than layers. That article says, “The fundamental flaw with package-by-layer style, on the other hand, is that it puts implementation details ahead of high level abstractions…” I think this is misleading. Someone looking at the codebase is already interested in the “implementation details” of how it is constructed. I use apologetic quotes because we are talking about the highest-level architectural decisions, so calling them “details” seems like a hand-waving way of dismissing the structure of the software. Abstractions let us divide a problem into manageable parts. Dividing a problem into mostly-independent, loosely-coupled layers is a common first step in architecture, and I think it is much more fundamental than dividing an application into features.
Features tend to come and go much more quickly than layers. Over time, the most stable part of the software architecture is likely to be the division of layers, so that should be the top-level structural division. The division is so deep that some features may not map 1-1 with features in other layers: you may have several UI components per model component, or vice versa. It is very likely that there are fewer layers than features. And finally, specific layers are common to many software applications: you are very likely to see something like “model” and “UI” layers in most applications; by contrast, features are completely dependent on the domain. If I know very little about the project structure, and I’m looking at the project for the first time, I think it is more likely that I can find what I need if the top-level division is similar to other applications. Once I’m more familiar with the application, I probably know something about each of the layers, but I may not have touched some of the features.
So while it may not be appropriate for every application, my tendency is to prefer package by layer, unless I have a compelling reason to do something else.