Código Limpo: Funções (em Javascript)
Você está cansado de lutar com funções complexas e difíceis de entender em sua base de código? Você deseja escrever funções que sejam mais fáceis de manter, reutilizáveis e menos propensas a erros? Nesse caso, você precisa aprender sobre “Código Limpo: Funções”. Seguindo as melhores práticas descritas no livro “Clean Code” de Robert C. Martin, você pode aprender a escrever funções que são mais fáceis de ler, testar e manter. Nesta postagem do blog, exploraremos os principais conceitos das funções de código limpo e forneceremos dicas e exemplos práticos para ajudá-lo a implementar esses conceitos em seu próprio código. Com a nossa ajuda, você pode levar suas habilidades de codificação para o próximo nível e escrever funções que são uma alegria de se trabalhar. Então, você está pronto para aprender sobre funções de código limpo? Vamos mergulhar!
Índice
· Funções pequenas são melhores que as grandes
· Funções devem fazer uma coisa
· Funções devem ter nomes descritivos
· Funções devem ter um número limitado de argumentos
· Funções não devem ter efeitos colaterais
· Funções não devem depender de variáveis globais
· Funções não devem depender demais Profundamente aninhado
· Use exceções, não códigos de erro
· Conclusão
Funções pequenas são melhores que as grandes
Pequenas funções são mais fáceis de ler e entender porque geralmente fazem uma coisa e têm um propósito claro. Isso também os torna mais fáceis de testar e manter porque há menos código para revisar ou modificar. Funções grandes, por outro lado, podem ser mais complexas e difíceis de entender, o que pode levar a bugs ou erros.
// Large function
function processOrders(orders) {
const total = orders.reduce((acc, order) => acc + order.price, 0);
const orderIds = orders.map(order => order.id);
const orderCount = orders.length;
const orderSummary = `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
console.log(orderSummary);
return orderSummary;
}
// --------------------------------------------------------------
// Refactored into smaller functions
function getTotalPrice(orders) {
return orders.reduce((acc, order) => acc + order.price, 0);
}
function getOrderIds(orders) {
return orders.map(order => order.id);
}
function getOrderCount(orders) {
return orders.length;
}
function generateOrderSummary(orders) {
const total = getTotalPrice(orders);
const orderIds = getOrderIds(orders);
const orderCount = getOrderCount(orders);
return `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
}
function logOrderSummary(orders) {
const orderSummary = generateOrderSummary(orders);
console.log(orderSummary);
return orderSummary;
}
A getTotalPrice()função pega uma matriz de pedidos e retorna seu preço total usando a reduce()função para somar o preço de cada pedido. A getOrderIds()função recebe uma matriz de pedidos e retorna uma matriz de seus IDs usando a map()função. A getOrderCount()função recebe uma matriz de pedidos e retorna sua contagem usando a lengthpropriedade. Por fim, a generateOrderSummary()função recebe uma matriz de pedidos e usa as três funções menores para gerar uma string de resumo. A logOrderSummary()função pega uma matriz de pedidos e registra a string de resumo no console.
As funções devem fazer uma coisa
Cada função deve ter um propósito claro e distinto. Quando uma função faz várias coisas, pode se tornar mais difícil de entender, testar e manter. Ao dividir uma tarefa maior em funções menores, podemos criar um código mais legível e sustentável.
// Function that performs multiple tasks
function processUserInput(input) {
const inputLines = input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
const trimmedLines = inputLines.map(line => line.trim());
const nonEmptyLines = trimmedLines.filter(line => line !== '');
const formattedLines = nonEmptyLines.map(line => `> ${line}`);
return formattedLines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
// --------------------------------------------------------------
// Refactored into smaller functions
function splitInput(input) {
return input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function trimLines(lines) {
return lines.map(line => line.trim());
}
function removeEmptyLines(lines) {
return lines.filter(line => line !== '');
}
function formatLines(lines) {
return lines.map(line => `> ${line}`);
}
function joinLines(lines) {
return lines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function processUserInput(input) {
const lines = splitInput(input);
const trimmedLines = trimLines(lines);
const nonEmptyLines = removeEmptyLines(trimmedLines);
const formattedLines = formatLines(nonEmptyLines);
return joinLines(formattedLines);
}
A splitInput()função pega uma string e usa o split()método para dividi-la em uma matriz de linhas. A trimLines()função pega uma matriz de linhas e usa o map()método para remover qualquer espaço em branco do início e do final de cada linha. A removeEmptyLines()função pega uma matriz de linhas e usa o filter()método para remover quaisquer linhas vazias. A formatLines()função pega uma matriz de linhas e usa o map()método para adicionar um >caractere ao início de cada linha. A joinLines()função pega uma matriz de linhas e usa o join()método para juntá-las em uma única string, separada por novas linhas. Finalmente, a processUserInput()função usa as funções menores para processar a string de entrada.
As funções devem ter nomes descritivos
Os nomes das funções devem descrever com precisão o que a função faz e devem ser fáceis de entender sem a necessidade de ler a implementação da função. Um nome de função descritivo pode ajudar a tornar o código mais autoexplicativo e reduzir a necessidade de comentários.
// Function with a vague name
function processData(data) {
// ...
}
// --------------------------------------------------------------
// Refactored with a descriptive name
function processUserData(userData) {
// ...
}
As funções devem ter um número limitado de argumentos
As funções que usam um grande número de argumentos podem ser mais difíceis de usar, entender e testar. Procure manter o número de argumentos abaixo de três ou quatro, se possível. Uma maneira de reduzir o número de argumentos é passá-los como um único objeto ou estrutura de dados.
// Function with too many arguments
function createPerson(name, age, address, phone, email) {
// ...
}
// --------------------------------------------------------------
// Refactored to use an object instead
function createPerson(personData) {
// ...
}
// Now, we can pass an object with properties for name, age, address, phone, and email:
const personData = {
name: 'John Doe',
age: 30,
address: '123 Main St',
phone: '555-555-1234',
email: '[email protected]'
};
const person = createPerson(personData);
As funções não devem ter efeitos colaterais
Um efeito colateral ocorre quando uma função modifica qualquer estado fora de seu próprio escopo. Os efeitos colaterais podem dificultar o teste e o raciocínio sobre o comportamento da função e também podem levar a um comportamento inesperado. As funções devem operar apenas em seus próprios parâmetros e variáveis locais e não devem modificar nenhum estado fora de seu escopo.
// Example with side effects
let arr = [1, 2, 3];
function popLastElement() {
arr.pop(); // modifies the external state of `arr`
}
popLastElement();
console.log(arr); // Output: [1, 2]
// --------------------------------------------------------------
// Example without side effects
function getLastElement(arr) {
return arr[arr.length - 1]; // returns a new value without modifying the input
}
let arr = [1, 2, 3];
let lastElement = getLastElement(arr);
console.log(lastElement); // Output: 3
Funções não devem depender de variáveis globais
As variáveis globais dificultam a compreensão e o teste das funções e podem levar a um comportamento inesperado. As funções devem operar apenas em seus próprios parâmetros e variáveis locais e não devem depender do estado global. Isso também facilita a reutilização da função em diferentes contextos.
// Example relying on global state
let x = 0;
function increment() {
x++;
}
increment();
console.log(x); // Output: 1
// --------------------------------------------------------------
// Example without relying on global state
function increment(x) {
return x + 1;
}
let y = 0;
y = increment(y);
console.log(y); // Output: 1
As funções não devem ser muito aninhadas
As funções aninhadas profundamente podem ser mais difíceis de ler e entender, além de levar a estruturas de controle complexas. As funções devem ser estruturadas de forma a facilitar a compreensão do fluxo de controle, sem ter que acompanhar mentalmente vários níveis de funções aninhadas.
// Example with deeply nested functions
function add(a, b) {
function increment(x) {
return x + 1;
}
let c = increment(a);
let d = increment(b);
return c + d;
}
console.log(add(1, 2)); // Output: 5
// --------------------------------------------------------------
// Example with flatter function structure
function increment(x) {
return x + 1;
}
function add(a, b) {
let c = increment(a);
let d = increment(b);
return c + d;
}
console.log(add(1, 2)); // Output: 5
Use exceções, não códigos de erro
Códigos de erro podem tornar mais difícil raciocinar sobre o código e podem levar a estruturas de controle complexas. As exceções permitem um fluxo de controle mais natural e um tratamento de erros mais fácil. As funções devem lançar exceções para indicar erros ou comportamento inesperado, em vez de retornar códigos ou valores de erro.
// Example with error code
function divide(a, b) {
if (b === 0) {
return -1; // error code for divide by zero
}
return a / b;
}
let result = divide(4, 0);
if (result === -1) {
console.log("Error: Divide by zero"); // error handling with error code
}
// --------------------------------------------------------------
// Example with exception
function divide(a, b) {
if (b === 0) {
throw new Error("Divide by zero"); // throws an exception
}
return a / b;
}
try {
let result = divide(4, 0);
} catch (e) {
console.log("Error: " + e.message); // error handling with exception
}
Conclusão
Em conclusão, é importante seguir as melhores práticas ao escrever funções para melhorar a qualidade geral de nossa base de código. Ao fazer isso, podemos garantir que nossas funções não sejam apenas legíveis e reutilizáveis, mas também sustentáveis a longo prazo. Isso pode ajudar a reduzir o número de bugs e erros que podem surgir de um código mal escrito, o que pode economizar tempo e recursos a longo prazo.
Vale a pena notar que o código limpo não se trata apenas de escrever um código que funcione; trata-se também de escrever código que possa ser facilmente compreendido, testado e modificado ao longo do tempo. Portanto, é recomendável reservar um tempo para considerar cuidadosamente as práticas recomendadas descritas acima ao escrever funções, a fim de otimizar a qualidade e a capacidade de manutenção do seu código.





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)