Quais são as diferenças entre os paradigmas de programação?
Primeiramente, vamos imaginar que você precisa ir até a casa de ume amigue que mora na mesma cidade que a sua. Para fazer isso, existem diversas opções de transporte, como carro, ônibus, metrô, trem, bicicleta e a pé. E em algumas dessas opções, há mais de uma forma, de carro por exemplo você pode ir com um carro seu, de carona, ou via aplicativo. E em cada uma dessas formas, há vantagens e desvantagens, em questões de preço, tempo, distância, segurança, conforto,etc.
A mesma coisa acontece nos tipos de paradigmas de programação. Diferentes tipos de programação buscam solucionar problemas diferentes, e para a programação se adaptar melhor a esses diferentes objetivos, a forma de estruturar e organizar o código vai ser diferente também.
Dessas diferentes estruturas e organizações do código, que vem os diferentes tipos de programação, sendo grandes grupos de linguagens com características semelhantes. Sendo os dois principais as linguagens orientadas a objeto, e as linguagens funcionais.
Programação orientada a objeto (POO)
Primeiro, vamos falar sobre o tipo mais popular de programação, a programação orientada a objeto, ou POO.
A POO é baseada no conceito de objetos, que são representações de um dado. Um exemplo simples é um bolo. Um bolo tem o sabor da massa, da cobertura, cores, tamanho, quem fez, qual é o tamanho de cada pedaço,etc. Todos esses dados sobre o bolo podem ser representados em um único objeto, sendo esse o principal elemento nas linguagens orientadas à objeto.
Uma outra característica muito marcante nas linguagens orientadas a objeto é o foco mais no como, que no que. Em outras palavras, é mais importante o caminho para chegar em uma ação, que a ação em si.
Um exemplo disso é a adição de uma nova pessoa usuária. Em POO, a maior parte do processo seria a montagem de um objeto que represente essa nova pessoa, e todas as checagens nesse processo. Só no fim do fluxo que a adição seria feita de verdade. Então o foco foi mais direcionado à como fazer, do que à ação por si.
Exemplos de linguagens famosas que incluem programação orientada à objeto são Ruby, Scala, Java, Python,etc.
Programação funcional
A programação funcional por um outro lado é mais focada nas funções do que nos objetos, buscando criar um código mais limpo, e direto, com uma menor complexidade que a programação orientada à objetos. Tanto que um dos conceitos da programação funcional são as funções puras.
As funções puras são funções que estão isoladas do resto do código, então independente de qualquer outro código que estiver fora do escopo delas, elas sempre vão dar os mesmo resultados. Algo que não pode ser garantido em linguagens orientadas à objeto por conta das propriedades que os objetos podem ter.
A vantagem por trás das funções puras é a simplicidade, e a segurança delas. Porque não tem nenhum objeto, ou classe que pode afetar a função, tendo a garantia que recebendo os mesmos inputs, o resultado sempre será o mesmo.
Exemplos de linguagens famosas que incluem programação funcional são Haskell, Elixir, Erlang, OCaml,etc.
Mutabilidade de variáveis
Em linguagens orientadas à objetos, por padrão, as variáveis são mutáveis, enquanto linguagens funcionais têm as variáveis imutáveis por padrão. Essa diferença vem por conta das funções puras, pois uma das filosofias da programação funcional é representar o retorno das funções como o “trabalho pronto”, apenas atribuindo uma variável com esse valor.
Programação imperativa e declarativa
Programação orientada a objeto e programação funcional também se diferem na forma que organizamos o nosso código, com a POO sendo uma programação imperativa, enquanto a programação funcional sendo uma programação declarativa. Para mostrar essa diferença, vamos à um exemplo prático.
Vamos supor que temos uma lista de senhas, e que precisamos filtrar essas senhas para apenas as que tem mais de 9 caracteres. Em Javascript, de forma imperativa, poderíamos fazer isso da seguinte forma:
const senhas =[
"123456",
"senha",
"admin",
"feministech",
"minhasenha",
];
let senhasAprovadas = [];
for (let i = 0; i < senhas.length; i++) {
const senha = senhas[i];
if (senha.length >= 9){
senhasAprovadas.push(senha);
}
}
Tentando olhar esse código de forma mais profunda, ele faz esse processo de verificação e adição contando uma história, então primeiro é usado o for
, passando item por item dessa lista. Para cada item, será verificado se o tamanho da senha é maior que 9 caracteres, e caso sim, essa senha será adicionada à uma lista de senhas aprovadas.
Essa forma de programar, colocando instruções que criam uma história, dependendo da outra é a forma imperativa. Essa palavra “imperativa” significa uma ordem, como “faça aquilo, depois aquilo, e depois isso”.
Podemos também fazer um código com o mesmo resultado, mas de uma forma declarativa, dessa forma:
const senhasAprovadas = senhas.filter(senha => senha.length >= 9);
No código acima, usamos a função filter
para filtrar todos os itens dessa lista de senhas, e mantendo apenas os itens que tiverem um número de caracteres maior que 9, removendo todo o resto da lista.
Essa forma mostrada acima é declarativa pois estamos nos preocupando apenas com o que estamos fazendo, não com como estamos fazendo todo esse processo, sendo essa a principal diferença entre programação imperativa e declarativa.
Exemplo prático: fatorial de um número
Agora vamos à um exemplo prático, vamos criar uma função que retorna o fatorial de um número, que é a multiplicação de todos os número antecessores a esse, até o número um.
Para criar essa função, em Javascript, com POO, podemos escrever essa função dessa forma:
function fatorial(numero) {
if (numero === 0 || numero === 1)
return 1;
for (var i = num - 1; i >= 1; i--) {
numero *= i;
}
return numero;
}
Analisando esse código, podemos ver que se esse número for 0, ou 1, o retorno será fixo em 1. Se não, será executado um for, indo do número, até 1, diminuindo esse valor, e a cada execução deste for, o número será multiplicado pelo seu valor, menos um. E depois será retornado o número fatorial.
Essa solução funciona, mas podemos resolver esse problema de outra forma, usando um conceito da programação funcional chamado de recursão.
function fatorial(numero) {
if (numero < 0)
return -1;
else if (numero == 0)
return 1;
else {
return (numero * fatorial(num - 1));
}
}
Analisando esse código, podemos ver que existem 3 possibilidades: Se o número for menor que zero, se o número for igual a zero, ou se o número é nenhuma das duas opções (maior que zero).
Caso o número seja menor que zero, seu fatorial será -1
, caso seja igual a zero, seu fatorial será 1
, e se caso o número for maior que zero, é usada uma função de recursão, onde será retornado o número, vezes o resultado dessa mesma função, com o número subtraído de um.
É difícil entender esses conceitos de recursão no começo, mas é basicamente usar uma função dentro da mesma função, evitando ter que usar loops como for
e while
sem necessidade.
Na maioria das vezes usar recursividade em JS ou linguagens semelhantes pode não ser uma boa ideia, pois elas não lidam bem com isso a nível de máquina virtual ou runtime, isso pode deixar o código lento e até mesmo estourar a pilha de execução, fechando o programa, ou travando a máquina.
Mas em linguagens de programação funcionais, esse código é perfeitamente adequado, e correto seguindo os padrões da linguagem. Um exemplo disso é que podemos criar uma função de fatorial usando recursão em Elixir, uma linguagem muito caracterizada pela programação funcional.
defmodule Factorial do
def of(0), do: 1
def of(n) when n > 0, do: n * of(n - 1)
end
Nesse caso, usar programação funcional (ou apenas conceitos de programação funcional, como a recursão) pode simplificar o código, tornando ele menor e mais legível. Mas caso precisássemos mexer com valores fora da função, ou com coisas que podem mudar de estado antes ou depois dessa função, e que poderiam mudar a sua execução, POO seria melhor nesses casos, garantindo mais segurança e flexibilidade.
Onde usar cada uma?
Como vimos, a POO e a programação funcional tem características bem diferentes, e por isso, cada uma pode ser utilizada em situações diferentes.
Para aplicações que exigem muitas classes, e muitas instâncias de objetos, como CRUD’s, com classe para usuáries, posts, transações,etc. E pouca manipulação desses objetos, como apenas fazer verificações, escrever em um banco de dados, e retornar outro objeto, POO pode se encaixar perfeitamente, fornecendo todos os recursos que você precisa.
Enquanto para aplicações que exigem poucas variáveis, e variáveis com valores mais simples, como números, strings, ou listas, e muita manipulação nesses valores, como aplicações matemáticas, programação funcional pode se encaixar melhor que POO, garantindo que sempre quando o seu programa receber os mesmo valores de input, serão retornados os mesmo valores de output.
E além, caso você esteja utilizando uma linguagem mista, é possível usar ambos tipos de programações dentro de uma única aplicação.
Linguagens mistas
Existem linguagens que implementam diversos paradigmas de programação, como POO e programação funcional, ao mesmo tempo. Oferecendo ambas formas de programar em uma mesma linguagem, podendo até mesmo intercalar os dois tipos, ou até outros, em um mesmo código.
Exemplos de linguagens que são multiparadigma é Kotlin, Python, Javascript e C#.
Finalização
Nesse artigo te apresentei conceitos sobre programação orientada a objetos, e programação funcional, e separei as duas, mostrando as suas diferenças e funcionalidades.
Muito obrigada por ler ❤️🏳️⚧️ e me segue nas redes, é tudo @lissatransborda 👀
Top comments (16)
Muito bom ! Obrigado por compartilhar de forma tão clara esses conceitos .
Essa explicação de linguagem declarativa e linguagem imperativa me fez olhar com outros olhos pro Javascript. É impressionante a quantidade de vezes que eu já passei por cima desses conceitos no meu dia a dia e nunca parei pra pensar neles.
Ótimo artigo, Lissa.
que bom que você gostou lele, eu que agradeço <3
Excelente forma de abordar o tema que é bastante extenso e vem a ser útil para quem busca criar suas próprias linguagens de programação ou adentrar em áreas similares, os exemplos são bem práticos mostrando como os efeitos colaterais podem afetar a execução do programa, sem se prender a uma tecnologia de execução destes recursos.
Parabéns 🎉
Demorei um tempo para entender a diferença, entretanto quando entendi passei a amar linguagens mais funcionais pela sua "simplicidade" aparente, por isso achei extramente interessante sua postagem Lissa, ficou bem fácil de entender as diferenças e bem didático parabénssss ficou incrível demais.
Obrigadaaaaa ♥️
Curti de mais!!! Bem explicado!
Ótimo texto!
Se quiser como complemento:
Muito bom o artigo. Com os exemplos ficou bem fácil de entender.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.