Reactive Programming para Desenvolvedores Android — Part I
Uma das coisas que me faz gostar tanto da área de desenvolvimento de software especialmente falando do desenvolvimento de apps para android é a velocidade com que as coisas mudam trazendo novas ferramentas e técnicas interessantes.
Nos últimos anos, Functional Reactive Programming(especificamente falando da biblioteca RX Java para Java e Android) foi um dos tópicos que mais se falou e cresceu no seio das comunidades de desenvolvimento para android.
Tive a oportunidade de poder entrar de forma profunda e implementar durante o último ano e gostaria de partilhar em uma série de posts começando por falar das motivações e uma explicação básica sobre este tópico.
O que é Functional Reactive Programming?
Um dos motivos pelo qual este é um tópico extremamente falado mas muitos acham difícil de entender, é porque antes mesmo de traduzir estes conceitos para código a nomenclatura gera muita confusão pois a parte “Functional” do nome nos leva a um outro conceito muito mais antigo que não tem relação com o que vou falar durante a série de posts.
Functional Programming — O verdadeiro Significado(O mais antigo)
Functional Programming na sua essência é um paradigma que pressupõe que funções(ou métodos) devem ser escritos com o objectivo de realizar uma função específica sem efeitos colaterais(Funções puras).
Isto implica ter uma função que não depende e nem manipula variáveis fora do seu escopo. (Porque functional programming é um tema interessante e por si só muito longo, se estiver interessado em ler um pouco mais sobre este tópico sugiro que leia um post muito mais detalhado AQUI )
Tendo em conta a definição original de functional programming, olhemos para a definição de functional reactive programming para poder entender a diferença da parte functional entre os dois nomes.
Functional reactive programming é programar utilizando fluxos de dados assíncronos que podem ser transformados em um novo fluxo utilizando um conjunto de funções.
Este fluxo de dados é emitido por um elemento e pode ou não existir um outro elemento que ira reagir a medida que vai recebendo o fluxo de dados.
Olhando para a definição acima, enquanto que o termo mais antigo remete a criação de funções puras, o termo mais recente refere-se a parte functional como um conjunto de funções que permitem modificar o fluxo de dados como veremos mais abaixo.
Sendo assim, acredito que de agora em diante podemos concordar que utilizarei o termo Reactive Programming sempre que quisermos falar de Functional Reactive Programming para evitar dúvidas e confusões.
The Observer Pattern
Reactive Programming tem como base o Observer pattern que pressupõe a existência de 2 componentes em que o primeiro é denominado Observable e é responsável por emitir um fluxo de dados e um segundo componente denominado Observer que fica a escuta e recebe o fluxo de dados como mostra a figura abaixo:
Reactive Programming [The Observer Pattern++]
Por sua vez, Reactive Programming pode ser considerado como um upgrade ao Observer Pattern em que continuamos a ter 2 elementos em que um emite um fluxo de dados e o outro recebe e reage a esse fluxo de dados e é adicionada uma forte componente intermédia composta por diferentes funções que permitem a manipulação dos dados ou do fluxo como um todo como mostra a figura abaixo.
Porque Pensar de Forma Reactiva?
A ideia de pensar de forma reactiva surge dos problemas e trabalho que temos de fazer quando pensamos da forma oposta(não reactiva ;) ).
Pensar de forma não reactiva é pensar de forma imperativa, e pensar de forma imperativa é o que normalmente se faz desde a altura que se começa a aprender a programar em que olhamos para o nosso código a ser executado em uma única thread e utilizar callbacks com a lógica que queremos que seja realizada na nossa thread original assim que uma outra thread acaba de fazer um determinado trabalho.
Tomando como exemplo uma aplicação(Web, Android) básica que se conecta a uma API para ler dados, na implementação pensando de forma imperativa existiria um componente responsável por iniciar a chamada a API e definir um método de callback que será invocado assim que a API enviar a resposta.
Até então, esta solução sempre foi a melhor e por isso vários sistemas foram desenvolvidos desta maneira.
O problema entretanto é que a medida que o sistema vai crescendo, gerir estas interfaces com métodos de callbacks entre outras complicações existentes ao trabalhar com múltiplas threads torna-se muito dispendioso e transforma o código em algo muito difícil de manter.
Para enfatizar ainda mais os constrangimentos de pensar de forma imperativa tomando o exemplo anterior implementando especificamente para Android, significa que a chamada a API seria feita com o objectivo de apresentar a informação em um Fragment ou uma Activity e porque não sabemos quando este trabalho irá terminar e a forma como a chamada está a ser feita não tem noção sobre o componente que a iniciou, corremos o risco de ter graves problemas se o utilizador sair da aplicação pois a tarefa continuara a ser executada e no momento de fazer o set dos fields na Activity ou no Fragment estes componentes ja não existirão mais.
Falando especificamente do Android, todo o sistema pode ser considerado assíncrono pois como no exemplo anterior, operações como leitura a base de dados interna, os dados de entrada enviados pelo utilizador através de eventos de clique entre outros são assíncronos e pensar de forma imperativa apesar de funcionar sempre dará mais trabalho a medida que a aplicação for crescendo.
Tendo em conta os cenários acima a maior dúvida agora deve ser sobre como pensar de forma reactiva.
Pensar de forma reactiva é simples(Uma mentira para te fazer ler os próximos posts que se transformara em verdade no fim da série) e devemos simplesmente olhar para o sistema em desenvolvimento em termos do fluxo de dados dentro dele, isto é, pensar como um determinado componente irá reagir de forma automática a mudanças de um outro componente do sistema que este pré dispôs-se a escutar sobre as suas mudanças.
Se por exemplo na forma imperativa existir uma variável a e esta variável for definida o valor a soma das variáveis b + c por mais que o valor de b e c sejam modificados mais para frente, o valor de a nunca sera modificado a não ser que voltemos a fazer a operação de definição de a como a soma de b+c
Na forma reactiva o a subscreveria-se(Um termo que utilizarei muito ao longo da série) a b e c e teria o seu valor actualizado sempre que b e c mudassem sem a necessidade de executar a operação de atribuição da soma das duas variáveis.
Entender tudo isto na teoria é no início muito complicado mas posso garantir que no próximo post entrarei em mais detalhes sobre como traduzir esta forma de pensar para código utilizando a biblioteca RX Java utilizada para java e android.
Se gostaste do conteúdo deste post por favor deixe um like clicando no coraçãozinho abaixo e partilhe com um amigo que achas que também gostaria de aprender um pouco mais sobre este tópico.
Ate o próximo post,
DM =)