Padrões Java¶
Este documento define os padrões oficiais de desenvolvimento Java para projetos da Arkorizon.
O foco deste guia é linguagem, estilo, nomenclatura, organização de código e boas práticas gerais. Regras arquiteturais completas ficam em Arquitetura Hexagonal. Testes ficam em Padrões de Testes Java.
Versão padrão¶
A versão padrão para novos projetos Java é:
Java 21 LTS
Projetos existentes podem permanecer em versões anteriores apenas quando houver restrição técnica ou operacional documentada.
Princípios¶
- Código Java deve ser escrito em inglês.
- Código deve ser simples, explícito e fácil de revisar.
- Nomes devem expressar intenção de negócio ou responsabilidade técnica.
- Evite abstrações antes de existir necessidade real.
- Prefira imutabilidade sempre que possível.
- Não misture regras de negócio com frameworks.
- Erros devem ser explícitos e rastreáveis.
- Código deve favorecer testes unitários simples.
Idioma do código¶
Tudo no código Java deve estar em inglês:
- classes;
- interfaces;
- records;
- métodos;
- variáveis;
- pacotes;
- exceptions;
- mensagens de exception;
- comentários;
- Javadocs.
Exceção: arquivos de internacionalização (i18n) podem conter traduções.
Nomenclatura¶
| Elemento | Padrão | Exemplo |
|---|---|---|
| Classe | PascalCase |
AuthTokenGenerator |
| Interface | PascalCase |
LoginUseCase |
| Método | camelCase |
generateToken |
| Variável | camelCase |
userId |
| Constante | UPPER_SNAKE_CASE |
MAX_LOGIN_ATTEMPTS |
| Package | minúsculo com pontos | com.arkorizon.iam.auth.domain |
| Enum | PascalCase |
OrderStatus |
| Exception | sufixo Exception |
UserNotFoundException |
| DTO | sufixo DTO |
LoginRequestDTO |
| Command | sufixo Command |
CreateUserCommand |
| Result | sufixo Result |
UserResult |
| JPA Entity | sufixo Entity |
UserEntity |
| Mapper | sufixo Mapper |
UserMapper |
| Adapter | sufixo Adapter |
UserPersistenceAdapter |
| Port | sufixo Port |
FindUserByEmailPort |
Abreviações¶
Não use abreviações obscuras.
Ruim:
UsrCtrl
AuthSvc
PwdVal
RespDTO
Bom:
UserController
AuthService
PasswordValidator
AuthTokenResponseDTO
Abreviações amplamente conhecidas são permitidas quando tornam o nome mais claro:
DTO
API
URL
URI
HTTP
JWT
UUID
Records¶
Use record para objetos imutáveis de dados.
Bons usos:
Command;Result;- DTOs;
- value objects simples;
- query parameters;
- mensagens internas imutáveis.
Exemplo:
public record CreateUserCommand(
String name,
String email
) {
}
Evite record quando:
- o objeto possui ciclo de vida complexo;
- precisa proteger mutações;
- possui muitas invariantes internas;
- representa entidade de domínio rica;
- representa entidade JPA.
Classes¶
Use class quando existir comportamento, ciclo de vida ou invariantes relevantes.
public final class LoginAttemptPolicy {
private final int maxAttempts;
public LoginAttemptPolicy(final int maxAttempts) {
if (maxAttempts <= 0) {
throw new IllegalArgumentException("Max attempts must be positive");
}
this.maxAttempts = maxAttempts;
}
public boolean isBlocked(final int failedAttempts) {
return failedAttempts >= maxAttempts;
}
}
Imutabilidade¶
Prefira objetos imutáveis.
- Use
finalem campos sempre que possível. - Evite setters sem necessidade.
- Prefira construtores ou factories para criar objetos válidos.
- Use coleções imutáveis quando retornar dados.
public final class UserProfile {
private final String displayName;
public UserProfile(final String displayName) {
this.displayName = displayName;
}
public String displayName() {
return displayName;
}
}
Uso de final¶
Use final quando ajudar a deixar a intenção clara.
Recomendado:
public AuthTokenResult execute(final LoginCommand command) {
final User user = findUserByEmailPort.findByEmail(command.email())
.orElseThrow(InvalidCredentialsException::new);
return tokenIssuerPort.issueFor(user);
}
Não transforme final em ruído. Em código muito simples, a clareza vem primeiro.
Uso de var¶
Use var apenas para variáveis locais quando o tipo for óbvio.
Bom:
var users = userRepository.findAll();
Evite quando o tipo não for claro:
var result = externalClient.execute(request);
Nesse caso, prefira tipo explícito.
Null handling¶
Evite retornar null.
Use:
Optional<T>para ausência em retorno;- collections vazias em vez de
null; - exceptions para falhas de negócio;
- validação explícita em fronteiras.
public interface FindUserByEmailPort {
Optional<User> findByEmail(String email);
}
Não use Optional em campos, DTOs ou parâmetros sem motivo forte.
Exceptions¶
Exceptions devem ter significado claro.
public final class UserNotFoundException extends RuntimeException {
public UserNotFoundException(final String email) {
super("User not found by email: " + email);
}
}
Regras:
- Use
RuntimeExceptionpara falhas de domínio e aplicação. - Mensagens devem estar em inglês.
- Não engula exceptions silenciosamente.
- Não use
Exceptiongenérica quando existe significado de negócio. - Não retorne
nullpara representar erro.
Logging¶
Use logs para diagnóstico, não para substituir tratamento de erro.
Regras:
- Não logar secrets, tokens, senhas ou dados sensíveis.
- Logs devem ter contexto suficiente.
- Evite logs excessivos em loops ou fluxos de alto volume.
- Use níveis corretamente.
| Nível | Uso |
|---|---|
trace |
Diagnóstico muito detalhado, raro em produção. |
debug |
Diagnóstico técnico. |
info |
Evento relevante de negócio ou operação. |
warn |
Situação inesperada, mas recuperável. |
error |
Falha que exige atenção ou interrompe fluxo. |
Exemplo:
log.warn("Login rejected for inactive user: userId={}", user.id());
Collections¶
Prefira interfaces nos contratos:
List<User> users
Set<Role> roles
Map<String, String> metadata
Evite expor implementação sem necessidade:
ArrayList<User> users
HashMap<String, String> metadata
Retorne coleções vazias em vez de null.
return List.of();
Datas e horários¶
Use Java Time API.
| Caso | Tipo recomendado |
|---|---|
| Instante absoluto | Instant |
| Data sem horário | LocalDate |
| Data e hora local | LocalDateTime |
| Duração | Duration |
| Período calendário | Period |
Evite Date e Calendar em código novo.
Valores monetários¶
Use BigDecimal para dinheiro.
Não use double ou float para valores monetários.
public record Money(
BigDecimal amount,
String currency
) {
}
Streams¶
Use streams quando melhorarem legibilidade.
Bom:
final List<String> activeEmails = users.stream()
.filter(User::active)
.map(User::email)
.toList();
Evite streams complexas demais. Se a cadeia exige muitos passos, extraia métodos ou use código imperativo claro.
Anotações de framework¶
Anotações Spring, JPA, Jackson e Bean Validation devem ficar nas bordas.
Permitido em adapters:
@RestController
@Entity
@JsonProperty
@NotBlank
Proibido no domínio:
@Service
@Entity
@RequestBody
@NotBlank
O domínio deve permanecer Java puro, conforme Arquitetura Hexagonal.
Hexagonal Architecture¶
Projetos backend da Arkorizon devem seguir Arquitetura Hexagonal quando houver regra de negócio relevante.
Este documento Java define estilo de código. A regra arquitetural completa fica em:
Resumo prático:
| Conceito | Onde fica |
|---|---|
| Use case | domain.service |
| Input port | domain.port.in |
| Output port | domain.port.out |
| Domain model | domain.model |
| Command | domain.command |
| Result | domain.result |
| Controller | adapter.in.web.controller |
| DTO | adapter.in.web.dto |
| JPA Entity | adapter.out.persistence.entity |
| Repository | adapter.out.persistence.repository |
| Persistence adapter | adapter.out.persistence.adapter |
| Bean config | config |
Use cases¶
Use cases devem ser interfaces no input port e implementações em Java puro.
public interface CreateUserUseCase {
UserResult execute(CreateUserCommand command);
}
public final class CreateUserUseCaseImpl implements CreateUserUseCase {
@Override
public UserResult execute(final CreateUserCommand command) {
// Business behavior
}
}
Regras:
- Não usar
@Serviceno use case do núcleo. - Não injetar repository no use case.
- Não receber DTO no use case.
- Não retornar JPA entity do use case.
- Usar ports para dependências externas.
DTOs¶
DTOs pertencem aos adapters.
public record LoginRequestDTO(
@NotBlank @Email String email,
@NotBlank String password
) {
}
Regras:
- DTO pode usar Bean Validation.
- DTO pode usar anotações Jackson quando necessário.
- DTO não deve entrar no domínio.
- DTO não deve conter regra de negócio.
Entities JPA¶
Entities JPA pertencem ao adapter de persistência.
@Entity
@Table(name = "tb_user")
public class UserEntity {
@Id
private UUID id;
@Column(name = "email", nullable = false)
private String email;
protected UserEntity() {
}
}
Regras:
- Entity JPA deve ter sufixo
Entity. - Entity JPA não é domain model.
- Entity JPA não deve aparecer em controller.
- Entity JPA não deve ser retornada por use case.
- Entity JPA não deve conter regra de negócio.
Mappers¶
Use mappers para atravessar bordas.
@Mapper(componentModel = "spring")
public interface UserWebMapper {
CreateUserCommand toCommand(CreateUserRequestDTO request);
UserResponseDTO toResponse(UserResult result);
}
Regras:
- Web mapper traduz DTO para command/result.
- Persistence mapper traduz entity para domain model.
- Não use um mapper genérico para tudo.
- Mapper deve ter sufixo
Mapper.
Comentários e Javadocs¶
Comentários devem explicar intenção, regra ou decisão, não repetir o código.
Ruim:
// Sets the user name
user.setName(name);
Bom:
// External providers may return uppercase emails; normalize before lookup.
final String normalizedEmail = email.toLowerCase(Locale.ROOT);
Use Javadocs em APIs públicas, SDKs, bibliotecas e contratos que serão consumidos por outros times.
O que é proibido¶
- Código Java em português.
- Abreviações obscuras.
nullcomo retorno para ausência comum.- Regras de negócio em controller.
- Repository sendo chamado diretamente pelo controller.
- JPA entity usada como response DTO.
- DTO entrando em use case.
- Spring/JPA no domínio.
UtilsouHelpergenéricos sem responsabilidade clara.catch (Exception ignored).- Logs com tokens, senhas ou secrets.
Checklist de revisão Java¶
- O código está em inglês.
- Nomes expressam intenção.
- Não há abreviações obscuras.
- Objetos são imutáveis quando possível.
recordfoi usado apenas onde faz sentido.- Ausência é modelada sem
nulldesnecessário. - Exceptions têm significado claro.
- Logs não expõem dados sensíveis.
- Domínio não depende de framework.
- DTOs, entities e mappers ficam nas bordas corretas.
- Use cases são testáveis sem Spring.