Aplicando Clean Architecture em sua aplicação Android com Injeção de dependência, Use Cases e Repository.

Igor Thiago Correa Filho
Usemobile
Published in
5 min readSep 8, 2020
Photo by Scott Graham on Unsplash

Sempre que vamos definir o que usaremos em nossos projetos, nos deparamos com muitas possibilidades. Existem várias libs e padrões de projeto que podem nos auxiliar no desenvolvimento, que, por muitas vezes, chegamos a utilizar até mais do que é necessário, entrando em um processo chamado overengineer.

Para evitar esse problema, neste artigo vou explicar como utilizar Clean Architecture utilizando MVVM (Model-View-ViewModel) com Injeção de dependência, Use Cases e Repository. Essa implementação é boa tanto para projetos pequenos quanto grandes, pois ela é simples e escalável.

O objetivo aqui não é explicar todos os conceitos detalhadamente, e sim apresentá-los e ensinar como como utilizá-los juntos.

O que é Clean Architecture?

A Clean Architecture fornece uma metodologia a ser usada ao escrever códigos com o objetivo de facilitar o desenvolvimento, permitir melhor manutenção e reaproveitamento de código. Ao utilizar Clean Architecture, teremos camadas separadas e com objetivos únicos, criando, assim, um fluxo mais testável. Apesar da curva de aprendizado ser um pouco maior, os ganhos a longo prazo são mais vantajosos.

Cada uma das camadas tem conhecimento apenas de camadas de dentro. Isto é, a View conhece apenas a ViewModel, a ViewModel conhece apenas os Use Cases, e os Use Cases conhecem apenas os Repositórios, como podemos ver na imagem abaixo:

Passaremos agora por cada um dos conceitos que devem ficar claros para o bom entendimento de todo o fluxo.

Conceitos e ferramentas utilizadas

Injeção de dependência

A injeção de dependência é muito importante para mantermos no projeto um baixo nível de acoplamento, além de garantir a testabilidade das nossas classes. Para quem não está acostumado com o conceito de injeção de dependência recomendo dar uma lida aqui.

Para facilitar todo esse processo utilizei o framework Dagger.

Utilizando o Dagger para inicializar uma ViewModel, será necessária a criação de uma Factory que irá fornecer essa ViewModel da forma correta.

Após implementar a factory acima, o inicialização da ViewModel na View ficará da seguinte forma:

Lembrando que, como estamos utilizando Dagger, devemos avisar para ele que a View será injetada.

Todas as ViewModels, Repositories e Use Cases são fornecidos pelo Dagger, e todos devem ser declarados no construtor principal, para facilitar na hora de realizar testes.

Dessa forma, ao testar a classe LoginViewModel, podemos passar um LoginUseCase mockado no construtor da ViewModel.

Funções como parâmetro

O Kotlin nos permite passar funções como parâmetro, o que vai ser extremamente prestativo no nosso caso. Isso porque a ViewModel terá uma função de erro que normalmente é geral; e uma de sucesso que, por sua vez, geralmente deve-se ter uma para cada Use Case chamado.

As funções de sucesso serão usadas para recebermos os valores já formatados que queremos de uma chamada remota, e o Use Case fará esse trabalho para nós.

Já a função de erro fica por conta de informar à View que ocorreu um erro na requisição.

Neste exemplo de login, observamos que os parâmetros passados ao Use Case são e-mail, senha, função de sucesso e função de erro. O e-mail e senha serão utilizados na requisição para o login e as funções de sucesso e erro serão chamadas quando e se necessário.

A função de sucesso indica para a View parar o progress, informando que o usuário foi logado com sucesso. Enquanto isso, a função de erro solicita a parada do progress e indica falha no login do usuário, reportando o erro recebido.

Todas as LiveDatas são observadas pela View e, através dos valores recebidos nela, a View realiza determinadas ações. Por exemplo: navegar para uma outra activity ou fragment, mostrar um toast, parar ou iniciar um progress

Use Case

Como o próprio nome já diz, o Use Case controla os casos de uso do seu projeto. Exemplos disso são: acesso a diferentes repositórios para atualizar dados locais e a formatação das respostas recebidas para que seja possível o melhor acesso delas na ViewModel. Ou seja, o Use Case tem acesso ao(s) repositório(s) necessários.

Muitas vezes o Use Case vai ser apenas um mediador entre a ViewModel e o repositório, mas é importante mantê-lo para que a arquitetura do projeto seja mantida. Além disso, eles ajudam muito na hora de reaproveitar código.

Um exemplo disso é quando duas ViewModel diferentes necessitam chamar o mesmo endpoint. Com o Use Case bem feito, toda a parte lógica já estará pronta, logo, fica a cargo das ViewModels apenas chamarem a função execute e passarem os parâmetros necessários.

Percebemos através do exemplo que: o Use Case tem acesso ao repositório que realizará o login do usuário (LoginRepository) e ao repositório que salvará o usuário localmente (UserRepository). Com isso, no retorno da função de sucesso, o Use Case pega o usuário recebido remotamente, salva localmente e chama a função de sucesso para ser ativada no LoginViewModel.

Repository

É a camada que controla o acesso aos dados, deixando as coisas separadas e mais bem definidas, criando uma barreira entre a aplicação e seus dados. Ela faz também com que o método de cada acesso seja individual, podendo mudar a qualquer momento sem interferir nas outras camadas.

Para isso criamos uma interface com os métodos do repositórios. No nosso exemplo, chamaremos a interface de LoginRepository e a implementação dela de LoginRepositoryImp. Para obter acesso a esses métodos com o Dagger, faremos o seguinte:

A partir daqui, a implementação do repositório depende do que você estará utilizando para acesso aos dados. O importante é separar a camada de dados da sua aplicação. No nosso exemplo, a interface do Repository será a seguinte:

Com isso, completamos todo o fluxo da nossa aplicação. Desde a ação que o usuário toma até o retorno que daremos a ele.

Por hoje é só! Obrigado por ter acompanhado até aqui. Espero que todos os pontos tenham ficado claros e que te ajudem a melhorar sua aplicação. E lembre-se: antes de utilizar algo, sempre pense no que isso pode te ajudar, porque se não estiver ajudando em nada pode estar atrapalhando.

Qualquer dúvida ou sugestão estou a disposição. Acredito que tudo pode melhorar e mudar. Grande abraço!

--

--