Coding Guidelines
Padrões de código para projetos InfoWhere
Regras de Idioma
| Elemento | Idioma |
|---|---|
| Código (variáveis, métodos, classes) | Inglês |
| Comentários no código | Inglês (ou nenhum) |
| Commits | Inglês |
| Documentação (README, ADRs, Guidelines) | Português |
Regras Gerais
- Não adicionar comentários automáticos no código
- Remover imports não utilizados (otimizar imports)
- Não usar nomes totalmente qualificados em tipos (ex:
Set<com.xpto.Set>)- Sempre usar imports normais e nomes simples de classes
- Métodos com mais de 3 parâmetros → quebrar em múltiplas linhas, um parâmetro por linha
- Preferir lambdas em vez de classes anônimas
- Evitar APIs deprecated
- Anemic Domain Model — entities devem ser simples; lógica de negócio nos services
- Respeitar regras do Sonar (SonarLint/SonarQube)
- Não deixar código com issues, bugs ou vulnerabilidades
- Sempre gerar testes para novos services, components ou controllers
- Cobertura mínima de 85%
Comentários
┌─────────────────────────────────────────────────────────────────┐
│ REGRA: Código deve ser auto-documentado │
│ │
│ ❌ Comentários automáticos (Javadoc vazio, etc.) │
│ ❌ Comentários óbvios ("get user" antes de getUser()) │
│ ❌ Comentários em português │
│ ⚠️ Comentários explicativos — só se REALMENTE necessário │
│ ✅ Código limpo com nomes claros │
│ │
│ Se precisas de comentário para explicar, refatora o código. │
└─────────────────────────────────────────────────────────────────┘
Exemplo
// ❌ RUIM — Comentário óbvio + português
// Busca o usuário pelo ID
public User getUser(Long id) {
return userRepository.findById(id);
}
// ❌ RUIM — Comentário automático
/**
* Gets user.
* @param id the id
* @return the user
*/
public User getUser(Long id) {
return userRepository.findById(id);
}
// ✅ BOM — Código auto-documentado
public User findUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
// ✅ ACEITÁVEL — Explica "porquê", não "o quê"
// Retry 3 times due to external API instability
public User fetchUserFromExternalApi(Long id) {
return retryTemplate.execute(ctx -> externalApi.getUser(id));
}
Arquitetura por Stack
Java Spring (Produção/Enterprise)
Controller → Facade → Service → Repository
| Camada | Responsabilidade |
|---|---|
| Controller | Request/Response, validação de entrada |
| Facade | Orquestra services, coordena chamadas |
| Service | Lógica de negócio isolada |
| Repository | Acesso a dados |
Estrutura de pastas:
src/main/java/be/infowhere/{projeto}/
├── controller/
├── facade/
├── service/
├── repository/
├── domain/
│ ├── entity/
│ └── dto/
├── mapper/
├── exception/
└── config/
DTOs e Mapeamento:
- Request DTOs:
*Request(ex:CreateUserRequest) - Response DTOs:
*Response(ex:UserResponse) - Nunca expor entities diretamente na API
- Usar MapStruct 1.5+ para mapeamento entity ↔ DTO
Dependências Core:
- Lombok (reduz boilerplate)
- MapStruct (DTO mapping)
- Spring Data JPA + Hibernate
- Liquibase para migrations (preferido sobre Flyway)
O que NÃO usar:
- Flyway → preferir Liquibase
- WebFlux → só se realmente precisar de reactive
- JSP/Thymeleaf → backend é só API
- JDK < 21 → sempre LTS atual
- Gradle → preferir Maven (mais familiar)
Python/Node — Nível Médio
Router → Service → Model
Sem Facade, sem Repository separado — Service acessa ORM direto.
Python:
- FastAPI + Pydantic para validação
- UV como package manager (não pip)
- httpx para requests async (não requests)
- Schemas Pydantic separados de models SQLAlchemy/Beanie
Node:
- Express + Zod para validação
- pnpm como package manager (não npm)
- Prisma como ORM (não Sequelize)
- Sempre TypeScript (nunca JavaScript puro)
- Sempre ESM (nunca CommonJS)
Python/Node — Nível Script
Arquivo único ou poucos arquivos. Sem arquitetura formal.
Angular
- Usar apenas standalone components
- Nunca usar deep imports (
projects/.../src) - Organizar estrutura em
features/,shared/,core/ - Rotas em
app.routes.ts; bootstrap viaapp.config.ts - Não modificar diretamente arquivos
environment*.ts - Não colocar lógica de negócio em components — delegar para services
- Sempre usar Reactive Forms em vez de Template Forms
- Imports do Angular Material devem ser modulares (ex:
MatButtonModule) - Preferir Signals para estado local
- Usar RxJS apenas para sistemas grandes (real-time, streams complexos)
- Preferir ChangeDetectionStrategy.OnPush nos components
- Sempre tipar Observables e Subjects (nunca usar
any) - Não usar
console.log— usar logger da aplicação
Vue
- Usar Composition API com
<script setup lang="ts"> - Usar
ref(),computed(),watch()para reatividade - Pinia para estado global
- Bootstrap como UI framework
- Componentes pragmáticos — dividir quando faz sentido, não por dogma
- Não usar
console.log— usar logger da aplicação
Nomenclatura
| Elemento | Java/TypeScript | Python |
|---|---|---|
| Classes | PascalCase | PascalCase |
| Métodos | camelCase | snake_case |
| Variáveis | camelCase | snake_case |
| Constantes | UPPER_SNAKE | UPPER_SNAKE |
| Arquivos | kebab-case | snake_case |
Formatação
| Stack | Indentação | Formatter |
|---|---|---|
| Java | 4 espaços | Spotless |
| Python | 4 espaços | Black + Ruff |
| Node/TypeScript | 2 espaços | Prettier |
| Vue/Angular | 2 espaços | Prettier |
- Linha máxima: 120 caracteres
Segurança — Paths Ignorados
Não acessar, ler ou modificar:
.env**/secrets/****/certs/****/keystore/****/docs/finance/**
Code Review
- Pelo menos 1 aprovação
- Testes passando
- Sem conflitos
- Lint/Sonar limpo
Database Conventions
| Elemento | Convenção | Exemplo |
|---|---|---|
| Tabelas | snake_case plural |
users, invoice_items |
| Colunas | snake_case |
created_at, user_id |
| Índices | idx_{table}_{column} |
idx_users_email |
| Foreign Keys | fk_{table}_{ref_table} |
fk_orders_users |
| Primary Keys | id (bigint/uuid) |
id |
Migrations:
- Java: Liquibase (XML ou YAML)
- Python: Alembic
- Node: Prisma Migrate
API REST Conventions
| Elemento | Convenção |
|---|---|
| URLs | kebab-case |
| Versionamento | /api/v1/ |
| Formato | JSON |
| Métodos | GET, POST, PUT, PATCH, DELETE |
Status codes:
200— OK201— Created204— No Content400— Bad Request401— Unauthorized403— Forbidden404— Not Found500— Internal Server Error
Autenticação Padrão
- Identity Provider: Keycloak
- Protocolo: OAuth2 + JWT
- Spring Security: Resource Server (valida JWT)
- Frontend: PKCE flow
⚠️ Cada projeto define seu próprio setup de auth — esta é apenas a referência padrão.
Logging
| Stack | Framework | Formato Produção |
|---|---|---|
| Java | SLF4J + Logback | JSON |
| Python | structlog | JSON |
| Node | pino | JSON |
Níveis: ERROR, WARN, INFO, DEBUG
Infraestrutura de Referência (InfoWhere)
⚠️ Esta seção é referência para projetos pessoais/InfoWhere.
Projetos externos definem sua própria infraestrutura (cloud, on-premise, etc.)
CI/CD
- Runner: GitHub Actions
- Deploy: Varia por projeto (cloud, servidor interno, etc.)
Convenção de Portas (quando aplicável)
| Série | Uso |
|---|---|
| 10000 | Frontends |
| 20000 | Backends |
| 30000 | Infraestrutura |
Stack InfoWhere (Referência)
| Serviço | Função |
|---|---|
| Keycloak | Identity Provider |
| Kong | API Gateway |
| PostgreSQL | Database relacional |
| MongoDB Atlas | Database documento |
| Cloudflare Tunnel | Exposição de serviços |
| Grafana/Prometheus/Loki | Observabilidade |
Filosofia
- Local-first, cloud quando necessário
- Containers descartáveis, dados em serviços gerenciados
- IaC desde o início — shell scripts, Terraform, Ansible