O que é uma Função Pura? Código em Javascript.

Allan Ramos
4 min readSep 13, 2019

--

Esse artigo é uma tradução livre de What Is a Pure Function in JavaScript?, por Yazeed Bzadough.

Funções puras são blocos atômicos na programação funcional. São adoradas por sua simplicidade e testabilidade.

Esse post abordará um rápido checklist para te mostrar se uma função é pura ou não.

O Checklist

Uma função precisa ter 2 (duas) coisas para ser considerada “pura”:

  1. A mesma entrada (input) sempre retorna o mesmo saída (output);
  2. Não possui efeitos colaterais (side-effects).

Vamos entender cada um deles.

1. Mesma entrada => Mesma saída

Compare isso:

const add = (x, y) => x + y;add(2, 4); // 6

Com isso:

let x = 2;const add = (y) => {
x += y;
};
add(4); // x === 6 (resultado ao executar na primeira vez)
add(4); // x === 10(resultado ao executar na segunda vez)

Funções Puras = Resultados consistentes

O primeiro exemplo retornará um valor baseado nos parâmetros enviados, independentemente de onde/quando for chamado.

Se você passar 2 e 4, sempre receberá 6.

Nada afeta o resultado.

Funções Impuras = Resultados inconsistentes

O segundo exemplo não retorna nada. Ele depende do estado compartilhado para fazer seu trabalho incrementando uma variável fora de seu próprio escopo.

Esse padrão é pode ser um baita pesadelo de um desenvolvedor.

O estado compartilhado introduz uma dependência temporal. Você obtém diferentes resultados dependendo de quando invocar a função. Na primeira vez o resultado será 6, na segunda será 10, e assim por diante.

Qual delas possui perguntas mais simples de responder?

Qual delas é a menos provável de produzir bugs que acontecem apenas sob certas condições?

Qual delas é a mais provável de ter sucesso em um ambiente multi-threaded onde as dependências de tempo podem quebrar o sistema?

Definitivamente a primeira.

2. Sem Efeitos Colaterais (Side-Effects)

Esse teste é um checklist. Alguns exemplos de efeitos colaterais (side-effects) são:

  1. Mutação da entrada;
  2. console.log;
  3. Chamadas HTTP (AJAX/fetch);
  4. Modificar o filesystem (fs);
  5. Consultar o DOM.

Basicamente, qualquer trabalho executado por uma função que não esteja relacionado ao cálculo de uma saída (output).

Eu recomendo você assistir esse trecho do Uncle Bob Martin sobre o problema do estado. Começa lá pelos 15 minutos.

Aqui abaixo está uma função impura com um efeito colateral.

Não é tão ruim

const dobroImpuro = (x) => {
console.log('dobrando', x);
return x * 2;
};
const resultado = dobroImpuro(4);console.log({ resultado });

O console.log é o efeito colateral aqui, mas com toda a praticidade, não vai nos prejudicar. Ainda vamos obter as mesmas saídas, dadas as mesmas entradas.

Isso, entretanto, poderá causar um problema.

“Impuramente” modificando um objeto

const assocImpuro = (key, value, object) => {
object[key] = value;
};
const pessoa = {
nome: 'Bob'
};
const resultado = assocImpuro('tamanhoDoTenis', 40, pessoa);console.log({
pessoa,
resultado
});

A variável pessoa foi alterada para sempre pois nossa função introduziu uma instrução de atribuição.

Estado compartilhado significa que o impacto do assocImpuro não é mais totalmente óbvio. Entender seu efeito em um sistema agora envolve rastrear todas as variáveis ​​que já foram tocadas e conhecer suas histórias.

Estado compartilhado = dependências temporais

Nós podemos purificar a função assocImpuro simplesmente retornando um novo objeto com as propriedades desejadas.

Purificando

const assocPuro = (key, value, object) => ({
...object,
[key]: value
});
const pessoa = {
name: 'Bob'
};
const resultado = assocPuro('tamanhoDoTenis', 40, pessoa);console.log({
pessoa,
resultado
});

Agora a função assocPuro retorna um resultado testável e nós nunca nos preocuparemos se isso mudou algo em outro lugar.

Você pode inclusive fazer o código abaixo e permanecer com a função pura:

Outro modo puro

const assocPuro = (key, value, object) => {
const novoObjeto = { ...object };
novoObjeto[key] = value; return novoObjeto;
};
const pessoa = {
name: 'Bob'
};
const resultado = assocPuro('tamanhoDoTenis', 40, pessoa);console.log({
pessoa,
resultado
});

Mutar seu objeto pode ser perigoso, mas mutar uma cópia não tem problema.
Nosso resultado final ainda é uma função testável e previsível que funciona independentemente de onde/quando você a chama.

A mutação está limitada a esse pequeno escopo e você ainda está retornando um valor.

Resumo

  • Uma função pura é livre de efeitos colaterais (side-effects) e retorna sempre a mesma saída, dada a mesma entrada;
  • Efeitos colaterais (side-effects) incluem: mutação da entrada (input), chamadas HTTP, escrita no disco, escrever algo na tela;
  • Você pode tranquilamente clonar, então mutar sua entrada. Apenas deixe o original intocável;
  • A syntax de Spread ( ... ) é o modo mais fácil de clonar objetos e arrays.

Meu curso gratuito

Esse tutorial foi retirado do meu curso gratuito do site Educative.io, Functional Programming Patterns With RamdaJS!

Por favor, considere compartilhar ou mostrar isso a alguém se gostou do conteúdo.

É repleto de lições, gráficos, exercícios e amostras de código executáveis ​​para ensinar um estilo básico de programação funcional usando o RamdaJS.

Eu também estou no Twitter se desejar conversar. Até a próxima!

Se cuida,
Yazeed Bzadough
http://yazeedb.com/

--

--