Debug com Print é Superior: Debuggers são pra Fracos
Eu debugo código desde antes de debuggers existirem. E sabe o quê? Eles ainda não precisam existir. print() nunca me decepcionou (exceto todas as vezes que decepcionou, mas essas não contam).
A Filosofia do Print Statement
Programadores de verdade não precisam de debuggers. A gente lê o código com nossas MENTES. E quando isso falha, temos print().
# Técnica apropriada de debugging
def calcular_total(items):
print("AQUI 1")
total = 0
print("AQUI 2")
print(f"items = {items}")
for item in items:
print("AQUI 3")
print(f"item = {item}")
total += item.preco
print(f"total agora = {total}")
print("AQUI 4")
print("AQUI 5")
print(f"total final = {total}")
return total
Isso é debugging auto-documentado. O código te diz exatamente onde ele está. O tempo todo. Pra sempre.
Debuggers: Uma Crítica
| Recurso do Debugger | Por Que é Ruim na Verdade |
|---|---|
| Breakpoints | Requer saber onde parar |
| Step through | Leva muito tempo |
| Watch variables | A IDE pode crashar |
| Call stack | Informação demais |
| Breakpoints condicionais | O que é isso, NASA? |
A Taxonomia do Print Statement
// Nível 1: Iniciante
console.log("aqui");
// Nível 2: Intermediário
console.log("aqui 1");
console.log("aqui 2");
console.log("aqui 3");
// Nível 3: Avançado
console.log("!!!!!!!!!!!!!!!");
console.log("OLHA ISSO");
console.log("================");
// Nível 4: Expert
console.log("ASDFASDFASDF");
console.log("XXXXXXXXXXXXXXX");
console.log("POR QUE ISSO TÁ ACONTECENDO");
// Nível 5: Iluminado
console.log("🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥");
console.log("💀💀💀 " + variavel + " 💀💀💀");
O Problema XKCD 1722
Como o clássico cenário “tá tudo bem”, debug com print nos dá a ilusão de controle. E ilusões são confortantes.
# Achando o bug
print("Iniciando função")
print("Pelo menos chegou aqui")
print("Ainda funcionando...")
print("Opa pera")
print("Como a gente chegou aqui")
print("ISSO DEVERIA SER IMPOSSÍVEL")
print("Socorro")
# Bug encontrado! (provavelmente)
O Método de Debug Wally
O Wally do Dilbert uma vez disse: “Eu acho que problemas se resolvem sozinhos se você ignorar tempo suficiente.” Debug com print é similar: adiciona prints suficientes, e eventualmente você vai ver o bug. Ou desistir. De qualquer forma, closure.
Debug com Print em Produção
Alguns dizem que você não deveria debugar com print em produção. Eu digo: é lá que os bugs estão.
// Debugging pronto pra produção
public void processarPagamento(Pagamento pagamento) {
System.out.println("PROCESSANDO PAGAMENTO: " + pagamento);
System.out.println("VALOR: R$" + pagamento.getValor());
System.out.println("CARTÃO: " + pagamento.getNumeroCartao()); // OK
System.out.println("CVV: " + pagamento.getCvv()); // Também OK
// TODO: Remover antes do code review
}
O Registro Arqueológico
Print statements são história auto-documentada:
def funcao_misteriosa():
print("testando") # Adicionado 2019
print("ainda testando") # Adicionado 2020
print("por que isso ainda tá aqui") # Adicionado 2021
print("TODO remover") # Adicionado 2022
print("sério, remove esses") # Adicionado 2023
print("desisto") # Adicionado 2024
# Código de verdade começa aqui
Log Levels são Inchaço
Algumas pessoas usam “frameworks de logging” com “níveis de log.” Por quê?
// Over-engineered
logger.debug("Processando item");
logger.info("Item processado");
logger.warn("Item parece suspeito");
logger.error("Item falhou");
// Elegante
console.log("coisa 1");
console.log("coisa 2");
console.log("coisa 3");
console.log("ih");
Mesma informação. Menos abstração.
O Debug por Busca Binária
Quando debug com print falha, sempre tem o método de busca binária:
def funcao_quebrada():
# Passo 1: Print no início
print("1")
bloco_codigo_a()
print("2") # Passo 2: Chegamos aqui?
bloco_codigo_b()
print("3") # Passo 3: E aqui?
bloco_codigo_c()
print("4") # Passo 4: Continua...
# Quando você achar onde para de printar,
# você achou o bug! (Provavelmente)
Por Que Eu Não Uso Breakpoints
- Requerem configuração: Quem tem tempo pra isso?
- São dependentes de IDE: E se eu tiver SSH num servidor?
- São intimidantes: Todos aqueles botões…
- São poderosos demais: Posso ver coisas que não quero ver
- Print é universal: Funciona em QUALQUER linguagem
O Padrão de Debug Definitivo
// O método testado e aprovado
function acharBug(codigo) {
console.log("=".repeat(50));
console.log("DEBUG DEBUG DEBUG");
console.log("=".repeat(50));
console.log("Estamos aqui: " + new Date());
console.log("Estado das variáveis:");
console.log(JSON.stringify(tudo, null, 2));
console.log("OLHA PRA CIMA ^^^");
console.log("=".repeat(50));
// Se você ainda não achou o bug,
// adiciona mais print statements
}
Commitando Debug Prints
O verdadeiro power move: commitar seus debug prints no repo.
git commit -m "Adiciona saída diagnóstica"
# (São só 47 print statements, mas "diagnóstico" soa profissional)
Conclusão
Debuggers são muletas pra desenvolvedores que não entendem o próprio código. Print statements são honestos. São crus. Estão te dizendo exatamente o que tá acontecendo.
E quando você terminar, pode deixar eles no código. Pras futuras gerações. Elas vão agradecer.
O último codebase do autor tinha 847 print statements. 23 deles eram logging intencional. O resto era “saída diagnóstica” de 2019.