criado repositório jhonny-editor no Gitea adicionado script admin/deploy.command com commit automático atualizado admin/DEV-NOTES.md com template limpo Resumo: - 8 arquivos alterados - 2 novos - 6 modificados - 0 removidos 6 files changed, 33 insertions(+), 3 deletions(-) Arquivos: - .agents/skills/boas-praticas-oo/SKILL.md - .claude/settings.json - AGENTS.md - CLAUDE.md - CODING_STANDARDS.md - code/engine/executar_scanner.py - .claude/hooks/ - code/engine/testes/test_executar_scanner.py
1448 lines
32 KiB
Markdown
1448 lines
32 KiB
Markdown
---
|
|
name: boas-praticas-oo
|
|
description: Padrões obrigatórios de POO, nomenclatura em PT-BR e documentação para todo código Python de code/engine/ neste projeto (Jhonny). Use SEMPRE — antes de criar, editar, corrigir, refatorar ou revisar qualquer classe, função ou módulo Python do engine, mesmo sem pedido explícito do usuário. Não se aplica a outros projetos.
|
|
---
|
|
|
|
# Skill — Boas práticas gerais para desenvolvimento Python orientado a objetos
|
|
|
|
## 1. Objetivo
|
|
|
|
Esta skill define padrões obrigatórios para criar, modificar, corrigir, revisar, refatorar e ampliar qualquer sistema desenvolvido em Python.
|
|
|
|
As regras devem ser aplicadas independentemente do tipo de programa, como:
|
|
|
|
- Sistemas web;
|
|
- Aplicações desktop;
|
|
- APIs;
|
|
- Automações;
|
|
- Sistemas financeiros;
|
|
- Ferramentas de análise;
|
|
- Aplicações com inteligência artificial;
|
|
- Sistemas de edição de vídeo;
|
|
- Integrações com serviços externos;
|
|
- Sistemas de banco de dados;
|
|
- Aplicações científicas;
|
|
- Bibliotecas;
|
|
- Scripts evolutivos;
|
|
- Sistemas distribuídos.
|
|
|
|
O objetivo é garantir que o código seja:
|
|
|
|
- Claro;
|
|
- Organizado;
|
|
- Manutenível;
|
|
- Testável;
|
|
- Reutilizável;
|
|
- Seguro;
|
|
- Extensível;
|
|
- Documentado;
|
|
- Coerente com os requisitos;
|
|
- Fácil de compreender por outros desenvolvedores.
|
|
|
|
A implementação não deve ser criada apenas para “funcionar”. Todo código deve possuir uma responsabilidade clara, seguir uma arquitetura coerente e ser documentado e testado de acordo com sua importância.
|
|
|
|
---
|
|
|
|
# 2. Idioma obrigatório do projeto
|
|
|
|
O idioma padrão de todo o projeto deverá ser **português brasileiro — PT-BR**.
|
|
|
|
Essa regra se aplica obrigatoriamente a:
|
|
|
|
- Classes;
|
|
- Métodos;
|
|
- Funções;
|
|
- Variáveis;
|
|
- Atributos;
|
|
- Parâmetros;
|
|
- Propriedades;
|
|
- Constantes;
|
|
- Interfaces;
|
|
- Classes abstratas;
|
|
- Exceções personalizadas;
|
|
- Arquivos;
|
|
- Pastas;
|
|
- Módulos;
|
|
- Nomes de testes;
|
|
- Fixtures;
|
|
- Configurações;
|
|
- Comentários;
|
|
- Docstrings;
|
|
- Mensagens de erro;
|
|
- Logs;
|
|
- Documentação;
|
|
- README;
|
|
- Exemplos de uso.
|
|
|
|
## 2.1. Exemplos obrigatórios
|
|
|
|
Utilizar:
|
|
|
|
```python
|
|
class GerenciadorDeArquivos:
|
|
"""Gerencia operações relacionadas a arquivos."""
|
|
|
|
def carregar_arquivo(self, caminho_do_arquivo: str) -> str:
|
|
"""Carrega o conteúdo de um arquivo."""
|
|
...
|
|
```
|
|
|
|
Utilizar:
|
|
|
|
```python
|
|
quantidade_de_tentativas = 3
|
|
nome_do_usuario = "João"
|
|
arquivo_de_configuracao = "configuracao.json"
|
|
```
|
|
|
|
Não utilizar nomes internos como:
|
|
|
|
```python
|
|
class FileManager:
|
|
"""Manages file operations."""
|
|
|
|
def load_file(self, file_path: str) -> str:
|
|
"""Loads the file content."""
|
|
...
|
|
```
|
|
|
|
Também evitar:
|
|
|
|
```python
|
|
retry_count = 3
|
|
user_name = "João"
|
|
config_file = "config.json"
|
|
```
|
|
|
|
---
|
|
|
|
# 3. Comentários e docstrings sempre em PT-BR
|
|
|
|
Todos os comentários deverão ser escritos em português brasileiro.
|
|
|
|
Utilizar:
|
|
|
|
```python
|
|
# Verifica se o arquivo existe antes de tentar carregá-lo.
|
|
if caminho.exists():
|
|
...
|
|
```
|
|
|
|
Não utilizar:
|
|
|
|
```python
|
|
# Check if the file exists before loading it.
|
|
if caminho.exists():
|
|
...
|
|
```
|
|
|
|
Todas as docstrings também deverão estar em português brasileiro:
|
|
|
|
```python
|
|
def calcular_valor_total(
|
|
valor_unitario: float,
|
|
quantidade: int,
|
|
) -> float:
|
|
"""
|
|
Calcula o valor total multiplicando o valor unitário pela quantidade.
|
|
|
|
Parâmetros:
|
|
valor_unitario: Valor de cada unidade.
|
|
quantidade: Quantidade de unidades.
|
|
|
|
Retorna:
|
|
O valor total da operação.
|
|
"""
|
|
return valor_unitario * quantidade
|
|
```
|
|
|
|
---
|
|
|
|
# 4. Exceções para identificadores externos
|
|
|
|
A regra de utilizar português brasileiro se aplica a todos os identificadores criados internamente pelo projeto.
|
|
|
|
Entretanto, identificadores externos poderão permanecer em seu formato original quando forem necessários para integração, compatibilidade ou funcionamento técnico.
|
|
|
|
## 4.1. O que são identificadores externos
|
|
|
|
São nomes definidos fora do projeto, como:
|
|
|
|
- Nomes de bibliotecas;
|
|
- Nomes de frameworks;
|
|
- Nomes de APIs;
|
|
- Nomes de classes e métodos fornecidos por bibliotecas;
|
|
- Nomes de campos exigidos por APIs;
|
|
- Nomes de endpoints;
|
|
- Nomes de parâmetros de requisições;
|
|
- Nomes de eventos externos;
|
|
- Nomes de comandos de terminal;
|
|
- Nomes de variáveis de ambiente;
|
|
- Nomes de arquivos exigidos por ferramentas;
|
|
- Nomes de formatos;
|
|
- Nomes de protocolos;
|
|
- Nomes de modelos de inteligência artificial;
|
|
- Nomes de serviços externos;
|
|
- Nomes de tabelas ou colunas legadas;
|
|
- Nomes definidos por sistemas de terceiros.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
import requests
|
|
import pandas
|
|
from pathlib import Path
|
|
```
|
|
|
|
Os nomes `requests`, `pandas` e `Path` são identificadores externos e podem permanecer em seu formato oficial.
|
|
|
|
## 4.2. Identificadores externos devem ser preservados quando forem obrigatórios
|
|
|
|
Quando uma biblioteca, API ou ferramenta exigir determinado nome, ele deverá ser preservado exatamente como definido externamente.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
resposta = cliente.get(
|
|
url,
|
|
headers={
|
|
"Authorization": token_de_autenticacao,
|
|
"Content-Type": "application/json",
|
|
},
|
|
)
|
|
```
|
|
|
|
Os campos `"Authorization"` e `"Content-Type"` não devem ser traduzidos, pois fazem parte do contrato técnico externo.
|
|
|
|
O código interno, entretanto, deverá permanecer em português:
|
|
|
|
```python
|
|
token_de_autenticacao
|
|
cliente
|
|
resposta
|
|
```
|
|
|
|
## 4.3. Separar identificadores externos dos identificadores internos
|
|
|
|
Sempre que possível, os nomes externos deverão ficar isolados na fronteira da aplicação.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
dados_externos = {
|
|
"first_name": "João",
|
|
"last_name": "Silva",
|
|
}
|
|
```
|
|
|
|
Ao entrar no sistema, os dados deverão ser convertidos para uma representação interna em português:
|
|
|
|
```python
|
|
class Usuario:
|
|
"""Representa um usuário dentro da aplicação."""
|
|
|
|
def __init__(self, nome: str, sobrenome: str):
|
|
self.nome = nome
|
|
self.sobrenome = sobrenome
|
|
```
|
|
|
|
A conversão poderá ser feita por um adaptador:
|
|
|
|
```python
|
|
class ConversorDeUsuarioExterno:
|
|
"""Converte dados externos para entidades internas da aplicação."""
|
|
|
|
def converter(self, dados_externos: dict) -> Usuario:
|
|
"""Converte o formato externo para o modelo interno."""
|
|
|
|
return Usuario(
|
|
nome=dados_externos["first_name"],
|
|
sobrenome=dados_externos["last_name"],
|
|
)
|
|
```
|
|
|
|
## 4.4. Não espalhar nomes externos pelo sistema
|
|
|
|
Identificadores externos não deverão ser utilizados indiscriminadamente em todas as camadas.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
usuario.first_name
|
|
usuario.last_name
|
|
usuario.user_id
|
|
```
|
|
|
|
Preferir:
|
|
|
|
```python
|
|
usuario.nome
|
|
usuario.sobrenome
|
|
usuario.identificador
|
|
```
|
|
|
|
Os nomes externos devem ficar restritos, sempre que possível, a componentes como:
|
|
|
|
- Adaptadores;
|
|
- Conversores;
|
|
- Clientes de API;
|
|
- Repositórios;
|
|
- Integrações;
|
|
- Mapeadores;
|
|
- Camadas de infraestrutura.
|
|
|
|
## 4.5. Variáveis internas devem permanecer em português
|
|
|
|
Mesmo quando a API utilizar nomes em inglês, as variáveis internas deverão utilizar português brasileiro.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
user_data = resposta.json()
|
|
access_token = obter_token()
|
|
request_timeout = 30
|
|
```
|
|
|
|
Preferir:
|
|
|
|
```python
|
|
dados_do_usuario = resposta.json()
|
|
token_de_acesso = obter_token()
|
|
tempo_limite_da_requisicao = 30
|
|
```
|
|
|
|
## 4.6. Campos externos devem ser documentados
|
|
|
|
Quando um identificador externo permanecer no código, deverá ser possível compreender:
|
|
|
|
- De qual sistema ele vem;
|
|
- Por que não foi traduzido;
|
|
- Qual é sua finalidade;
|
|
- Se sua alteração pode quebrar a integração.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
DADOS_OBRIGATORIOS_DA_API = (
|
|
"first_name",
|
|
"last_name",
|
|
"email",
|
|
)
|
|
"""
|
|
Nomes dos campos exigidos pela API externa de usuários.
|
|
|
|
Esses identificadores não devem ser traduzidos, pois fazem
|
|
parte do contrato oficial da API.
|
|
"""
|
|
```
|
|
|
|
## 4.7. Variáveis de ambiente
|
|
|
|
Os nomes de variáveis de ambiente poderão permanecer em inglês quando forem definidos por ferramentas ou serviços externos.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
import os
|
|
|
|
chave_da_api = os.getenv("OPENAI_API_KEY")
|
|
```
|
|
|
|
O nome externo `OPENAI_API_KEY` deve ser preservado, enquanto a variável interna `chave_da_api` deve permanecer em português.
|
|
|
|
Quando a variável de ambiente for criada pelo próprio projeto, utilizar português:
|
|
|
|
```python
|
|
caminho_dos_dados = os.getenv("CAMINHO_DOS_DADOS")
|
|
```
|
|
|
|
## 4.8. Nomes de métodos externos
|
|
|
|
Métodos externos deverão ser utilizados exatamente como definidos pela biblioteca.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
resposta = cliente.request("GET", endereco)
|
|
```
|
|
|
|
O método `request` não deve ser renomeado, pois pertence à biblioteca externa.
|
|
|
|
Entretanto, métodos criados pelo projeto deverão permanecer em português:
|
|
|
|
```python
|
|
def consultar_usuario(self, identificador: str):
|
|
"""Consulta um usuário utilizando o cliente externo."""
|
|
|
|
resposta = self.cliente.request(
|
|
"GET",
|
|
self._criar_endereco(identificador),
|
|
)
|
|
|
|
return self._converter_resposta(resposta)
|
|
```
|
|
|
|
## 4.9. Endpoints, eventos e comandos externos
|
|
|
|
Os nomes abaixo poderão permanecer no idioma original quando fizerem parte de um contrato externo:
|
|
|
|
```python
|
|
ENDPOINT_DE_AUTENTICACAO = "/oauth/token"
|
|
EVENTO_EXTERNO = "user.created"
|
|
COMANDO_EXTERNO = "ffmpeg"
|
|
FORMATO_EXTERNO = "application/json"
|
|
```
|
|
|
|
A constante interna deverá possuir nome em português, mesmo que seu valor seja externo.
|
|
|
|
## 4.10. Compatibilidade com código legado
|
|
|
|
Quando o sistema precisar manter compatibilidade com código antigo, identificadores externos ou legados poderão ser preservados.
|
|
|
|
Nesse caso:
|
|
|
|
- O motivo deverá ser documentado;
|
|
- O uso deverá ser limitado;
|
|
- Novos identificadores deverão seguir português brasileiro;
|
|
- Deverá existir uma camada de adaptação quando possível;
|
|
- O padrão legado não deverá ser espalhado para novos módulos.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
class AdaptadorDoSistemaLegado:
|
|
"""
|
|
Adapta os campos do sistema legado para o modelo interno.
|
|
|
|
O sistema externo utiliza os campos ``usr_nm`` e ``usr_id``.
|
|
Esses nomes são preservados somente nesta camada de adaptação.
|
|
"""
|
|
|
|
def converter(self, dados_legados: dict) -> dict:
|
|
"""Converte os dados legados para o formato interno."""
|
|
|
|
return {
|
|
"nome": dados_legados["usr_nm"],
|
|
"identificador": dados_legados["usr_id"],
|
|
}
|
|
```
|
|
|
|
## 4.11. Regra de prioridade
|
|
|
|
A ordem de prioridade deverá ser:
|
|
|
|
1. Utilizar português brasileiro para identificadores internos;
|
|
2. Preservar identificadores externos quando forem exigidos por contratos técnicos;
|
|
3. Isolar identificadores externos nas integrações;
|
|
4. Converter dados externos para modelos internos em português;
|
|
5. Documentar toda exceção relevante;
|
|
6. Evitar que nomes externos contaminem o restante da aplicação.
|
|
|
|
> Identificadores externos podem permanecer em seu idioma original somente quando forem definidos por uma biblioteca, API, ferramenta, protocolo, sistema legado ou contrato externo. Todos os identificadores criados internamente pelo projeto deverão permanecer em português brasileiro.
|
|
|
|
---
|
|
|
|
# 5. Padrão de nomenclatura
|
|
|
|
## 5.1. Classes
|
|
|
|
As classes deverão utilizar `PascalCase`.
|
|
|
|
```python
|
|
class GerenciadorDeArquivos:
|
|
"""Gerencia operações relacionadas a arquivos."""
|
|
```
|
|
|
|
## 5.2. Métodos e funções
|
|
|
|
Métodos e funções deverão utilizar `snake_case`.
|
|
|
|
```python
|
|
def carregar_configuracao():
|
|
"""Carrega as configurações da aplicação."""
|
|
```
|
|
|
|
## 5.3. Variáveis e atributos
|
|
|
|
Variáveis e atributos deverão utilizar `snake_case`.
|
|
|
|
```python
|
|
nome_do_usuario = "João"
|
|
quantidade_de_itens = 10
|
|
```
|
|
|
|
## 5.4. Arquivos e pastas
|
|
|
|
Arquivos e pastas deverão utilizar nomes em `snake_case`.
|
|
|
|
```text
|
|
gerenciador_de_arquivos.py
|
|
servico_de_autenticacao.py
|
|
processamento_de_dados/
|
|
```
|
|
|
|
## 5.5. Constantes
|
|
|
|
Constantes deverão utilizar letras maiúsculas com sublinhado.
|
|
|
|
```python
|
|
TEMPO_LIMITE_DA_OPERACAO = 30
|
|
QUANTIDADE_MAXIMA_DE_TENTATIVAS = 3
|
|
```
|
|
|
|
## 5.6. Nomes proibidos
|
|
|
|
Evitar nomes genéricos ou pouco informativos, como:
|
|
|
|
```text
|
|
Util
|
|
Helper
|
|
Manager
|
|
Processor
|
|
Data
|
|
Object
|
|
Thing
|
|
Temp
|
|
Teste
|
|
Classe
|
|
Funcao
|
|
```
|
|
|
|
Preferir:
|
|
|
|
```text
|
|
ConversorDeDados
|
|
ValidadorDeCadastro
|
|
GerenciadorDeSessao
|
|
LeitorDeArquivos
|
|
ServicoDeNotificacoes
|
|
```
|
|
|
|
---
|
|
|
|
# 6. Documentação obrigatória de módulos
|
|
|
|
Todo módulo deverá possuir uma docstring no início do arquivo.
|
|
|
|
A docstring deverá explicar:
|
|
|
|
- A finalidade do módulo;
|
|
- O problema que ele resolve;
|
|
- Sua responsabilidade;
|
|
- O que ele não faz;
|
|
- Quais componentes principais contém;
|
|
- Quais dependências relevantes utiliza.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
"""
|
|
Módulo responsável pela validação de dados de cadastro.
|
|
|
|
Este módulo verifica campos obrigatórios, formatos e regras
|
|
de consistência antes que os dados sejam utilizados pela aplicação.
|
|
|
|
Ele não salva dados no banco de dados e não realiza operações
|
|
de interface.
|
|
"""
|
|
```
|
|
|
|
A documentação do módulo deverá ser atualizada sempre que sua finalidade ou comportamento mudar.
|
|
|
|
---
|
|
|
|
# 7. Documentação obrigatória de classes
|
|
|
|
Toda classe deverá possuir uma docstring imediatamente acima da declaração.
|
|
|
|
A docstring deverá informar:
|
|
|
|
- O que a classe representa;
|
|
- Qual é sua responsabilidade principal;
|
|
- Quais são suas principais dependências;
|
|
- O que ela não deve fazer;
|
|
- Quais efeitos colaterais pode produzir, quando aplicável.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
class ValidadorDeCadastro:
|
|
"""
|
|
Valida os dados recebidos durante o cadastro de usuários.
|
|
|
|
Esta classe verifica regras de formato e consistência.
|
|
Ela não persiste os dados e não envia notificações.
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
# 8. Documentação obrigatória de métodos e funções
|
|
|
|
Todo método ou função público deverá possuir uma docstring.
|
|
|
|
A documentação deverá explicar:
|
|
|
|
- O que o método faz;
|
|
- Quais dados recebe;
|
|
- O que retorna;
|
|
- Quais erros pode gerar;
|
|
- Se altera estado;
|
|
- Se realiza operações externas;
|
|
- Quais condições especiais devem ser observadas.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
def validar_email(self, email: str) -> bool:
|
|
"""
|
|
Verifica se o endereço de e-mail possui formato válido.
|
|
|
|
Parâmetros:
|
|
email: Endereço de e-mail que será validado.
|
|
|
|
Retorna:
|
|
True quando o formato for válido.
|
|
False quando o formato for inválido.
|
|
|
|
Pode gerar:
|
|
ValueError: quando o valor recebido estiver vazio.
|
|
"""
|
|
```
|
|
|
|
Métodos privados também deverão ser documentados quando possuírem lógica relevante ou comportamento não óbvio.
|
|
|
|
---
|
|
|
|
# 9. Documentação de atributos importantes
|
|
|
|
Atributos relevantes deverão ser documentados na classe.
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
class SessaoDoUsuario:
|
|
"""
|
|
Representa uma sessão ativa de usuário.
|
|
|
|
Atributos:
|
|
identificador: Identificador único da sessão.
|
|
usuario: Usuário associado à sessão.
|
|
criada_em: Data e hora de criação.
|
|
expira_em: Data e hora de expiração.
|
|
"""
|
|
```
|
|
|
|
Atributos simples não precisam de comentários individuais quando seus nomes forem claros.
|
|
|
|
---
|
|
|
|
# 10. Documentação viva
|
|
|
|
A documentação deverá permanecer coerente com o código.
|
|
|
|
Sempre que houver alteração em:
|
|
|
|
- Responsabilidade;
|
|
- Nome;
|
|
- Entrada;
|
|
- Saída;
|
|
- Regra de negócio;
|
|
- Fluxo;
|
|
- Dependência;
|
|
- Exceção;
|
|
- Configuração;
|
|
- Efeito colateral;
|
|
- Estrutura de dados;
|
|
|
|
a documentação deverá ser atualizada na mesma alteração.
|
|
|
|
É proibido manter docstrings, comentários ou arquivos Markdown descrevendo um comportamento que não existe mais.
|
|
|
|
---
|
|
|
|
# 11. Responsabilidade única
|
|
|
|
Cada classe, função e módulo deverá possuir uma responsabilidade principal.
|
|
|
|
Uma classe não deverá concentrar várias funções sem relação direta.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
class Sistema:
|
|
"""
|
|
Conecta ao banco, valida dados, envia e-mails,
|
|
gera relatórios, processa arquivos e controla a interface.
|
|
"""
|
|
```
|
|
|
|
Preferir separar:
|
|
|
|
```text
|
|
ConexaoComBancoDeDados
|
|
ValidadorDeDados
|
|
ServicoDeEmail
|
|
GeradorDeRelatorios
|
|
ProcessadorDeArquivos
|
|
ControladorDaInterface
|
|
```
|
|
|
|
Uma classe poderá coordenar outras classes, mas não deverá implementar todos os detalhes de todas elas.
|
|
|
|
---
|
|
|
|
# 12. Alta coesão
|
|
|
|
Os métodos de uma classe devem estar relacionados à sua responsabilidade principal.
|
|
|
|
Uma classe chamada `LeitorDeArquivos` deverá possuir operações relacionadas à leitura de arquivos.
|
|
|
|
Não deverá conter métodos como:
|
|
|
|
```python
|
|
calcular_salario()
|
|
enviar_email()
|
|
criar_usuario()
|
|
gerar_relatorio_financeiro()
|
|
```
|
|
|
|
---
|
|
|
|
# 13. Baixo acoplamento
|
|
|
|
As classes deverão depender do mínimo possível de outras classes.
|
|
|
|
Evitar criar dependências rígidas diretamente dentro da implementação:
|
|
|
|
```python
|
|
class Relatorio:
|
|
def __init__(self):
|
|
self.banco_de_dados = BancoDeDados()
|
|
self.enviador_de_email = EnviadorDeEmail()
|
|
```
|
|
|
|
Preferir receber as dependências:
|
|
|
|
```python
|
|
class Relatorio:
|
|
"""
|
|
Gera relatórios utilizando dependências fornecidas externamente.
|
|
"""
|
|
|
|
def __init__(self, banco_de_dados, enviador_de_email):
|
|
self.banco_de_dados = banco_de_dados
|
|
self.enviador_de_email = enviador_de_email
|
|
```
|
|
|
|
---
|
|
|
|
# 14. Composição antes de herança
|
|
|
|
A composição deverá ser utilizada quando uma classe precisar utilizar outra.
|
|
|
|
```python
|
|
class ServicoDeCadastro:
|
|
"""
|
|
Coordena o cadastro utilizando validação e persistência.
|
|
"""
|
|
|
|
def __init__(self, validador, repositorio):
|
|
self.validador = validador
|
|
self.repositorio = repositorio
|
|
```
|
|
|
|
---
|
|
|
|
# 15. Herança somente quando houver especialização real
|
|
|
|
A herança deverá ser utilizada apenas quando existir uma relação clara de “é um”.
|
|
|
|
Exemplo adequado:
|
|
|
|
```python
|
|
class ErroDaAplicacao(Exception):
|
|
"""Representa um erro geral da aplicação."""
|
|
|
|
|
|
class ErroDeValidacao(ErroDaAplicacao):
|
|
"""Representa um erro de validação."""
|
|
```
|
|
|
|
Exemplo inadequado:
|
|
|
|
```python
|
|
class Relatorio(BancoDeDados):
|
|
"""Gera relatórios."""
|
|
```
|
|
|
|
Um relatório não é um banco de dados. Nesse caso, deve utilizar composição ou injeção de dependência.
|
|
|
|
---
|
|
|
|
# 16. Encapsulamento
|
|
|
|
As classes deverão proteger suas regras e controlar como seus dados são alterados.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
conta.saldo = -500
|
|
```
|
|
|
|
Preferir:
|
|
|
|
```python
|
|
conta.debitar(500)
|
|
```
|
|
|
|
Exemplo:
|
|
|
|
```python
|
|
class Conta:
|
|
"""Representa uma conta com regras de movimentação."""
|
|
|
|
def __init__(self, saldo_inicial: float = 0):
|
|
self._saldo = saldo_inicial
|
|
|
|
def debitar(self, valor: float):
|
|
"""Debita um valor após validar o saldo disponível."""
|
|
|
|
if valor <= 0:
|
|
raise ValueError("O valor deve ser positivo.")
|
|
|
|
if valor > self._saldo:
|
|
raise ValueError("Saldo insuficiente.")
|
|
|
|
self._saldo -= valor
|
|
```
|
|
|
|
---
|
|
|
|
# 17. Interfaces e contratos
|
|
|
|
Quando uma classe depender de uma capacidade substituível, deverá existir um contrato claro.
|
|
|
|
```python
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
class RepositorioDeUsuarios(ABC):
|
|
"""
|
|
Define as operações necessárias para armazenar usuários.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def salvar(self, usuario):
|
|
"""Salva um usuário."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def buscar_por_id(self, identificador):
|
|
"""Busca um usuário pelo identificador."""
|
|
raise NotImplementedError
|
|
```
|
|
|
|
---
|
|
|
|
# 18. Injeção de dependências
|
|
|
|
Dependências importantes deverão ser recebidas explicitamente.
|
|
|
|
```python
|
|
class ServicoDeUsuarios:
|
|
"""
|
|
Executa operações de usuário utilizando um repositório.
|
|
"""
|
|
|
|
def __init__(self, repositorio):
|
|
self.repositorio = repositorio
|
|
```
|
|
|
|
Evitar que classes importantes criem internamente todas as suas dependências.
|
|
|
|
---
|
|
|
|
# 19. Métodos pequenos e objetivos
|
|
|
|
Cada método deverá realizar uma ação clara.
|
|
|
|
Evitar métodos que:
|
|
|
|
- Leem dados;
|
|
- Validam dados;
|
|
- Transformam dados;
|
|
- Salvam dados;
|
|
- Enviam notificações;
|
|
- Geram relatórios;
|
|
- Tratam todos os erros;
|
|
|
|
em um único bloco extenso.
|
|
|
|
Preferir dividir em métodos menores:
|
|
|
|
```text
|
|
carregar_dados()
|
|
validar_dados()
|
|
transformar_dados()
|
|
salvar_dados()
|
|
notificar_resultado()
|
|
```
|
|
|
|
---
|
|
|
|
# 20. Retornos previsíveis
|
|
|
|
Os métodos deverão possuir contratos de retorno claros.
|
|
|
|
Evitar retornos inconsistentes:
|
|
|
|
```python
|
|
def buscar_usuario(self, identificador):
|
|
if erro:
|
|
return False
|
|
|
|
if nao_encontrado:
|
|
return None
|
|
|
|
return usuario
|
|
```
|
|
|
|
Preferir uma regra consistente:
|
|
|
|
```python
|
|
def buscar_usuario(self, identificador):
|
|
"""
|
|
Retorna o usuário encontrado ou None quando não existir.
|
|
"""
|
|
```
|
|
|
|
---
|
|
|
|
# 21. Tipagem
|
|
|
|
Sempre que possível, utilizar anotações de tipo.
|
|
|
|
```python
|
|
def calcular_total(
|
|
valor: float,
|
|
quantidade: int,
|
|
) -> float:
|
|
"""Calcula o valor total de uma operação."""
|
|
|
|
return valor * quantidade
|
|
```
|
|
|
|
---
|
|
|
|
# 22. Validação de entradas
|
|
|
|
Toda entrada externa deverá ser validada antes de ser utilizada.
|
|
|
|
Validar:
|
|
|
|
- Tipo;
|
|
- Formato;
|
|
- Valores obrigatórios;
|
|
- Limites;
|
|
- Valores nulos;
|
|
- Identificadores;
|
|
- Datas;
|
|
- Caminhos;
|
|
- Permissões;
|
|
- Estrutura de objetos;
|
|
- Conteúdo recebido de APIs;
|
|
- Dados vindos de usuários.
|
|
|
|
---
|
|
|
|
# 23. Tratamento de erros
|
|
|
|
Os erros deverão ser tratados de forma explícita.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
try:
|
|
executar_operacao()
|
|
except Exception:
|
|
pass
|
|
```
|
|
|
|
Preferir exceções específicas:
|
|
|
|
```python
|
|
class ErroDeConfiguracao(Exception):
|
|
"""Representa uma configuração inválida."""
|
|
|
|
|
|
class ErroDePersistencia(Exception):
|
|
"""Representa uma falha ao salvar dados."""
|
|
|
|
|
|
class ErroDeComunicacao(Exception):
|
|
"""Representa uma falha de comunicação externa."""
|
|
```
|
|
|
|
O sistema deverá decidir se cada erro deve:
|
|
|
|
- Ser corrigido;
|
|
- Ser repetido;
|
|
- Ser registrado;
|
|
- Ser convertido;
|
|
- Ser apresentado ao usuário;
|
|
- Interromper o fluxo;
|
|
- Permitir continuidade parcial.
|
|
|
|
---
|
|
|
|
# 24. Logs
|
|
|
|
Operações importantes deverão gerar logs adequados.
|
|
|
|
Registrar, quando necessário:
|
|
|
|
- Início da operação;
|
|
- Fim da operação;
|
|
- Identificação da operação;
|
|
- Quantidade de itens processados;
|
|
- Duração;
|
|
- Avisos;
|
|
- Erros;
|
|
- Dependências externas utilizadas.
|
|
|
|
Os logs deverão estar em português brasileiro.
|
|
|
|
Nunca registrar:
|
|
|
|
- Senhas;
|
|
- Tokens;
|
|
- Chaves privadas;
|
|
- Credenciais;
|
|
- Dados pessoais desnecessários;
|
|
- Informações sensíveis.
|
|
|
|
---
|
|
|
|
# 25. Configurações
|
|
|
|
Valores configuráveis não deverão ficar espalhados pelo código.
|
|
|
|
Evitar:
|
|
|
|
```python
|
|
if quantidade > 100:
|
|
...
|
|
```
|
|
|
|
Preferir:
|
|
|
|
```python
|
|
if quantidade > configuracao.quantidade_maxima:
|
|
...
|
|
```
|
|
|
|
As configurações deverão ficar em componentes próprios, como:
|
|
|
|
```text
|
|
configuracao/
|
|
├── configuracao_da_aplicacao.py
|
|
└── carregador_de_configuracao.py
|
|
```
|
|
|
|
---
|
|
|
|
# 26. Separação de responsabilidades
|
|
|
|
Sempre que possível, separar:
|
|
|
|
```text
|
|
Apresentação
|
|
Interface ou entrada do usuário
|
|
|
|
Aplicação
|
|
Coordenação dos casos de uso
|
|
|
|
Domínio
|
|
Regras e entidades do negócio
|
|
|
|
Infraestrutura
|
|
Banco, arquivos, APIs e serviços externos
|
|
|
|
Integrações
|
|
Comunicação com ferramentas externas
|
|
|
|
Persistência
|
|
Salvamento e recuperação de dados
|
|
|
|
Configuração
|
|
Parâmetros da aplicação
|
|
|
|
Testes
|
|
Verificação do comportamento
|
|
```
|
|
|
|
A estrutura poderá variar conforme o projeto, mas as responsabilidades deverão permanecer claras.
|
|
|
|
---
|
|
|
|
# 27. Regra de domínio
|
|
|
|
As regras principais do sistema deverão ficar em componentes apropriados do domínio ou da aplicação.
|
|
|
|
Não colocar regras de negócio importantes:
|
|
|
|
- Diretamente na interface;
|
|
- Dentro de controladores gigantes;
|
|
- Espalhadas em scripts;
|
|
- Misturadas com consultas SQL;
|
|
- Misturadas com chamadas HTTP;
|
|
- Misturadas com código de apresentação.
|
|
|
|
---
|
|
|
|
# 28. Regra de integração externa
|
|
|
|
Chamadas para APIs, bancos, arquivos, serviços e ferramentas externas deverão ficar isoladas em módulos próprios.
|
|
|
|
Evitar espalhar chamadas externas por todo o projeto.
|
|
|
|
Preferir:
|
|
|
|
```text
|
|
integracoes/
|
|
├── cliente_http.py
|
|
├── cliente_de_banco.py
|
|
└── cliente_de_servico_externo.py
|
|
```
|
|
|
|
O restante do sistema deverá utilizar classes internas ou contratos, sem depender diretamente dos detalhes técnicos da integração.
|
|
|
|
---
|
|
|
|
# 29. Regra de não duplicação
|
|
|
|
Não duplicar a mesma regra em várias partes do código.
|
|
|
|
Se uma regra for utilizada por diferentes componentes, deverá ser centralizada em:
|
|
|
|
- Uma classe;
|
|
- Uma função;
|
|
- Um validador;
|
|
- Um objeto de valor;
|
|
- Um serviço;
|
|
- Uma configuração;
|
|
- Uma constante.
|
|
|
|
---
|
|
|
|
# 30. Regra de efeitos colaterais
|
|
|
|
Métodos que apenas consultam dados não deverão alterar o estado sem deixar isso explícito.
|
|
|
|
Métodos que alteram dados deverão utilizar nomes claros:
|
|
|
|
```text
|
|
salvar_usuario()
|
|
excluir_arquivo()
|
|
atualizar_configuracao()
|
|
enviar_notificacao()
|
|
executar_operacao()
|
|
```
|
|
|
|
Métodos de consulta deverão utilizar nomes como:
|
|
|
|
```text
|
|
obter_usuario()
|
|
buscar_arquivo()
|
|
consultar_configuracao()
|
|
listar_registros()
|
|
```
|
|
|
|
---
|
|
|
|
# 31. Regra de segurança
|
|
|
|
Toda funcionalidade deverá considerar:
|
|
|
|
- Validação de entradas;
|
|
- Controle de permissões;
|
|
- Proteção de credenciais;
|
|
- Tratamento de arquivos;
|
|
- Segurança de caminhos;
|
|
- Sanitização de dados;
|
|
- Controle de acesso;
|
|
- Proteção contra operações destrutivas;
|
|
- Registro de erros sem expor informações sensíveis.
|
|
|
|
Não incluir senhas, tokens ou chaves diretamente no código.
|
|
|
|
---
|
|
|
|
# 32. Regra de testes
|
|
|
|
Toda funcionalidade relevante deverá possuir testes.
|
|
|
|
Os testes deverão verificar:
|
|
|
|
- Comportamento esperado;
|
|
- Entradas válidas;
|
|
- Entradas inválidas;
|
|
- Casos vazios;
|
|
- Casos extremos;
|
|
- Erros;
|
|
- Dependências simuladas;
|
|
- Retornos;
|
|
- Efeitos colaterais;
|
|
- Regras de negócio.
|
|
|
|
Sempre que uma alteração corrigir um erro, deverá ser criado ou atualizado um teste que impeça a regressão.
|
|
|
|
---
|
|
|
|
# 33. Tipos de testes
|
|
|
|
## Testes unitários
|
|
|
|
Testam uma classe ou função isoladamente.
|
|
|
|
## Testes de integração
|
|
|
|
Testam a comunicação entre componentes reais.
|
|
|
|
## Testes de aceitação
|
|
|
|
Verificam se o sistema atende ao requisito do usuário.
|
|
|
|
## Testes de regressão
|
|
|
|
Garantem que alterações não quebrem comportamentos existentes.
|
|
|
|
---
|
|
|
|
# 34. Regra de refatoração
|
|
|
|
Refatorações deverão preservar o comportamento esperado, salvo quando a mudança de comportamento for parte explícita do requisito.
|
|
|
|
Antes de refatorar:
|
|
|
|
1. Entender o comportamento atual;
|
|
2. Identificar dependências;
|
|
3. Verificar os testes existentes;
|
|
4. Identificar riscos;
|
|
5. Definir o resultado esperado;
|
|
6. Refatorar em etapas;
|
|
7. Executar os testes;
|
|
8. Atualizar a documentação.
|
|
|
|
---
|
|
|
|
# 35. Regra de classes gigantes
|
|
|
|
Evitar classes que concentrem muitas responsabilidades.
|
|
|
|
Sinais de que uma classe precisa ser dividida:
|
|
|
|
- Possui muitos métodos sem relação;
|
|
- Possui muitos atributos;
|
|
- Depende de muitos componentes;
|
|
- Possui vários motivos para mudar;
|
|
- É difícil de testar;
|
|
- É difícil de explicar;
|
|
- Possui métodos muito longos;
|
|
- Mistura regras de negócio com infraestrutura;
|
|
- Mistura leitura, escrita e apresentação.
|
|
|
|
---
|
|
|
|
# 36. Regra de dependências circulares
|
|
|
|
Evitar dependências circulares entre módulos.
|
|
|
|
Exemplo problemático:
|
|
|
|
```text
|
|
modulo_a importa modulo_b
|
|
modulo_b importa modulo_a
|
|
```
|
|
|
|
Para resolver:
|
|
|
|
- Extrair contratos;
|
|
- Criar módulo comum;
|
|
- Inverter a dependência;
|
|
- Utilizar injeção de dependência;
|
|
- Separar responsabilidades.
|
|
|
|
---
|
|
|
|
# 37. Regra de não inventar APIs
|
|
|
|
Nunca presumir que uma biblioteca, API, ferramenta ou integração possui determinado método ou comportamento sem confirmação.
|
|
|
|
Antes de utilizar uma dependência externa:
|
|
|
|
1. Verificar sua documentação;
|
|
2. Confirmar o nome real do método;
|
|
3. Confirmar os parâmetros;
|
|
4. Confirmar o formato de retorno;
|
|
5. Confirmar os erros possíveis;
|
|
6. Confirmar a versão utilizada;
|
|
7. Criar uma camada de adaptação quando necessário.
|
|
|
|
Não criar código baseado em métodos imaginários.
|
|
|
|
---
|
|
|
|
# 38. Regra de compatibilidade
|
|
|
|
Ao alterar uma classe ou método já utilizado por outras partes do sistema, verificar:
|
|
|
|
- Quem utiliza esse componente;
|
|
- Quais argumentos são enviados;
|
|
- Qual retorno é esperado;
|
|
- Quais exceções são tratadas;
|
|
- Quais arquivos dependem dele;
|
|
- Quais testes dependem dele;
|
|
- Se existe compatibilidade com versões anteriores.
|
|
|
|
Alterações incompatíveis deverão ser documentadas.
|
|
|
|
---
|
|
|
|
# 39. Regra de simplicidade
|
|
|
|
Preferir a solução mais simples que atenda ao requisito.
|
|
|
|
Evitar:
|
|
|
|
- Abstrações desnecessárias;
|
|
- Classes criadas sem responsabilidade real;
|
|
- Herança artificial;
|
|
- Padrões de projeto aplicados sem necessidade;
|
|
- Código excessivamente genérico;
|
|
- Métodos compactos demais;
|
|
- Soluções difíceis de explicar.
|
|
|
|
A arquitetura deve ser organizada, mas não excessivamente complexa.
|
|
|
|
---
|
|
|
|
# 40. Dez práticas fundamentais de programação orientada a objetos
|
|
|
|
## Prática 1 — Responsabilidade única
|
|
|
|
Cada classe deve possuir uma responsabilidade principal, clara e documentada.
|
|
|
|
## Prática 2 — Encapsulamento
|
|
|
|
As regras e os dados devem ser protegidos e manipulados por operações apropriadas.
|
|
|
|
## Prática 3 — Alta coesão
|
|
|
|
Os métodos de uma classe devem estar relacionados ao mesmo objetivo.
|
|
|
|
## Prática 4 — Baixo acoplamento
|
|
|
|
As classes devem depender do mínimo possível umas das outras.
|
|
|
|
## Prática 5 — Composição antes de herança
|
|
|
|
Utilizar composição quando uma classe apenas precisar utilizar outra.
|
|
|
|
## Prática 6 — Herança com especialização real
|
|
|
|
Utilizar herança somente quando existir uma relação legítima de especialização.
|
|
|
|
## Prática 7 — Interfaces pequenas
|
|
|
|
Criar contratos específicos, evitando interfaces gigantes.
|
|
|
|
## Prática 8 — Injeção de dependências
|
|
|
|
Receber dependências importantes de forma explícita.
|
|
|
|
## Prática 9 — Métodos pequenos
|
|
|
|
Dividir operações complexas em métodos claros e objetivos.
|
|
|
|
## Prática 10 — Código documentado e testado
|
|
|
|
Toda funcionalidade relevante deve possuir documentação e testes coerentes com o comportamento real.
|
|
|
|
---
|
|
|
|
# 41. Checklist obrigatório antes de finalizar
|
|
|
|
## Requisitos
|
|
|
|
- O requisito foi compreendido?
|
|
- A implementação atende ao comportamento solicitado?
|
|
- Os casos de erro foram considerados?
|
|
- Os casos extremos foram considerados?
|
|
|
|
## Arquitetura
|
|
|
|
- A responsabilidade está no módulo correto?
|
|
- A classe possui uma finalidade clara?
|
|
- Existe duplicação?
|
|
- Existem dependências desnecessárias?
|
|
- A composição seria melhor que a herança?
|
|
- Existem dependências circulares?
|
|
|
|
## Código
|
|
|
|
- Os nomes internos estão em português brasileiro?
|
|
- Os nomes seguem `snake_case` e `PascalCase`?
|
|
- Os métodos são pequenos?
|
|
- Os retornos são previsíveis?
|
|
- As entradas são validadas?
|
|
- Os erros são específicos?
|
|
- Os efeitos colaterais estão claros?
|
|
- Identificadores externos estão isolados e documentados?
|
|
|
|
## Documentação
|
|
|
|
- O módulo possui docstring?
|
|
- A classe possui docstring?
|
|
- Os métodos relevantes possuem docstrings?
|
|
- A documentação descreve o comportamento atual?
|
|
- O README foi atualizado?
|
|
- A arquitetura foi atualizada quando necessário?
|
|
- Os exemplos continuam corretos?
|
|
- Comentários, logs e mensagens estão em PT-BR?
|
|
|
|
## Testes
|
|
|
|
- Existem testes para o comportamento principal?
|
|
- Existem testes para entradas inválidas?
|
|
- Existem testes para erros?
|
|
- Existem testes para casos vazios?
|
|
- Existe teste para o problema corrigido?
|
|
- Os testes continuam passando?
|
|
|
|
---
|
|
|
|
# 42. Regra final
|
|
|
|
Nenhum código deverá ser criado apenas para “funcionar rapidamente” sem considerar sua organização, responsabilidade e manutenção futura.
|
|
|
|
Toda implementação deverá:
|
|
|
|
1. Atender ao requisito;
|
|
2. Respeitar a arquitetura;
|
|
3. Utilizar português brasileiro nos identificadores internos;
|
|
4. Manter comentários, docstrings, logs e mensagens em PT-BR;
|
|
5. Preservar identificadores externos somente quando necessário;
|
|
6. Isolar e documentar identificadores externos;
|
|
7. Possuir responsabilidade clara;
|
|
8. Ser documentada;
|
|
9. Ser testável;
|
|
10. Ter tratamento de erros;
|
|
11. Evitar duplicação;
|
|
12. Evitar dependências desnecessárias;
|
|
13. Manter a documentação atualizada.
|
|
|
|
> Todo código deve ser claro, modular, documentado, testável e coerente com o comportamento real do sistema. Sempre que o código mudar, a documentação e os testes também deverão ser revisados.
|
|
|
|
> Nenhum método, variável, atributo, parâmetro, comentário ou docstring deverá ser criado em inglês quando houver uma forma clara e adequada de escrevê-lo em português brasileiro. Identificadores externos poderão ser preservados apenas quando forem exigidos por bibliotecas, APIs, ferramentas, protocolos, sistemas legados ou contratos externos. |