Fala devs, tudo bem? Nesse post vou falar sobre um tópico importante que às vezes passa despercebido, que são os Code Smells. 🐽
📑 Sobre
Code Smells são sinais de que algo pode estar errado no seu código. Eles não são bugs propriamente ditos, mas indicam problemas de design que podem levar a bugs no futuro. Basicamente, são aqueles "toques" que fazem você pensar: "Hmm, isso pode causar problemas mais tarde." Vamos dar uma olhada em alguns exemplos em JavaScript! 😎
1. Duplicated Code (Código Duplicado)
Código duplicado é tipo quando você cola o mesmo trecho de código em várias partes do seu projeto, aí depois dá aquele nó e vira uma bagunça pra manter tudo certinho.
function calcularPrecoTotalComImposto(preco, taxaImposto) {
return preco + (preco * taxaImposto);
}
function calcularPrecoTotalComDescontoEImposto(preco, desconto, taxaImposto) {
const precoComDesconto = preco - desconto;
// Código duplicado
return precoComDesconto + (precoComDesconto * taxaImposto);
}
Refatorado:
// Código refatorado
function calcularPrecoTotalComImposto(preco, taxaImposto) {
return preco + (preco * taxaImposto);
}
function calcularPrecoTotalComDescontoEImposto(preco, desconto, taxaImposto) {
const precoComDesconto = preco - desconto;
return calcularPrecoTotalComImposto(precoComDesconto, taxaImposto);
}
2. Long Method (Método Longo)
Um método longo é aquele que faz muitas operações em sequência, fazendo com que fique muito difícil de entender e modificar.
// Método longo
function processarPedido(pedido) {
// Validar pedido
if (!pedido.id || !pedido.itens || pedido.itens.length === 0) {
throw new Error('Pedido inválido');
}
// Calcular preço total
const precoTotalInicial = itens.reduce((total, item) => total + item.preco * item.quantidade, 0);
// Aplicar desconto
const precoComDesconto = pedido.desconto ? precoTotalInicial - pedido.desconto : precoTotalInicial;
// Aplicar imposto
const taxaImposto = 0.1;
const precoFinal = precoComDesconto + precoComDesconto * taxaImposto;
// Finalizar pedido
console.log(`Pedido ${pedido.id} processado com preço total ${precoFinal.toFixed(2)}`);
}
Refatorado:
// Método refatorado
function validarPedido(pedido) {
if (!pedido.id || !pedido.itens || pedido.itens.length === 0) {
throw new Error('Pedido inválido');
}
}
function calcularPrecoTotal(itens, desconto = 0) {
const precoTotal = itens.reduce((total, item) => total + item.preco * item.quantidade, 0);
return precoTotal - desconto;
}
function aplicarImposto(precoTotal) {
return precoTotal * 1.1;
}
function processarPedido(pedido) {
validarPedido(pedido);
const precoTotal = calcularPrecoTotal(pedido.itens, pedido.desconto);
const precoTotalComImposto = aplicarImposto(precoTotal);
console.log(`Pedido ${pedido.id} processado com preço total ${precoTotalComImposto.toFixed(2)}`);
}
3. Large Class (Classe Grande)
Uma classe grande tem muitas responsabilidades ou métodos, o que pode indicar que ela está fazendo mais do que deveria e pode ser difícil de manter.
// Classe grande
class Pedido {
constructor(id, itens, desconto) {
this.id = id;
this.itens = itens;
this.desconto = desconto;
}
validar() {
if (!this.id || !this.itens || this.itens.length === 0) {
throw new Error('Pedido inválido');
}
}
calcularPrecoTotal() {
const precoTotal = itens.reduce((total, item) => total + item.preco * item.quantidade, 0);
return precoTotal - desconto;
}
aplicarImposto(precoTotal) {
return precoTotal * 1.1;
}
processar() {
this.validar();
let precoTotal = this.calcularPrecoTotal();
precoTotal = this.aplicarImposto(precoTotal);
console.log(`Pedido ${this.id} processado com preço total ${precoTotal}`);
}
}
Refatorado:
// Classes refatoradas
class ValidadorDePedido {
static validar(pedido) {
if (!pedido.id || !pedido.itens || pedido.itens.length === 0) {
throw new Error('Pedido inválido');
}
}
}
class CalculadoraDePreco {
static calcularPrecoTotal(itens, desconto = 0) {
const precoTotal = itens.reduce((total, item) => total + item.preco * item.quantidade, 0);
return precoTotal - desconto;
}
}
class CalculadoraDeImposto {
static aplicarImposto(precoTotal) {
return precoTotal * 1.1;
}
}
class ProcessadorDePedido {
constructor(pedido) {
this.pedido = pedido;
}
processar() {
ValidadorDePedido.validar(this.pedido);
const precoTotal = CalculadoraDePreco.calcularPrecoTotal(this.pedido.itens, this.pedido.desconto);
const precoTotalComImposto = CalculadoraDeImposto.aplicarImposto(precoTotal);
console.log(`Pedido ${this.pedido.id} processado com preço total ${precoTotalComImposto.toFixed(2)}`);
}
}
4. Feature Envy (Inveja de Funcionalidade)
Feature Envy ocorre quando uma classe utiliza excessivamente métodos ou dados de outra classe, o que pode indicar uma distribuição inadequada de responsabilidades.
// Feature Envy
class Cliente {
constructor(nome, endereco) {
this.nome = nome;
this.endereco = endereco;
}
}
class Pedido {
constructor(cliente, itens) {
this.cliente = cliente;
this.itens = itens;
}
imprimirEtiquetaDeEnvio() {
console.log(`Envio para: ${this.cliente.nome}, ${this.cliente.endereco}`);
}
}
Refatorado:
// Refatorado para mover a responsabilidade
class Cliente {
constructor(nome, endereco) {
this.nome = nome;
this.endereco = endereco;
}
obterEtiquetaDeEnvio() {
return `Envio para: ${this.nome}, ${this.endereco}`;
}
}
class Pedido {
constructor(cliente, itens) {
this.cliente = cliente;
this.itens = itens;
}
imprimirEtiquetaDeEnvio() {
console.log(this.cliente.obterEtiquetaDeEnvio());
}
}
5. Primitive Obsession (Obsessão por Primitivos)
Primitive Obsession é quando se utiliza primitivos (como strings e números) para representar conceitos que deveriam ser encapsulados em classes específicas, resultando em código menos legível e mais difícil de manter.
// Primitive Obsession
class Pedido {
constructor(id, itens, codigoDesconto) {
this.id = id;
this.itens = itens;
this.codigoDesconto = codigoDesconto;
}
aplicarDesconto() {
if (this.codigoDesconto === 'SAVE10') {
// Aplicar desconto de 10%
} else if (this.codigoDesconto === 'SAVE20') {
// Aplicar desconto de 20%
}
}
}
Refatorado:
// Refatorado para usar classes específicas
class Desconto {
constructor(codigo, porcentagem) {
this.codigo = codigo;
this.porcentagem = porcentagem;
}
aplicar(precoTotal) {
return precoTotal - (precoTotal * this.porcentagem / 100);
}
}
class Pedido {
constructor(id, itens, desconto) {
this.id = id;
this.itens = itens;
this.desconto = desconto;
}
aplicarDesconto(precoTotal) {
if (this.desconto) {
return this.desconto.aplicar(precoTotal);
}
return precoTotal;
}
}
Curtiu o post? Ainda há outros exemplos que poderiam ser citados, mas isso deixaria o post muito longo 😋, mas espero que esses exemplos ajudem de alguma forma a você conseguir identificar e corrigir os code smells
no seu projeto. 🚀
Top comments (0)