TL;DR: Use Spring Boot as the application framework, Google Java Format (via Spotless) for formatting, Checkstyle + PMD for linting, MapStruct for object mapping, SLF4J with Logback for logging, JUnit 5 + Mockito for testing, and Gradle for builds.
This series of pages outlines Java-specific conventions, with detailed explanations of recommended approaches and the reasoning behind them. For the general baseline, refer to the Code Style guide. See the sub-pages for specific topics:
All database versioning is managed through Liquibase. Follow these mandatory conventions:
| Rule | Description |
|---|---|
| File format | Always use .yaml (not .yml) |
| Quoting | Always use single quotes |
| Naming | Always use snake_case |
| Rollbacks | Every changeset must include a rollback statement |
| Pre-conditions | Every changeset must include pre-conditions to validate the database state |
| Boolean/Time columns | Use descriptive names: created_at, enabled, updated_at, activated |
Constraints must appear before the column name in column definitions:
# Correct
- column:
constraints:
nullable: false
name: 'email'
type: 'VARCHAR(255)'
# Wrong
- column:
name: 'email'
type: 'VARCHAR(255)'
constraints:
nullable: false| Type | Pattern | Example |
|---|---|---|
| Unique Index (UIX) | <table>_<column>_uix |
user_name_uix |
| Foreign Key (FK) | <origin_table>_<destination_table>_fkey |
user_user_contract_information_fkey |
| Primary Key (PK) | <table>_pkey |
user_service_pkey |
| Materialized View (MV) | <view>_uix |
rich_user_ix |
Follow Semantic Versioning for database changelogs:
| Change Type | Version Update |
|---|---|
| New table | X.Y+1.0 |
| Alter existing table | X.Y.Z+1 |
| Breaking structural change | X+1.0.0 |
Packages published for testing must use the -SNAPSHOT suffix (e.g., 3.0.0-SNAPSHOT). Snapshot packages must never be used in production.
databaseChangeLog:
- changeSet:
id: '00-create-table-example'
author: 'author.name'
context: 'prod, test'
preConditions:
- not:
tableExists:
tableName: 'example'
changes:
- createTable:
tableName: 'example'
columns:
- column:
autoIncrement: true
constraints:
nullable: false
primaryKey: true
primaryKeyName: 'example_pkey'
name: 'id'
type: 'BIGINT'
- column:
constraints:
nullable: false
unique: true
uniqueConstraintName: 'example_name_uix'
name: 'name'
type: 'VARCHAR(50)'
- column:
name: 'active'
type: 'BOOLEAN'
- column:
constraints:
nullable: false
name: 'created_at'
type: 'TIMESTAMP'
rollback:
- dropTable:
tableName: 'example'The following principles guide Java development across all projects:
- Program to interfaces, not implementations. Depend on abstractions (interfaces) rather than concrete classes. This enables testability and loose coupling.
- Favor composition over inheritance. Build complex behavior by composing objects rather than through deep class hierarchies.
- Immutability by default. Use
finalfields, records, and immutable collections wherever possible. Mutable state should be the exception, not the rule. - Fail fast. Validate inputs early and throw meaningful exceptions rather than propagating invalid state through the system.
- Convention over configuration. Leverage Spring Boot's auto-configuration and opinionated defaults rather than writing boilerplate.