Arquiteturas Avançadas Android: VIPER

Compartilhe

Compartilhar no facebook
Compartilhar no google
Compartilhar no twitter
Compartilhar no linkedin

Em um projeto realizado em 2017 na redspark para uma multinacional que tinha fornecedores de diversos países, enquanto uma equipe na Romênia desenvolvia o back-end e o front-end web, outra equipe cuidava do App Global e uma terceira equipe do Brasil, na qual eu estava presente, desenvolvia 2 módulos para o mesmo aplicativo. Fusos horários a parte, a parte técnica do projeto fluiu muito bem e boa parte deste resultado se deve as arquiteturas que esses Apps usavam: VIPER para iOS e Clean para Android. Após a finalização deste projeto, foi resolvido que a arquitetura padrão para desenvolvimento mobile iria mudar para novos projetos, adotou-se VIPER para iOS e Android. Diante deste contexto, este artigo visa uma breve introdução e a motivação da escolha desta arquitetura para Android.

Introdução ao VIPER

Quantas vezes você se deparou com activities enormes nos seus projetos? A activity é o controller no modelo MVC (Model-View-Controller. Na camada de View temos apenas os arquivos XML e na camada de Model as nossas entidades, sejam elas persistidas localmente ou gerenciadas de forma remota. Neste modelo a lógica de tela, regras de negócio, chamadas à APIs externas, gravação no banco de dados ficam na activity.

Arquiteturas como MVP (Model View Presenter) e MVVM (Model View ViewModel) se popularizaram nos últimos anos por dividir a responsabilidade do controller em mais camadas. A arquitetura VIPER segue a mesma linha, porém vai além, dividindo as camadas da aplicação em View, Interactor, Presenter, Entity e Router.

O primeiro ponto a ser notado nesta imagem é que nem todas as camadas interagem entre si. Neste artigo não vamos nos aprofundar na implementação desta arquitetura, mas nas responsabilidades de cada camada. Imagine que cada funcionalidade do app é um módulo VIPER que pode, de acordo com a necessidade, conter algumas ou todas estas camadas. Vamos tomar como exemplo o módulo de Login, comum em grande parte dos aplicativos.

A camada View continua sendo representada pelos arquivos XML com os elementos visuais, porém agora a classe Activity faz parte desta camada. Como a camada de View não deve ter lógica, é importante que a Activity possua apenas métodos “passivos” como por exemplo exibirLoader e exibirMensagem. Esta camada não solicita dados, apenas avisa o Presenter que algum evento ocorreu, como por exemplo nos métodos de ciclo de vida (onResume, onCreate, etc) em que o usuário pressionou o botão.

Toda a lógica de apresentação está no Presenter. É nesta camada que pedimos para a View exibir o Loader ou alguma mensagem. Podemos utilizar esta camada também para validações mais simples, como os campos login e senha serem obrigatórios. No nosso exemplo, se o usuário pressionou o botão de login o Presenter deve pedir para a View exibir o Loader, verificar se os campos estão preenchidos, exibir uma mensagem caso o algum campo esteja vazio.

As regras de negócio são de responsabilidade da camada de Interactor. Esta camada deve disponibilizar métodos que são os casos de uso no aplicativo. Voltando para o nosso exemplo, deve haver um método logarUsuário que irá realizar a chamada à API e poderia gravar o token de acesso no banco de dados local. Idealmente devemos ter uma camada extra aqui para abstrair o acesso à API e ao banco de dados. Criando um aplicativo menos acoplado e garantindo mais testabilidade.

Esta camada pode ser chamada de Repository e tem como responsabilidade o acesso aos dados (sejam locais ou remotos). O Repository não deve expor o dado como ele volta da API ou do banco de dados, mas sim na forma de Entity, que nada mais é que o nosso antigo modelo no MVC.

Imagine agora que tudo isso ocorreu: o usuário digitou o e-mail e senha, pressionou o botão, o Presenter foi avisado pela View e já acionou o método do Interactor que vê a chamada no Repository que, por sua vez, chamou a API através do Retrofit e salvou o token do usuário no SQLite. Ufa! Mas isso é tudo? Não! Ainda precisamos ir para a próxima tela. Esse é o papel do Router que é chamado pelo Presenter (existem versões do VIPER em que o Router é chamado pelo Interactor).

Esta camada é responsável pelas mudanças de telas (roteamento), passagem de dados e em muitos casos, como na redspark, o Router também é responsável por instanciar as classes as classes do módulo, garantindo que arquitetura VIPER seja seguida.

Conclusão

Este foi uma breve introdução sobre as responsabilidades de cada camada no VIPER. Aliás, é importante notar que palavra “responsabilidade” foi utilizada muitas vezes neste artigo. Não à toa, o VIPER está diretamente ligado aos princípios do SOLID, sendo o princípio da responsabilidade única (o “S” do SOLID) claramente notado. Pessoalmente eu vejo duas grandes vantagens na utilização do VIPER: testabilidade e manutenção.

Tantas divisões de responsabilidade geram classes mais simples e podemos criar testes unitários mais simples e eficientes. É uma boa prática gerenciar as dependências através de abstrações (interfaces), desta forma podemos facilmente mockar as camadas gerando testes totalmente independentes. A manutenção torna-se melhor pela divisão e melhor estruturação do código, principalmente se trabalhos em equipes grandes e aplicativos grandes onde muitas pessoas mexem no código.

Mas o VIPER é a bala de prata das arquiteturas? Claramente a comunidade não tem nenhum consenso sobre isso, tanto que vemos diversas arquiteturas surgirem como MVI e MvRx. Um dos pontos negativos do VIPER é o Overhead para um módulo, onde mesmo as telas mais simples vão conter 3 ou 4 classes. Além disso, existe pouca documentação sobre esta arquitetura e pouca, ou nenhuma, literatura na forma de livros. Eventualmente, isso leva as empresas a adaptarem o VIPER para suas necessidades criando “submodelos VIPER”. Aproveite para conferir o que é arquitetura da informação e como aplicá-la em seus projetos.

Pessoalmente, o maior ganho que eu vi ao adotarmos esta arquitetura na redspark foi a padronização de projetos Android e IOS. Utilizando linguagens razoavelmente parecidas (Kotlin e Swift), ficou muito mais fácil transitar entre os projetos, criar testes (no caso de TDD) entre outras vantagens.


Ficou interessado? Quer receber mais conteúdos como esse no se e-mail?

Acesse esse link  fale um pouco mais sobre você e seus interesses, compartilharemos artigos, notícias e outras novidades direto no seu e-mail :)

Fabio Tadashi Miyasato

Fabio Tadashi Miyasato

Formado em Desenvolvimento de Sistemas (FIAP) com MBA em desenvolvimento Java e IoT, atua como Desenvolvedor Android na Redspark em soluções para clientes como Nestlé, Sesc, Filoo, Hospital Albert Einstein entre outros. Acredita no potencial da tecnologia para mudar o mundo.

Deixe um comentário

%d blogueiros gostam disto: