Files
jhonny-editor/code/engine/skills/boas-praticas-oo.md
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

1443 lines
31 KiB
Markdown

# 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.