- Published on
Código Feio vs. Código Bonito
- Authors
- Name
- Wesley Caldas
Código Feio e Funcional vs. Código Bonito e com Performance Ruim: Um Dilema do Desenvolvimento
Recentemente andei fazendo a análise de um código que estava bem legível, porém a performace dele era bem ruim na hora de tratar uma grande quantidade de dados. Nisso notei que um dos grandes dilemas que nós enfrentamos é o equilíbrio entre legibilidade e performance. Nem sempre o código mais eficiente é o mais bonito, e nem sempre o código mais bonito é o mais eficiente. Vou dar um exemplo para ilustrar esse cenário:
Nos exemplos abaixo, o primeiro código é feio, mas eficiente. Já o segundo é mais elegante e legível, porém com performance inferior.
Exemplo 1: Código Feio, Mas Funcional e Performático
static preencherValoresFaltantes(
registros: Registro[],
datasConsolidadas: Date[],
tipoRegistro: TipoRegistro,
) {
const registrosLookup = registros.reduce((mapa, registro) => {
if (registro.tipoRegistro === tipoRegistro) {
const dataRegistro = moment(registro.dataRegistro).format("YYYY-MM-DD");
mapa[dataRegistro] = registro;
}
return mapa;
}, {});
let ultimoRegistro = { ...registros[0] };
return datasConsolidadas.map((dia, i) => {
const diaFormatado = moment(dia).format("YYYY-MM-DD");
const registroEncontrado = registrosLookup[diaFormatado];
if (!registroEncontrado) {
return ultimoRegistro;
}
ultimoRegistro = registroEncontrado;
return registroEncontrado;
});
}
Esse exemplo de código faz duas coisas principais:
- Cria um dicionário de cotações (
lookup
), onde a chave é a data da cotação formatada, e o valor é o objeto de cotação correspondente. - Percorre uma lista de datas consolidadas para verificar se há uma cotação correspondente. Caso contrário, ele usa a última cotação válida.
Características do Código:
- Performance: O código é altamente eficiente. Ao criar o dicionário
lookup
, ele permite que as buscas por cotações sejam feitas em tempo constante O(1). Ou seja, para cada data consolidada, o código apenas consulta o dicionário em vez de fazer uma busca completa no array de cotações. - Complexidade: Apesar de ser eficiente, o código não é exatamente bonito. O uso de
reduce
e o acesso direto aos indices da lista, especialmente para quem não está acostumado a essas práticas. Isso compromete a clareza do código.
Exemplo 2: Código Bonito, Mas com Performance Ruim
static preencherRegistrosFaltantes(
registros: Registro[],
datasConsolidadas: Date[],
TipoRegistro: TipoRegistro,
) {
let ultimoRegistro = { ...registros[0] };
return datasConsolidadas.map((data) => {
const item = registros.find((registro) => registro.tipoRegistro === TipoRegistro && registro.dataRegistro === data);
if (!item) {
return ultimoRegistro;
}
ultimoRegistro = item;
return item;
});
}
Neste segundo exemplo, o código faz basicamente a mesma coisa, mas de maneira mais "elegante" e legível:
- O
lookup
foi removido e, em vez disso, o código faz uma busca direta com o métodofind
dentro do array de cotações.
Características do Código:
- Legibilidade: Esse código é muito mais legível e fácil de entender. Ele utiliza o método
find
de forma clara, o que melhora sua compreensão, especialmente para desenvolvedores que estão acostumados a trabalhar com arrays em JavaScript/TypeScript. - Performance: Apesar de mais legível, o uso de
find
resulta em uma complexidade de O(n²), pois para cada data consolidada, o código precisa percorrer todo o array de cotações. Isso pode ser ineficiente em grandes volumes de dados.
Comparação Direta
Aspecto | Código Feio e Funcional | Código Bonito e com Performance Ruim |
---|---|---|
Legibilidade | Moderada, especialmente para iniciantes | Alta, fácil de entender e manter |
Complexidade | O(n) para buscas nas datas consolidadas | O(n²) devido ao uso de find |
Escalabilidade | Melhor performance para grandes conjuntos de dados | Não escala bem com grandes volumes |
Uso de Estruturas | Uso eficiente de lookup para buscas rápidas | Não utiliza estruturas de busca otimizadas |
Quando Escolher Código Feio e Performático?
- Projetos que lidam com grandes volumes de dados: Quando a performance é um fator crítico, como em sistemas de tempo real, grandes bancos de dados ou cálculos intensivos, o código feio, mas eficiente, pode ser necessário.
- Soluções temporárias ou legados: Em sistemas legados, ou quando se precisa de uma solução rápida e funcional, pode ser aceitável sacrificar a legibilidade em prol da performance.
Quando Escolher Código Bonito e Menos Performático?
- Sistemas pequenos ou moderados: Se o volume de dados é relativamente pequeno e a performance não é um fator crítico, o código mais bonito e legível pode ser a melhor escolha, já que ele é mais fácil de manter.
- Equipes grandes: Em ambientes colaborativos, onde muitos desenvolvedores trabalham no mesmo código, um código legível e bem estruturado pode evitar problemas de manutenção e melhorar a produtividade.
O dilema entre código feio e performático vs código bonito e menos eficiente é uma escolha que deve ser feita com base no contexto. Nem sempre o código mais eficiente é a melhor escolha, principalmente quando se lida com equipes grandes ou projetos de manutenção contínua. Por outro lado, sistemas de alta performance e grande escala muitas vezes exigem soluções mais complexas e otimizadas, mesmo que isso signifique sacrificar a clareza.
A chave é sempre encontrar o equilíbrio certo para o seu caso de uso. Se a performance é fundamental, vale a pena investir em uma solução mais eficiente, mesmo que seja mais difícil de entender. Se a manutenção e a legibilidade são prioridades, optar por um código mais simples, mesmo que menos performático, pode ser a melhor abordagem.
No fim das contas, o bom código não é necessariamente aquele que é apenas eficiente ou bonito, mas sim aquele que resolve o problema da melhor forma possível dentro do contexto em que está inserido.