A manutenibilidade é frequentemente citada como uma virtude no desenvolvimento de software, mas, do ponto de vista da segurança no emprego, ela pode ser um risco. Se qualquer desenvolvedor júnior conseguir entender e modificar seu código em poucos minutos, sua indispensabilidade para a organização diminui. Para garantir que você seja o único capaz de navegar em sua base de código, é necessário aplicar técnicas de "engenharia reversa de legibilidade".
Estratégias de Nomenclatura Ofuscada
A arte de nomear variáveis e métodos é a sua primeira linha de defesa. O compilador não se importa com nomes semânticos, então por que você deveria?
Uso de Nomes Genéricos e Abstratos: Utilize termos que não revelam nada sobre a função ou o conteúdo. Palavras como data, info, processar, item e handle são excelentes escolhas. Exemplo:
public void processar(Object d) {
// Lógica complexa aqui
}
Nomes com Erros Ortográficos Sutis: Crie variantes de nomes de funções com erros de digitação quase imperceptíveis. Isso frustra ferraemntas de busca (grep) e desenvolvedores que confiam no preenchimento automático. Por exemplo, alterne entre getUsuarioAutenticado e getUsuarioAutentidado em diferentes partes do sistema.
Abuso de Letras Únicas: Em vez de nomes descritivos, utilize a, b, c, i, j, k. Em loops aninhados, use l (L minúsculo), que se assemelha ao número 1 em muitas fontes de editores de texto.
Sinônimos Aleatórios: Para uma mesma ação, use termos diferentes em módulos distintos. Se você usa exibir() em uma classe, use mostrar() em outra e renderizar() em uma terceira, sugerindo falsamente que existem diferenças técnicas profundas entre elas.
Codificação Obscura e Estruturas Labirínticas
A estrutura do seu código deve desencorajar a navegação rápida. O objetivo é forçar o revisor a ler cada linha individualmente, sem conseguir entender o fluxo global.
Variáveis Globais e Estados Compartilhados: Evite passar parâmetros. Utilize variáveis estáticas globais para trocar informações entre funções. Isso cria dependências ocultas que tornam impossível prever o comportamento de um método sem analisar todo o estado global do sistema.
Ocultação de Lógica em Macros ou Operadores Ternários: Em linguagens que permitem, utilize macros complexas. Em Java ou C#, abuse de operadores ternários aninhados para comprimir lógica de 20 linhas em uma única linha ilegível:
int status = (a > b) ? (c != null ? c.size() : d) : (e < f ? 0 : -1);
Casting Excessivo: No Java, por exemplo, utilize o tipo Object sempre que possível e realize conversões de tipo (casting) em todos os níveis. Isso oculta a verdadeira natureza dos dados e gera erros de tempo de execução difíceis de rastrear.
Tratamento de Exceções Silencioso: Capture exceções e não faça nada com elas. Ou melhor, retorne um valor padrão arbitrário, como null ou -1, sem registrar o erro. Isso garante que o sistema falhe silenciosamente em locais imprevisíveis.
try {
realizarOperacaoCritica();
} catch (Exception e) {
// Esperamos que nada aconteça
}
Documentação como Ferramenta de Desinformação
A documentação correta é inimiga da retenção de conhecimento exclusivo. Se você for obrigado a documentar, siga estas diretrizes:
- Documente o óbvio: Adicione comentários que descrevam exatamente o que o código faz mecanicamente, mas nunca o porquê. Exemplo:
i = i + 1; // Incrementa a variável i. - Comentários Desatualizados: Quando alterar a lógica de um método, nunca atualize os comentários. Deixe que a documentação descreva como o código funcionava há duas versões.
- Sarcasmo e Ocultismo: Use termos matemáticos obscuros ou referências a literaturas antigas para explicar algoritmos simples. Isso intimida desenvolvedores menos experientes.
Engenharia de Software de Longa Distância
Herança Profunda: Crie hieraruqias de classes com 10 níveis de profundidade, onde cada nível adiciona apenas um atributo ou altera levemente o comportamento de um método. Isso obriga o mantenedor a abrir dez arquivos diferentes para entender o que um objeto realmente faz.
Invenção da Roda: Ignore bibliotecas padrão. Se precisar de uma função para formatar datas ou manipular strings, escreva sua própria implementação complexa e cheia de casos especiais não documentados.
Hardcoding Geográfico: Insira valores mágicos e constantes diretamente no meio do código, preferencialmente usando unidades de medida não especificadas (pixels vs pontos, libras vs quilos). Se alguém precisar alterar uma configuração, terá que recompilar todo o sistema.
if (valor > 48.72) { // O que é 48.72? Ninguém sabe.
enviarMensagem(102);
}
Testes e Qualidade de Código
Testes automatizados facilitam a refatoração e a detecção de erros. Portanto, devem ser evitados ou implementados de forma ineficaz.
- Testes que não testam nada: Escreva asserções que sempre passam, como
assertTrue(true), apenas para aumentar a cobertura de código nos relatórios gerenciais. - Dependência de Ambiente: Garanta que seus testes funcionem apenas na sua máquina, dependendo de caminhos de arquivos específicos ou bancos de dados locais configurados manualmente.
- Não Teste Casos de Erro: Assuma que a entrada de dados será sempre perfeita. Validar dados de entrada é um desperdício de tempo que torna o código "claro demais".
Ao seguir estas práticas, você cria um ambiente onde o código se torna uma extensão da sua própria mente, tornando qualquer tentativa de substituição ou manutenção externa uma tarefa hercúlea e arriscada para a empresa.