O que são?

Funções, no conceito mais básico, são blocos de código. Elas podem receber valores externos, chamados de parâmetros, ou não; quando recebem parâmetros, estes valores são utilizados de alguma forma dentro delas.

Exemplos de funções com e sem parâmetros são:

function exemplo(){
    console.log("Essa é uma função sem parâmetros.")
}

exemplo() //imprime Essa é uma função sem parâmetros.

function soma(a, b){
    return a + b
}

console.log(soma(2, 3)) //imprime 5

let y = 3
function sub(x){
    return x - y
}
console.log(sub(5))//imprime 2

Já nesses exemplos podemos identificar algumas funções puras e impuras. Você se arrisca a adivinhar quais são as puras ou impuras? Vou dar um tempinho.

… Pronto?

Vamos lá!

As funções puras são a exemplo() e a soma(a, b), enquanto que a função impura é a função sub(x). Mas por quê?

Uma das características das funções puras é que elas recebem um determinado parâmetro, então elas retornarão o mesmo resultado sem efeitos colaterais. Ou seja, a mesma entrada gera a mesma saída.

Perceba que as funções exemplo() e soma(a, b) não dependem de dados externos à função. Você pode apontar a função soma, que recebe a e b como parâmetros, isso é um dado externo, não?

Para isso, vamos voltar à primeira característica. Perceba que os parâmetros a e b sempre são somados (ou concatenados, se você passar valores de String). Mas a saída é sempre a mesma, o que significa que não há nada externo à função que possa atrapalhar sua execução.

O mesmo não aplica, por exemplo, a função sub(x), que faz a subtração de x e y. O resultado dessa função é dependente de valores externos a ela, por isso ela se caracteriza como uma função impura.

Por que usar funções puras?

Pela capacidade de sempre mostrar o mesmo resultado e não dependerem de valores externos, as funções puras são conhecidas por sua capacidade de testes. Você pode usá-las para conseguir resultados contínuos em testes e ter a certeza de que o resultado estará correto, coisa que não acontece com as funções impuras.

Além disso, por não utilizarem de estratégias externas, essas funções podem ser refatoradas sempre que necessário, já que o que acontece dentro de seu escopo de execução não depende do escopo externo ou global.

Por isso, recomenda-se o reuso das funções puras. Uma vez que você as declarou no seu código, sabe qual resultado elas vão produzir – que vai ser sempre um resultado contínuo e observável – sabe que elas não causarão efeitos colaterais no resto do código, ora, tem mais é que utilizar novamente! Isso ajuda a deixar o código mais compacto e compreensível.

Então devo usar somente as puras, única e exclusivamente?

Não! É preciso entender que as funções impuras não necessariamente são inúteis, ou devem ser evitadas. Elas de fato são mais difíceis de testar, mas de maneira alguma isso as torna inúteis!

Na verdade, é quase impossível evitá-las. Por exemplo, funções usadas em bancos de dados são necessariamente funções impuras, porque precisam, constantemente, acessar dados externos para usá-los nas suas execuções.

Um projeto real consiste em funções puras e impuras, mas priorizando ao máximo o uso das funções puras. Procurar isolar as funções impura num local à parte, o que garante uma facilidade maior de teste do código; pode ser feito por meio de encapsulamento, por exemplo.

Os conceitos de funções puras e impuras são relativamente novos para mim também, pois nunca pensei que teria uma definição para funções que usam informações de fora e as que não usam… Achei que era só questão de escopo. Pensando nisso, quis elaborar esse artigo, para ajudar espalhar esse conhecimento sobre o assunto.

Sugiro também que deem uma olhada no vídeo da Cod3r também sobre o assunto, que se encontra nesse link aqui!

Bons estudos e até a próxima!