What strategy do you use for package naming in Java projects and why?

29,958

Solution 1

For package design, I first divide by layer, then by some other functionality.

There are some additional rules:

  1. layers are stacked from most general (bottom) to most specific (top)
  2. each layer has a public interface (abstraction)
  3. a layer can only depend on the public interface of another layer (encapsulation)
  4. a layer can only depend on more general layers (dependencies from top to bottom)
  5. a layer preferably depends on the layer directly below it

So, for a web application for example, you could have the following layers in your application tier (from top to bottom):

  • presentation layer: generates the UI that will be shown in the client tier
  • application layer: contains logic that is specific to an application, stateful
  • service layer: groups functionality by domain, stateless
  • integration layer: provides access to the backend tier (db, jms, email, ...)

For the resulting package layout, these are some additional rules:

  • the root of every package name is <prefix.company>.<appname>.<layer>
  • the interface of a layer is further split up by functionality: <root>.<logic>
  • the private implementation of a layer is prefixed with private: <root>.private

Here is an example layout.

The presentation layer is divided by view technology, and optionally by (groups of) applications.

com.company.appname.presentation.internal
com.company.appname.presentation.springmvc.product
com.company.appname.presentation.servlet
...

The application layer is divided into use cases.

com.company.appname.application.lookupproduct
com.company.appname.application.internal.lookupproduct
com.company.appname.application.editclient
com.company.appname.application.internal.editclient
...

The service layer is divided into business domains, influenced by the domain logic in a backend tier.

com.company.appname.service.clientservice
com.company.appname.service.internal.jmsclientservice
com.company.appname.service.internal.xmlclientservice
com.company.appname.service.productservice
...

The integration layer is divided into 'technologies' and access objects.

com.company.appname.integration.jmsgateway
com.company.appname.integration.internal.mqjmsgateway
com.company.appname.integration.productdao
com.company.appname.integration.internal.dbproductdao
com.company.appname.integration.internal.mockproductdao
...

Advantages of separating packages like this is that it is easier to manage complexity, and it increases testability and reusability. While it seems like a lot of overhead, in my experience it actually comes very natural and everyone working on this structure (or similar) picks it up in a matter of days.

Why do I think the vertical approach is not so good?

In the layered model, several different high-level modules can use the same lower-level module. For example: you can build multiple views for the same application, multiple applications can use the same service, multiple services can use the same gateway. The trick here is that when moving through the layers, the level of functionality changes. Modules in more specific layers don't map 1-1 on modules from the more general layer, because the levels of functionality they express don't map 1-1.

When you use the vertical approach for package design, i.e. you divide by functionality first, then you force all building blocks with different levels of functionality into the same 'functionality jacket'. You might design your general modules for the more specific one. But this violates the important principle that the more general layer should not know about more specific layers. The service layer for example shouldn't be modeled after concepts from the application layer.

Solution 2

I find myself sticking with Uncle Bob's package design principles. In short, classes which are to be reused together and changed together (for the same reason, e.g. a dependency change or a framework change) should be put in the same package. IMO, the functional breakdown would have better chance of achieving these goals than the vertical/business-specific break-down in most applications.

For example, a horizontal slice of domain objects can be reused by different kinds of front-ends or even applications and a horizontal slice of the web front-end is likely to change together when the underlying web framework needs to be changed. On the other hand, it's easy to imagine the ripple effect of these changes across many packages if classes across different functional areas are grouped in those packages.

Obviously, not all kinds of software are the same and the vertical breakdown may make sense (in terms of achieving the goals of reusability and closeability-to-change) in certain projects.

Solution 3

There are usually both levels of division present. From the top, there are deployment units. These are named 'logically' (in your terms, think Eclipse features). Inside deployment unit, you have functional division of packages (think Eclipse plugins).

For example, feature is com.feature, and it consists of com.feature.client, com.feature.core and com.feature.ui plugins. Inside plugins, I have very little division to other packages, although that's not unusual too.

Update: Btw, there is great talk by Juergen Hoeller about code organization at InfoQ: http://www.infoq.com/presentations/code-organization-large-projects. Juergen is one of architects of Spring, and knows a lot about this stuff.

Solution 4

Most java projects I've worked on slice the java packages functionally first, then logically.

Usually parts are sufficiently large that they're broken up into separate build artifacts, where you might put core functionality into one jar, apis into another, web frontend stuff into a warfile, etc.

Solution 5

I personally prefer grouping classes logically then within that include a subpackage for each functional participation.

Goals of packaging

Packages are after all about grouping things together - the idea being related classes live close to each other. If they live in the same package they can take advantage of package private to limit visibility. The problem is lumping all your view and persitance stuff into one package can lead to a lot of classes being mixed up into a single package. The next sensible thing to do is thus create view, persistance, util sub packages and refactor classes accordingly. Underfortunately protected and package private scoping does not support the concept of the current package and sub package as this would aide in enforcing such visibility rules.

I see now value in separation via functionality becase what value is there to group all the view related stuff. Things in this naming strategy become disconnected with some classes in the view whilst others are in persistance and so on.

An example of my logical packaging structure

For purposes of illustration lets name two modules - ill use the name module as a concept that groups classes under a particular branch of a pacckage tree.

apple.model apple.store banana.model banana.store

Advantages

A client using the Banana.store.BananaStore is only exposed to the functionality we wish to make available. The hibernate version is an implementation detail which they do not need to be aware nor should they see these classes as they add clutter to storage operations.

Other Logical v Functional advantages

The further up towards the root the broader the scope becomes and things belonging to one package start to exhibit more and more dependencies on things belonging to toher modules. If one were to examine for example the "banana" module most of the dependencies would be limited to within that module. In fact most helpers under "banana" would not be referenced at all outside this package scope.

Why functionality ?

What value does one achieve by lumping things based on functionality. Most classes in such a case are independent of each other with little or no need to take advantage of package private methods or classes. Refactoring them so into their own subpackages gains little but does help reduce the clutter.

Developer changes to the system

When developers are tasked to make changes that are a bit more than trivial it seems silly that potentially they have changes that include files from all areas of the package tree. With the logical structured approach their changes are more local within the same part of the package tree which just seems right.

Share:
29,958
Tim Visher
Author by

Tim Visher

Struggling to fuse faith, lifehacks, ministry, friends, and family into one ain't easy… No wonder I'm no good at it.

Updated on September 02, 2020

Comments

  • Tim Visher
    Tim Visher over 3 years

    I thought about this awhile ago and it recently resurfaced as my shop is doing its first real Java web app.

    As an intro, I see two main package naming strategies. (To be clear, I'm not referring to the whole 'domain.company.project' part of this, I'm talking about the package convention beneath that.) Anyway, the package naming conventions that I see are as follows:

    1. Functional: Naming your packages according to their function architecturally rather than their identity according to the business domain. Another term for this might be naming according to 'layer'. So, you'd have a *.ui package and a *.domain package and a *.orm package. Your packages are horizontal slices rather than vertical.

      This is much more common than logical naming. In fact, I don't believe I've ever seen or heard of a project that does this. This of course makes me leery (sort of like thinking that you've come up with a solution to an NP problem) as I'm not terribly smart and I assume everyone must have great reasons for doing it the way they do. On the other hand, I'm not opposed to people just missing the elephant in the room and I've never heard a an actual argument for doing package naming this way. It just seems to be the de facto standard.

    2. Logical: Naming your packages according to their business domain identity and putting every class that has to do with that vertical slice of functionality into that package.

      I have never seen or heard of this, as I mentioned before, but it makes a ton of sense to me.

      1. I tend to approach systems vertically rather than horizontally. I want to go in and develop the Order Processing system, not the data access layer. Obviously, there's a good chance that I'll touch the data access layer in the development of that system, but the point is that I don't think of it that way. What this means, of course, is that when I receive a change order or want to implement some new feature, it'd be nice to not have to go fishing around in a bunch of packages in order to find all the related classes. Instead, I just look in the X package because what I'm doing has to do with X.

      2. From a development standpoint, I see it as a major win to have your packages document your business domain rather than your architecture. I feel like the domain is almost always the part of the system that's harder to grok where as the system's architecture, especially at this point, is almost becoming mundane in its implementation. The fact that I can come to a system with this type of naming convention and instantly from the naming of the packages know that it deals with orders, customers, enterprises, products, etc. seems pretty darn handy.

      3. It seems like this would allow you to take much better advantage of Java's access modifiers. This allows you to much more cleanly define interfaces into subsystems rather than into layers of the system. So if you have an orders subsystem that you want to be transparently persistent, you could in theory just never let anything else know that it's persistent by not having to create public interfaces to its persistence classes in the dao layer and instead packaging the dao class in with only the classes it deals with. Obviously, if you wanted to expose this functionality, you could provide an interface for it or make it public. It just seems like you lose a lot of this by having a vertical slice of your system's features split across multiple packages.

      4. I suppose one disadvantage that I can see is that it does make ripping out layers a little bit more difficult. Instead of just deleting or renaming a package and then dropping a new one in place with an alternate technology, you have to go in and change all of the classes in all of the packages. However, I don't see this is a big deal. It may be from a lack of experience, but I have to imagine that the amount of times you swap out technologies pales in comparison to the amount of times you go in and edit vertical feature slices within your system.

    So I guess the question then would go out to you, how do you name your packages and why? Please understand that I don't necessarily think that I've stumbled onto the golden goose or something here. I'm pretty new to all this with mostly academic experience. However, I can't spot the holes in my reasoning so I'm hoping you all can so that I can move on.

  • Tim Visher
    Tim Visher over 15 years
    Is there any reason for going either way?
  • Tim Visher
    Tim Visher over 15 years
    I don't quite follow. Usually you might see com.apache.wicket.x where x is either functional or logical. I usually don't see com.x. I guess you're saying that you would go with a com.company.project.feature.layer structure? Do you have reasons?
  • Tim Visher
    Tim Visher over 15 years
    As I understand you then, you would advocate for the vertical naming convention. I think this is what a *.utils package is for, when you need a class across multiple slices.
  • Tim Visher
    Tim Visher over 15 years
    Thanks, this is very clear.As I said in the question, I feel like the number of times you would swap out technologies is far less than you would shift around vertical slices of functionality. Has this not been your experience?
  • Tim Visher
    Tim Visher over 15 years
    Ah. So one thing that doing horizontal slices does is shield you from actual upgrades in the libraries you're using. I think you're right that the vertical slices smear every dependency your system has across every package. Why is this such a big deal?
  • Tim Visher
    Tim Visher over 15 years
    Forgive me if I'm wrong, but it sounds to me like you're more talking about developing a framework that's intended to be used by many people. I think the rules change between that type of development and developing end user systems. Am I wrong?
  • Tim Visher
    Tim Visher over 15 years
    I think for common classes used by many of the vertical slices, it makes sense to have something like a utils package. Then, any classes that need it can simply depend on that package.
  • Tim Visher
    Tim Visher over 15 years
    What might that look like? domain.company.project.function.logicalSlice?
  • Tim Visher
    Tim Visher over 15 years
    I don't fully understand your point. I think what you're saying is that you should just do what makes the most sense for your project and for you that's logical with a little functional thrown in. Are there specific practical reasons for this?
  • Peter Štibraný
    Peter Štibraný over 15 years
    Reason is that "com.company.project.feature" is unit of deployment. At this level, some features are optional, and can be skipped (i.e. not deployed). However, inside feature, things are not optional, and you usually want them all. Here it makes more sense to divive by layers.
  • Varkhan
    Varkhan over 15 years
    Once again, size matters: when a project becomes big enough, it needs to be supported by several people, and some kind of specialization will occur. To ease interaction, and prevent mistakes, segmenting the project in parts becomes quickly necessary. And the utils package will soon become ginormous!
  • Ben Hardy
    Ben Hardy over 15 years
    pretty much! e.g. d.c.p.web.profiles, d.c.p.web.registration, d.c.p.apis, d.c.p.persistence etc. generally works pretty well, your mileage may vary. depends also if you're using domain modeling - if you have multiple domains, you may want to split by domain first.
  • brady
    brady over 15 years
    For a "feature", it's not such a big deal. They tend to be more volatile and have more dependencies anyway. On the other hand, this "client" code tends to have low re-usability. For something you intend to be a reusable library, isolating clients from every little change is a great investment.
  • Buu
    Buu over 15 years
    It's not just about technologies. Point #1 of your original post only makes sense if the vertical slices are independent applications/services communicating with each other via some interface (SOA, if you will). more below...
  • Buu
    Buu over 15 years
    Now as you move into the detail of each of those fine-grained app/service which has its own gui/business/data, I can hardly imagine that changes in a vertical slice, be it about technology, dependency, rule/workflow, logging, security, UI style, can be completely isolated from other slices.
  • JeeBee
    JeeBee over 15 years
    As I said, I'm going to have plugins to augment in-built functionality. A plugin is going to have to be able to parse and write its XML (and eventually into the DB) as well as provide functionality. Therefore do I have com.xx.feature.xml or com.xx.xml.feature? The former seems neater.
  • Luis Vito
    Luis Vito over 15 years
    Splitting by asset class (more generally: by business domain) makes it easier for the new people to find their way through the code. Splitting by function is good for encapsulation. For me, "package" access in Java is akin to a "friend" in C++.
  • mP.
    mP. over 15 years
    I personally prefer to the opposite, logical then functional. apples.rpc, apples.model and then banana.model, banana.store
  • mP.
    mP. over 15 years
    There is more value in being able to group all the apple stuff together than grouping all the web stuff together.
  • Esko Luontola
    Esko Luontola over 15 years
    Tim Visher, dependencies between packages are not a problem, as long as the dependencies always point in the same direction and there are no cycles in the dependency graph.
  • eljenso
    eljenso over 15 years
    "When developers [...] files from all areas of the package tree." You are right when you say this seems silly. Because this is exactly the point of proper layering: changes do not ripple through the entire structure of the application.
  • Tim Visher
    Tim Visher about 15 years
    Thanks for the advice. I'm not sure I'm understanding you clearly. I believe you're trying to argue for Logical packages, I'm not exactly clear why. Could you try to make your answer a little clearer, possibly rewording? Thanks!
  • Turing
    Turing about 13 years
    "Advantages of separating packages like this is that it is easier to manage complexity, and it increases testability and reusability." You really don't go into the reasons why this is so.
  • eljenso
    eljenso about 13 years
    You don't go into the reasons why it isn't so. But anyway... the rules for organizing are fairly clear and straightforward, so it reduces complexity. It is more testable and reusable because of the organization itself. Everyone can try it out, and afterwards we can agree or disagree. I briefly explain some of the disadvantages of the vertical approach, implicitly giving reasons why I think the horizontal approach is easier.
  • Tom
    Tom about 11 years
    This article explains quite nicely why it is better to use package-by-feature instead of package-by-layer.
  • pka
    pka over 10 years
    @eljenso "You don't go into the reasons why it isn't so", trying to shift the burden of proof? I think the article posted by Tom explains very nicely why package-by-feature is better and I'm having a hard time taking "I don't think it's a judgment call. First dividing by layer, then by functionality is definitely the way to go" seriously.
  • i3ensays
    i3ensays over 10 years
    I would be interested in your feedback on my answer
  • i3ensays
    i3ensays over 10 years
    @quant_dev I disagree with "..by function is good for encapsulation". I think you mean the complete opposite is true. Also, don't just pick out of "convenience". There is a case for each (see my answer).
  • user2793390
    user2793390 about 10 years
    Code reuse is not about the price of hardware but about code maintenance costs.
  • Raghu Kasturi
    Raghu Kasturi about 10 years
    Agree, but fixing something in a simple module shouldn't effect entire code. What maintenance costs are you talking about?
  • user2793390
    user2793390 about 10 years
    A bug fix in a module should affect the whole application. Why would you want to fix the same bug multiple times?
  • johnnieb
    johnnieb almost 8 years
    @BuuNguyen The link to the package design principles is broken.
  • David Rector
    David Rector over 3 years
    Have you had to maintain that code of yours years after you wrote it? I curse those who came before me that took such a lackadaisical approach to computer programming. Spending my time to fix your code multiple times due to duplicate is both inefficient and annoying.I had to work on my own code 18 years after I wrote it and every ameturish mistake I made just made life that much harder for me. redundancy is one of those terrible mistakes that I paid for in the end.