Java Package Naming Conventions
Package names are the first thing a reader of an unfamiliar service sees, and the one piece of structure that survives every refactor. The convention below exists so that source across our services stays predictable, and so that two teams can publish artefacts without colliding.
It was written for services that communicate asynchronously over Kafka with a schema registry holding the contracts, and that are laid out internally along hexagonal lines — inbound adapters, business logic, outbound adapters — as packages rather than as separate build modules. Splitting by functional area rather than by technical layer is what makes the naming below worth having.
The scheme
Section titled “The scheme”package [reversed.domain.name].[department_name].[functional_area].[application_name];| Segment | Purpose |
|---|---|
reversed.domain.name | The company’s internet domain, reversed. Prevents collisions with any other organisation’s classes on the classpath. |
department_name | Prevents collisions between departments in the same company. |
functional_area | Prevents collisions between functional areas in the same department. |
application_name | Prevents collisions between repositories and deployable applications. |
Rules for each segment
Section titled “Rules for each segment”- Lower case throughout. Package names that differ from class or interface names only by case are a source of avoidable confusion, and case-insensitive filesystems make them ambiguous.
- Alphanumeric characters and underscores only. Hyphens and dots are not legal in a Java identifier; a domain segment containing a hyphen has to be rewritten with an underscore.
- A segment cannot begin with a digit, for the same reason. Prefix it with an underscore or a word if the real name does.
- Avoid Java keywords as segment names —
int,new,packageand the rest are not legal identifiers.
Shared libraries
Section titled “Shared libraries”A library shared by several applications in one department drops the application segment:
package [reversed.domain.name].[department_name].shared.[library_name];A library shared across the whole company drops the department too:
package [reversed.domain.name].shared.[library_name];The package name should match the published artefact’s group and artefact id closely enough that a reader who sees a class on a stack trace can find the repository it came from without searching.