It can be difficult to know which packages to use at the start of development, or even which files go together in the same package.

To control the dependency graph of an application, classes that are likely to change together should live together - in the same package.  This means:

  • Don't have a separate exceptions package.   Define the exceptions in the package they belong to.

  • In Spring, don't have a separate services package.  Build the services in packages that relate to the service. For example, if you are building a WeatherService service, put its classes in a weather package, not in a services package and a services.impl package.  After all, the rest of the building blocks for the weather service will already be in the weather package.

  • If you have forms in your application, keep the forms and controllers that manage them in the same package.   Don't create a separate form package.  You can even give them similar names so they sit beside each other on the file system.  For example: AccountInvoiceEditForm.java and AccountInvoiceEditController.java

  • Don't feel that you need to keep the original package name you started with. A good programmer evolves their package structures throughout development, moving classes around and choosing better names as they go.  Only towards the end of the piece (hours or days later) does a beautiful layout become clear.

A web application is a good example of package naming, as it requires a clean split between logic and presentation.  In the following new example, the structure of a Timesheet application has been provided.  The structure is as follows:

Each of the packages in this structure have a purpose:

Package

Purpose

com.xyz.*

This is the parent package for the company “XYZ”.  There isn't usually anything in here.

com.xyz.common.*

Common utility classes and libraries that are used by the XYZ company are beneath here.

com.xyz.common.util.*

Utilities that are used by many projects across XYZ company. Classes in these kinds of packages are less common now that Spring and Apache Common projects are mature.

e.g. CookieUtils.java

com.xyz.common.web.interceptor.*

Web application interceptors that are used across many projects in XYZ company.

com.xyz.timesheet.*

This is the root of the timesheet application for company XYZ. There probably won't be much in the root other than a base TimesheetException.class and perhaps a Version.class and version.txt file.

com.xyz.timesheet.web.*

Root folder for the web application part of the timesheet application.  If you wanted to replace the web interface with a Swing interface (not sure why you would), you could remove everything below this package.

com.xyz.timesheet.web.model.*

The data models used to drive the user interface go here.  Data structures for browser profiles, cookies, pagination data, session data. It's all presentation related classes that are used to send data to and from the user screen – but not forms. Web data.

com.xyz.timesheet.web.tag.*

Where .tag files became too complex and needed to be coded in Java, they live here.

com.xyz.timesheet.web.util.*

Utility classes for use only by the web application which are not large enough to warrant a package of their own.  For example:

PaginationFormula.java


com.xyz.timesheet.web.controller.*

Controllers for the web application.  For large web applications, controllers will be categorized into sub-packages.  For example, if there is an Approval module in the timesheet website (with more than one or two screens), there would be a com.xyz.timesheet.web.controller.approval package.

com.xyz.timesheet.web.form.*

Forms for the web application live here.  If there is a 1:1 mapping between controller and form, keep them together and give them almost identical names so they sit together in the file system.  But this is rare – normally a form is used by more than controller.  Try and keep the names of the packages beneath the form and controller packages consistent, so if there is an approval package in the controller folder, there will be an approval package in the form folder.

com.xyz.timesheet.model.*

Contains the data model classes for the timesheet system.  The classes in here usually map directly to database tables; it is rare for a web application not to require some kind of database.  The model might also represent a local view of web service data, to break dependence on generated classes from a WSDL file.

com.xyz.timesheet.service.*

Services for the timesheet system. If there were only four or five services they could all be grouped together in this package.  

Notice that there is no com.xyz.timesheet.service.impl.* package – it doesn't make a lot of sense to move the implementation away from the interface.

com.xyz.timesheet.service.holiday.*

A package for holding the HolidayService and all the the peripheral classes it uses to provide public holiday calculations.  The reason the holiday package exists is because there were seven different classes it used and it was a good way to group them neatly.  A HolidayException is defined in this package.

com.xyz.timesheet.service.eis.*

This package contains four services for communicating with a web service backend called EIS (Enterprise Integration Services).

This package might also contain an EisError and subclasses thereof which can be thrown when a web service is down. See the section [exception.error] for more detail.

com.xyz.timesheet.job.*

Contains anything to do with scheduled Quartz jobs in the application. It could have been named “quartz” but a better name is “job”.  A better tool than Quartz might come along.

This example is by no means exhaustive, but can give a starting point for structuring your packages neatly.

Tip: Regularly review util packages to make sure they have not been loaded up with classes that really belong in a more specific location.  For example, it is likely ControllerHelper.java belongs in the same package as the rest of the controllers. SessionManager.java probably belongs in a web.session package where all the other session management classes are.

An important trap to go with this rule:

Trap: Every IT company toys with writing a timesheet application at some stage in their growth. Calculation of dates and public holidays and merging them in with company billing and invoicing is far harder than you imagine it would be, so don't do it!

blog comments powered by Disqus