✅ O que é Abstração;
✅ O que é Composição;
✅ Quais são as vantagens em abstrair e escrever código componível.
Vem comigo! 👇
A abstração é um conceito subestimado. Não costumamos pensar muito sobre abstrações enquanto programamos.
Considerando isso, vamos voltar ao básico por um momento e começar a pensar nos fundamentos desse conceito.
Afinal, abstração é um conceito mais denso e profundo do que podemos imaginar num primeiro momento.
Digo isso por que eu mesmo subestimei a abstração por um longo tempo, até compreender exatamente o quão importante ela é, e quanto tempo, código e dinheiro ela pode poupar, se você masterizá-la.
Os fundamentos que você corre o risco de subestimar e, após algum tempo de carreira, olhar para trás e refletir sobre o quão profundo e importante eles são, podem tornar você um Desenvolvedor(a) muito, muito mais eficiente.
🔥 Mas, o que é abstração?
A definição do dicionário não ajuda muito, então vou poupar seu tempo e contextualizar o conceito para o Desenvolvimento de Software:
Abstração é o processo de simplificação do código, encontrando similaridades entre diferentes partes do código e extraindo a lógica compartilhada para um componente nomeado (função, módulo, etc), reduzindo a quantidade de código necessária para alcançar um objetivo.
A chave para fazer mais com menos código é a masterização da abstração.
🔥 Exemplos de abstração
Vamos imaginar um array de objetos.
Suponhamos que o nosso objetivo agora seja obter um array com apenas os nomes e armazená-lo em uma const.
Uma boa abstração de código permite que você alcance esse objetivo escrevendo apenas isso:
Ao invés disso:
Uma boa abstração oculta detalhes da implementação:
Sem abstração, você teria que alcançar esse objetivo através de um loop no array.
Abstrações, economizam seu tempo e te poupam de escrever código non-sense:
Muitos dos processos de software são baseados em repetições.
Existe, por exemplo, uma abstração para que você obtenha apenas o(s) objeto(s) que você quiser do array, se baseando em qualquer valor que esse objeto possua.
Se você quisesse alcançar esse objetivo sem essa abstração, precisaria fazer um loop e se preocupar com:
🔸 Setar o index do loop;
🔸 O limite máximo de execuções;
🔸 A incrementação do index;
🔸 A atribuição dos novos valores;
Quando esses amigos fazem uma "vaquinha", ou "crowdfunding", para fazer uma festa para alguém, alguns contribuem mais, outros menos (o mundo não é justo).
De qualquer forma, também existe uma abstração que poupa o seu tempo em calcular o total de dinheiro arrecadado:
Todo o código mostrado até aqui faz apenas uma coisa: percorre o array e retorna algo novo.
Quando você oculta essas repetições e as abstrai, você acelera o processo que te leva a alcançar seu objetivo.
🔥 Reduzindo e reusando código através de abstrações
Dois pontos importantes do que a abstração faz: nomeação e reutilização.
Quando você reduz a quantidade de código através de uma abstração, você nomeia essa abstração.
E você pode reutilizar esse nome em partes diferentes do seu código.
Normalmente, quando você escreve código sem abstração, ele não possui um nome.
Esse código maluco não possui um nome:
Quando você escreve código sem nome, esse código não é reutilizável.
Escrever código nomeável te dá o poder de controlá-lo, chamá-lo várias e várias vezes e utilizá-lo em diferentes contextos, em diferentes situações.
Em Ciências da Computação e na Matemática, a possibilidade de nomear e referenciar algo é chamada de identidade.
🔥 Composição e Abstração
Outro ponto importante é o conceito de composição.
Para conseguir compor, você precisa decompor.
Desenvolver software é composição.
E composição é o processo de quebrar um grande problema em vários pequenos problemas e, então, compor soluções para esses pequenos problemas, dando forma à sua aplicação.
A composição é o que estrutura a sua aplicação.
Uma solução de software deve ter a flexibilidade de ser decomposta em partes e, então, recomposta em novas soluções sem modificar os detalhes internos da implementação.
Isso significa que você deve ter a flexibilidade de pegar um código como o abaixo, decompor ele em pequenas funções e invocar essas funções em diferentes contextos de diferentes lugares.
Ou seja, reutilizar o mesmo código, em diferentes situações, sem modificar o código.
E por que isso é importante?
Por que uma vez que você escreveu um código, você terá que mantê-lo.
Você é o responsável por assegurar que ele não terá bugs, e se tiver, você terá que removê-los.
Se houver mudanças, você é o responsável por adicioná-las, sem quebrar o que você já construiu. E isso é muito mais fácil quando o seu código é lucidamente composto em partes independentes, porém, componíveis.
Se substituírmos "simplicidade" por "abstração", na frase do John Maeda, temos uma frase que descreve de modo impecável o que é abstração:
Abstração é sobre subtrair o óbvio (implementação repetida) e adicionar o que importa (apenas os dados diferentes entre uma repetição e outra).
🔥 Os 2 principais componentes de uma abstração
Abstrações possuem 2 componentes principais:
1️⃣ Generalização - É o processo de encontrar similaridades (o óbvio) em padrões repetidos, e ocultar essas similaridades através da abstração;
2️⃣ Especialização - É o processo de utilizar a abstração e prover apenas o que é diferente (o que importa) para cada caso de uso.
Quanto mais abstrações você escreve, menos código você lê e escreve, e quanto menos código você escreve, menos bugs existem.
🔥 Formas de abstrações
Uma abstração de software pode ter diferentes formas:
Você pode ter uma função "f" que estabelece uma relação de "A" para "B", outra que relaciona "B" com "C", etc.
"h" é uma abstração de "f" e "g". Ou seja, redução e ocultação de complexidade.
🔥 Curried Functions
Imagine uma função "add", que simplesmente retorna a some de 2 números:
Se for necessário que você utilize essa função repetidas vezes, com uma quantia fixa, (1, por exemplo), você terá que invocá-la da forma abaixo, repetindo o "1" diversas vezes, apenas para incrementar valores:
Mas, podemos transformar "add" em uma curried function,
criar uma const "increment", que armazena a invocação de "add" (transformando-a em uma função),
e podemos utilizar "increment", que faz o mesmo que o código anterior, com menos código e complexidade:
Curried functions são uma forma de abstração que permitem que você crie versões especializadas (lembra dos 2 principais componentes de uma abstração?).
🔥 Higher-order Functions
Lembra do exemplo anterior com o "map"?
O map é uma Higher-order Function que abstrai a ideia de aplicar uma função à cada elemento de um array e retornar um novo array com esses resultados.
É possível, por exemplo, criarmos uma curried version do map e utilizarmos ela como uma factory function que pega a versão generalizada do map e a transforma em uma versão especializada que multiplica tudo por 2, por exemplo.
Vamos declarar uma const "map", que irá transformar o método map em uma curried function.
A "map" receberá uma função por parâmetro, que retorna uma outra função que recebe um array e retorna o valor da invocação do map encadeado no array:
A invocação do map receberá, como argumento, a função passada por parâmetro:
Isso, por si só, não faz muita coisa.
Mas podemos adicionar emoção nesse código, declarando uma const "doubleAll", que recebe a invocação de "map", recebendp como argumento uma função que multiplica por 2 o número recebido por parâmetro:
Agora, a invocação de doubleAll retorna um array com números multiplicados por 2:
Ou seja, criamos uma função especializada em que não precisamos especificar os parâmetros que ela irá receber, ou algo do tipo. Precisamos apenas invocá-la.
Quais são as abstrações mais úteis que você tem utilizado?
Gatsby? Redux? Higher-order Components?
Responda nos comentários!
Acha que esse conteúdo pode ajudar + pessoas❓
👉Retweeta👈 essa thread!
Linkei o início dela ali
em baixo, para facilitar =)
✅ Por que o Redux existe;
✅ Quais problemas ele resolve;
✅ Quais são as vantagens em utilizá-lo em uma aplicação;
Vem comigo! 👇
Ultimamente, tenho visto como algumas pessoas utilizam o redux em algumas aplicações e penso que um entendimento mais profundo sobre "por que o redux existe" traria ainda mais benefícios à esses projetos.
🔥 O padrão MVC
Nos últimos anos, estávamos presos ao MVC (Model-View-Controller).
Esse padrão era a forma em que isolávamos as responsabilidades de um app.
✅ O que é Blackboxing;
✅ Como utilizar breakpoints de listeners de eventos;
✅ Como utilizar a palavra-chave "debugger";
✅ E muito mais.
Vem debugar comigo! 👇
Investigar erros e debugar uma aplicação é uma habilidade a ser masterizada.
E essa habilidade está ligada ao seu modo de pensar. Ao seu processo resolver um problema inesperado no código.
Ao encontrar um bug, é comum que Desenvolvedores(as) mais novos, por exemplo, fiquem desconfortáveis e comecem a modificar partes do código, o que deixa a situação ainda mais complicada.