Clean Architecture + ReactJS Pt. 2

Criando a camada de infra e presentation

João Guilherme Berti Sczip
5 min readAug 4, 2020

Dando continuidade à série de artigos que resolvi escrever sobre a implementação da Clean Architecture utilizando ReactJS (a primeira parte pode ser lida aqui), nesse post me concentrei em dar continuidade à implementação dos casos de uso e também em realizar a composição da camada de apresentação (é aqui que o React entra).

Infra Layer

No final da primeira parte finalizei a implementação do caso de uso SendImage em uma classe concreta, essa classe possui uma dependência de um protocolo HttpPostClient definido em Data Layer, que deverá ser implementando na camada de infraestrutura.

A camada de infra é onde se encontram as implementações de classes que deverão se conectar com o mundo externo, as quais tem a responsabilidade de realizar requisições HTTP e operações em um banco de dados, por exemplo.

No exemplo escolhi a biblioteca axios para realizar esse trabalho. Em infra / http criei o arquivo axios-http-client.ts. A Figura 1 logo abaixo contém a implementação.

Figura 1 — AxiosHttpClient

Algumas observações sobre a implementação:

  • O tipo de retorno da resposta está como any (qualquer), porém, com o auxílio do Typescript, pode facilmente receber um tipo mais apropriado;
  • Outro detalhe importante aqui é a interface HttpPostClient, por que não criamos uma interface mais genérica, ao invés de uma que só sabe realizar requisições do tipo POST? Uma interface mais genérica estaria quebrando o princípio da letra I do SOLID o da segregação de interfaces. Nossa implementação ainda só se preocupa em fazer requisições do tipo POST, tornando desnecessário nossa interface possuir algum outro método, assim, a partir do momento que precisamos realizar algum outro tipo de requisição, definimos outra interface e fazemos com que o AxiosHttpClient também a implemente, tornando uma classe bastante flexível.

Presentation Layer

Após tanto código escrito, chegou o momento de começar a utilizar o React de fato. Toda a UI da aplicação ficará restrita à camada de apresentação, não contendo nenhum tipo de lógica de domínio, apenas a lógica da própria UI.

Lembrando que o conteúdo da camada de presentation é bastante relativo ao tipo de software que está sendo escrito, por exemplo, caso essa aplicação fosse uma API, nossa camada de apresentação iria possuir os controllers, responsáveis por capturar e tratar as requisições HTTP.

Dentro de presentation / pages / PhotoUpload crio o arquivo index.tsx, conforme ilustra a Figura 2. Optei também por utilizar a biblioteca styled components para trabalhar com a estilização.

Figura 2 — PhotoUpload page

Algumas observações importantes sobre a página:

  • Componente React do tipo funcional component, utilizando hooks para sua lógica interna e gerenciamento de estado interno do componente.
  • Pode-se observar também que o componente depende de uma interface SendImage, definido em suas props. Essa inversão de dependência é uma das principais vantagens de se utilizar uma arquitetura flexível mesmo ao utilizar uma biblioteca como o React.
  • A primeira vantagem é que a nossa UI não sabe como essa imagem será enviada, ela só precisa de um componente que saiba fazer esse envio, vemos nesse exemplo mais um princípio do SOLID, dessa vez o S, onde cada parte do sistema possui sua única responsabilidade.
  • Outra vantagem é que se um dia as imagens não forem mais enviadas por HTTP, ou também, se decidirmos trocar o axios pelo fetch, ou alguma outra biblioteca, essa mudança não trará nenhum impacto à nossa UI.
  • Por nosso componente depender apenas de uma interface, podemos, através da ajuda do polimorfismo, injetar qualquer classe concreta que implemente o mesmo protocolo, que em nosso caso será o RemoteSendImage.

Main Layer

Com todos os componentes necessários para a aplicação funcionar, chegou o momento de criar a composição desses componentes, para isso existe a camada Main.

A Main Layer é onde realizamos a criação e instanciação de todas as classes concretas responsáveis pelo funcionamento na aplicação, é o lugar aonde injetamos as dependências. Main Layer também é conhecido como Composition Root, onde a nossa árvore de dependências é criada.

Nessa camada é onde ocorre todo o acoplamento com demais bibliotecas e classes, também é onde pode-se fazer uso de algum framework de injeção dependência, entretanto, decidi por usar o pattern Factory.

Dentro de main / factories / pages / PhotoUpload crio o arquivo index.tsx, responsável por criar um PhotoUpload e suas dependências, conforme ilustra a Figura 3.

Figura 3 — PhotoUploadFactory

PhotoUploadFactory é apenas uma função que retorna um component PhotoUpload, para satisfazer a sua necessidade de um SendImage, injetamos um RemoteSendImage, que por usa vez também possui as suas dependências criadas.

Com a Factory criada, agora a adicionamos no arquivo index.tsx, responsável por realizar o bootstrap da aplicação. Esse arquivo também pertence à Main Layer, como mostra a Figura 4.

Figura 4 — index.tsx

E por fim, temos a nossa tela funcional.

Figura 5 — Tela funcional

Conclusão

Enquanto na primeira parte do artigo me preocupei em explicar os fundamentos da Clean Architecture, nessa segunda minha maior preocupação foi em provar através da implementação como de fato essa metodologia torna a aplicação mais flexível.

Diferentemente da grande parte dos exemplos que podemos encontrar na internet, essa implementação provê uma abordagem bastante diferente, onde o foco da nossa UI é apenas a lógica de apresentação. Conseguimos criar um componente totalmente independente da nossa lógica de domínio e vice-versa.

Se possuímos um caso de uso que precisa enviar uma imagem ao servidor, tanto faz se utilizamos uma página criada em React, Angular ou Vue, o nosso domínio não se preocupa com isso, se preocupa apenas com o núcleo da aplicação. Nosso domínio precisa funcionar da mesma forma independentemente do framework ou bibliotecas que estivermos utilizando, para que se algum dia seja necessário uma troca mais delicada, consigamos fazê-la sem precisar investir muito tempo nisso.

A partir do momento que temos uma arquitetura mais flexível e robusta, além de fortemente abstraída, conseguimos observar na prática os benefícios da orientação à objetos e de seus princípios sendo cumpridos. Em um primeiro momento pode parecer trabalhoso demais, de certa forma até é, pois é necessário criar muitos protocolos e implementações, porém, a longo prazo, é um trade-off que realmente vale a pena.

Links e referências

--

--