Código Simples

Escreva o código mais simples e legível que produz o resultado necessário, eliminando lógica complicada, abstrações e extras que não alteram a saída.

O que é Código Simples?

Esta skill orienta o agente a produzir código minimalista e de fácil compreensão humana, priorizando a clareza sobre abstrações desnecessárias. É útil para qualquer linguagem e plataforma (Claude Code, Cursor, Codex, etc.), sempre que o usuário pedir código simples, limpo, de fácil manutenção ou criticar código excessivamente complexo. A skill funciona através de um processo estruturado: primeiro, definir claramente os requisitos; depois, escrever a versão mais simples com funções, condicionais e loops; em seguida, aplicar o 'teste de exclusão' para remover componentes que não são essenciais; e, por fim, adicionar testes que cobrem todas as regras e casos de contorno. O foco está em construir para os requisitos de hoje, usar construções mais diretas (como `if` em vez de padrões de design), manter o fluxo reto com retornos antecipados, nomear variáveis com palavras comuns, e falhar de forma ruidosa. A skill também trata de casos específicos como verificação de overflow numérico e decisões sobre estado intermediário em operações de múltiplas etapas.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/m2vic/claude-skills/tree/HEAD/plugins/simple-code/skills/simple-code

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Código Simples faz?

Dois programas que produzem a mesma saída não são iguais: aquele que uma pessoa entende mais rápido é melhor. Cada classe, auxiliar, parâmetro e camada é algo que o próximo leitor precisa aprender, então cada um tem que merecer seu lugar alterando o que o programa faz.

O objetivo é um código que um novo colega de equipe possa ler de cima a baixo uma vez, explicar e alterar com segurança.

Como trabalhar

  1. Declare o trabalho. O que entra, o que sai, quais regras e casos de contorno foram solicitados, e qualquer objetivo de qualidade ou design que o usuário nomeou. Todos estes são requisitos. Trabalhe a partir desta lista, não a partir do que o código pode precisar um dia.
  2. Escreva a versão mais simples primeiro. Funções simples, comandos if, loops e dados literais, na ordem em que uma pessoa descreveria os passos. Este é o design que você mantém a menos que ele falhe em um requisito declarado.
  3. Execute o teste de exclusão. Para cada classe, auxiliar, parâmetro, constante, importação, ramificação e try: remova-o mentalmente. Se todo requisito declarado, incluindo metas de qualidade, ainda for atendido, remova-o de verdade.
  4. Teste e mantenha o teste. Cubra toda regra e caso de contorno declarados em um pequeno arquivo de teste simples ao lado do código, seguindo as convenções do projeto, a menos que o usuário diga o contrário. Testes mostram ao próximo leitor quais são as regras e tornam as alterações seguras, portanto fazem parte do trabalho e não são um extra.
  5. Relate de forma simples. Diga o que você construiu. Se você deliberadamente omitiu algo, nomeie em uma linha ("Sem CLI ou logging, já que nenhum foi solicitado"), para que o usuário possa pedir.

Como é o simples

Construa para os requisitos de hoje. Um "talvez adicionemos mais depois" não é uma funcionalidade para construir agora. Código simples é o mais fácil de estender, porque não há nada para contornar. Adicionar um cupom deve significar adicionar uma linha, não primeiro aprender um framework.

Atenda aos objetivos de qualidade declarados da maneira mais simples. Quando uma solicitação disser "pronto para produção", "robusto", "escalável" ou "nível empresarial", pergunte o que poderia realmente dar errado com este código em uso, e então lide diretamente com essas coisas: entrada ruim é rejeitada, falhas são visíveis, nada é perdido silenciosamente, o dinheiro fecha certo ao centavo. Essas palavras exigem esse cuidado. Elas não exigem camadas, sistemas de plugins ou frameworks.

Entregue um design que o usuário pediu. Quando alguém pedir uma arquitetura ou uma estrutura específica, entregue uma em sua menor forma útil, e não responda que deve esperar. Se mais formulários estão por vir, por exemplo, o design pode ser funções de verificação compartilhadas que o próximo formulário reutiliza, com uma linha sobre como adicionar uma. Pare antes de um motor que apenas casos imaginados precisariam.

Use a construção mais simples que funciona, aproximadamente nesta ordem:

  • um valor ou um dicionário literal antes de um sistema de configuração
  • if/elif ou um dicionário de consulta antes de um registro, estratégia, fábrica ou sistema de plugins
  • uma função antes de uma classe ou um struct com métodos; adicione uma apenas quando ela mantém estado que várias operações compartilham
  • um tipo concreto antes de uma interface ou genéricos; adicione-os apenas quando duas implementações ou tipos reais precisam deles hoje
  • código sequencial antes de goroutines e canais, a menos que concorrência seja o requisito
  • biblioteca padrão e auxiliares já no projeto antes de uma nova dependência

Mantenha o fluxo reto. Retorne cedo em vez de aninhar; mais de cerca de três níveis de profundidade geralmente significa que o fluxo pode ser achatado. Faça uma coisa por linha. Prefira um loop legível a uma compreensão aninhada, ternários encadeados, reduce ou uma regex engenhosa. Evite metaprogramação, reflexão e decoradores personalizados, a menos que a tarefa seja especificamente sobre eles.

Deixe pequenas repetições em paz. Três linhas semelhantes são frequentemente mais claras do que um auxiliar com flags. Extraia uma função quando ela dá a uma ideia real um bom nome ou quando a lógica deve permanecer sincronizada, não meramente porque duas linhas se parecem. Não adicione parâmetros que apenas um chamador usa ou que ninguém pediu.

Nomeie as coisas para um humano. Use palavras completas e comuns (taxa_de_envio, não te ou ContextoCalculoTaxa). Um bom nome elimina a necessidade de um comentário.

Comente apenas o porquê. Anote uma regra ou restrição surpreendente. Pule comentários que repetem o código, banners de seção e docstrings longos que reafirmam a assinatura.

Lide com as falhas que podem acontecer e falhe ruidosamente. Valide o que os requisitos ou um limite real (entrada do usuário, rede, arquivos) exigem, e retorne um erro claro para entrada ruim em vez de produzir uma resposta errada plausível. Se o código pula ou descarta dados, torne isso visível para quem o executa, por exemplo, com uma contagem em uma linha de log. Não capture uma exceção apenas para relançá-la, e não se proteja contra estados que o código não pode alcançar.

Verifique números de fora antes de fazer aritmética com eles. Uma quantidade, valor ou contagem de uma requisição pode ser enorme, e adicioná-la ou multiplicá-la pode causar um overflow para um valor pequeno ou negativo que passa em todas as verificações posteriores. Compare o valor recebido com seu limite (estoque, um máximo) antes de adicioná-lo a qualquer coisa, e adicione um teste que envie o maior valor que o tipo pode armazenar. Isto é um if, não código extra.

Decida o que uma reinicialização faz no meio de uma alteração de várias etapas. Quando o código altera o estado salvo, chama algo lento ou externo, como um provedor de pagamento, e então altera o estado novamente, pergunte o que acontece se o processo parar entre essas etapas. Salve um estado intermediário claro (como pendente) antes da chamada. Na reinicialização, não adivinhe: não desfaça uma etapa que pode ter sido bem-sucedida, como devolver o estoque por uma cobrança que pode ter sido concluída, e não reabra o trabalho para que uma repetição possa cobrar duas vezes. Deixe o registro em seu estado intermediário, mantenha-o bloqueado e torne-o visível, por exemplo, registrando quantos estão pendentes na inicialização, para que uma pessoa possa resolvê-lo. Escreva esta regra em uma ou duas linhas do design e teste-a reiniciando com um registro pendente.

Não adicione extras. Sem CLI, logging, configuração, repetições, cache, métricas ou hierarquias de tipo, a menos que tenham sido solicitados, ou que o trabalho ou uma meta declarada não possa ser cumprida sem eles. Código que roda sem supervisão, por exemplo, precisa de alguma forma de relatar problemas.

Ao alterar código existente

Siga as convenções do projeto e faça a menor alteração que realiza o trabalho. Não reestruture o código vizinho ou introduza um novo padrão de passagem. Mantenha código complicado que funciona, a menos que simplificá-lo seja a tarefa ou sua alteração exija isso; se parecer removível, mencione isso.

O que simples não significa

Nunca abra mão de nenhum destes para economizar linhas:

  • Comportamento correto, incluindo toda regra e caso de contorno declarados
  • Segurança: validação de entrada nos limites de confiança, consultas seguras, sem segredos no código
  • Precisão que importa: o dinheiro deve fechar certo ao centavo, incluindo casos de meio centavo, e um teste deve provar isso. Use o método mais simples que faça isso. Um float com um pequeno auxiliar de arredondamento que elimina ruído binário é aceitável quando os preços têm poucas casas decimais e um float cruza o limite da função de qualquer forma. Recorra a centavos inteiros ou frações exatas como big.Rat apenas quando uma regra declarada precisar deles, ou quando um teste mostrar que o método mais simples obtém um resultado errado
  • Desempenho que a tarefa realmente pediu ou uma medição mostrou que importa
  • Uma abstração que o usuário explicitamente solicitou; construa-a, em sua forma mais simples

Menos linhas também não é o objetivo. Código golf é tão difícil de ler quanto engenharia excessiva, então prefira a versão mais longa quando for mais clara. Uma função longa que faz tudo não é simples: quando uma função mistura etapas distintas como leitura, análise e resumo, dê a cada etapa uma função bem nomeada. Quando um problema tem complexidade real, mantenha-a, isole-a em um lugar bem nomeado e explique o porquê em um comentário curto.

Exemplo

Tarefa: aplicar um desconto de membro e cobrar 5 de frete em pedidos abaixo de 50.

Evite isto. Dá a mesma saída com muito mais para ler:

type DiscountStrategy interface {
	Apply(amount float64) float64
}

type MemberDiscount struct{}

func (MemberDiscount) Apply(amount float64) float64 {
	return amount * 0.95
}

type PriceCalculator struct {
	Strategy          DiscountStrategy
	ShippingThreshold float64
	ShippingFee       float64
}

func (c PriceCalculator) Calculate(amount float64) float64 {
	discounted := c.Strategy.Apply(amount)
	if discounted < c.ShippingThreshold {
		return discounted + c.ShippingFee
	}
	return discounted
}

Escreva isto:

func FinalPrice(amount float64, isMember bool) float64 {
	if isMember {
		amount = amount * 0.95
	}
	if amount < 50 {
		amount = amount + 5
	}
	return amount
}

Adicionar um desconto VIP depois leva mais um if, e ninguém precisou aprender uma interface e três tipos para fazer isso.

Habilidades Relacionadas