Tornando a Experiência do Desenvolvimento Mais Eficiente com Backend for Frontend (BFF): Uma Jornada de Adoção e Implementação
Neste artigo quero compartilhar uma boa experiência que tive com o BFF, trazer os pontos que me fizeram escolher essa forma de arquitetura para o desenvolvimento de um projeto na empresa onde trabalho!
Do começo
Trabalhei muito com um bom e funcional formato de desenvolvimento: O Backend ‘CRUD’ e o Frontend cuidando do tratamento de dados e requests.
Por mais que seja funcional e todos conhecem, comecei a trabalhar em telas que demoravam muito para carregar totalmente, uma request aqui, outra ali, uma condicional aqui, …, muito trefego de dados nessa historia, com essa dor, procurei mentoria com colegas mais experientes buscando uma solução, aí lançaram para mim o BFF!
O BFF
Bom, para definir o BFF por uma explicação rápida temos o seguinte entendimento: é uma API que vai encapsular uma resposta personalizada para diferentes UIs, como uma aplicação em mobile e uma web.
Sem nos aprofundarmos podemos tirar alguns pontos positivos e negativos como:
- Ponto super positivo: Todo dado da aplicação vai ter tratado internamente, uma mega camada de segurança
- Ponto positivo: O backend não precisa expor muitas rotas
- Ponto positivo: As regras de negócio estão todas no backend
- Ponto positivo: A UI vai ter a responsabilidade somente da própria UI e UX
- Ponto neutro: é uma melhoria do V do pattern MVC
TOP! É essa arquitetura que quero usar em novos projetos!
Implementação
Agora vem a parte boa, código, e para isso quero montar uma telinha para exemplificar uma implementação do BFF
Tela de carrinho, onde o usuário pode acionar/remover produtos no carrinho, pesquisar produtos e fechar a compra.
No primeiro passo podemos começar a montar a tela, em html mesmo:
<!DOCTYPE html>
<html>
<head>
<title>Shopping Cart</title>
</head>
<body>
<div>
<div id="sidebar">
<button>←</button>
<a>Carrinho</a>
<p>Total: R$ 7,00</p>
<button>Finalizar compra</button>
</div>
<div id="main">
<input type="text" placeholder="Pesquisar">
<div id="produto-1">
<img >
<h2>Meu produto aqui</h2>
<p>Descrição e talz</p>
<p>R$ 7,00</p>
<div><button>-</button><input type="text" value="1"><button>+</button></div>
</div>
<div id="produto-2">
<img >
<h2>Meu produto aqui</h2>
<p>Descrição e talz</p>
<p>R$ 14,00</p>
<div><button disabled>-</button><input type="text" value="0"><button disabled>+</button></div>
</div>
</div>
</div>
</body>
</html>
Tela montada, ta praticamente pronta, porem os dados precisam vir do backend, algo assim:
{
sidebar: {
backButton: {
text: "←"
action: "goBack"
},
title: "Carrinho",
details: {
value: "R$ 7,00"
label: "Total:"
},
checkoutButton: {
text: "Finalizar compra"
action: "request",
href: "/checkout/cart-123"
method: "POST",
onSuccess: {
action: "goTo",
href: "/checkout/cart-123"
},
}
},
main: {
search: {
placeholder: "Pesquisar"
},
products: [
{
id: "produto-1",
image: "https://via.placeholder.com/150",
title: "Meu produto aqui",
description: "Descrição e talz",
price: "R$ 7,00",
quantity: {
value: 1,
min: 0,
max: 10
},
buttons: {
quantityUpdate: {
action: "request",
href: "/checkout/cart-123/product-1",
method: "POST",
onSuccess: {
action: "refresh"
},
body: {
quantity: "::quantity::"
}
},
product: {
action: "goTo",
href: "/product/1"
}
}
},
{
id: "produto-2",
image: "https://via.placeholder.com/150",
title: "Meu produto aqui",
description: "Descrição e talz",
price: "R$ 14,00",
quantity: { value: 0 },
Disabled: true,
buttons: {
product: {
action: "goTo",
href: "/product/2"
}
}
}
]
}
}
Dinamica
Agora com uma conversa mais aprofundada, e trazendo mais sobre o fluxo, a dinâmica de comunicação do frontend com o backend vai ser a seguinte:
Frontend
O frontend vai 'iniciar', podendo trazer um loading, e, ao mesmo tempo, chamar a nossa rota BFF no backend(/api/screens/cart
), o retorno vai ser usado para montar a tela.
Sobre a montagem da tela temos já todos os valores formatados e traduzidos pelo backend, e também em ações temos o direcionamento(A famosa regra de negócio) já definidas, incluindo campos 'habilitados' ou não.
Na parte do direcionamento, vamos ter as 'actions' apontando oque fazer:
- goBack: faz a tela voltar
- goTo: le a propriedade de destino e move o usuário de tela
- request: direciona o frontend a fazer uma ação no backend
- onSuccess: é uma possível recursividade para um novo direcionamento
- refresh: recarrega a tela(OBS: Praticamente todos frameworks de frontend tem o controle dos componentes que precisam ser alterados, com isso se o json de retorno tiver somente o 'price' diferente, é esse o único componente que vai ser atualizado)
Backend
O backend é o cara que vai ter toda a responsabilidade nas costas, regras de negócio, disponibilidade de dados e desempenho!
Tendo somente uma rota para retornar a tela inteira montada, e outras 2 para ações do usuário(finalizar compra e alterar quantidade)
Tendo acesso a todos os dados, pode buscar por uma personalização da tela para o usuário, procurando por preferências como linguagem e moeda
Limitar os dados retornados para o frontend, evitando disponibilizar dados sensíveis
Ter muito mais velocidade em buscar dados, pois já está na nuvem
Extra
O backend pode ajudar muito o frontend, indo além, imagina agora eu adicionar em cada produto uma prop de searchTerms
, nela vou colocar todos os termos possíveis que aquele produto pode responder, algo como: ['productCode', 'title', 'colecation', 'tag']
, quando o frontend for fazer o filtro da pesquisa, está muito mais fácil saber oque filtrar.
E na mesma linha, imagina que tenhamos na sidebar
um botão de filtro rápido "Filtar produtos que estou comprando", para ajudar o frontend, o banckend pode trazer no produto uma prop de buying: true
para o filtro.
Também comentando que tanto no frontend, quanto no backend, é possível criar componentes que são especialistas que alguma parte do JSON do BFF. Um botão que é genérico o suficiente para tratar as actions
sozinho.
E se eu não usasse o BFF
Trazendo somente comparação, creio que teríamos estruturalmente esta aparência no projeto:
- Uma rota para carregar o usuário
- Uma rota para calcular o carrinho
- Uma rota para listar os produtos
- Uma rota para informar o estoque
- O frontend precisando de um 'localStore' para facilitar o controle da tela
- O frontend tendo que fazer várias requests, consumindo de certa forma muita 'banda'
- O frontend tento que utilizar processamento para modelar todos os dados
- O frontend tento que ter as regras de negocio 'clonadas'
Trabalho futuro e Considerações finais
Estou estudando para que esse backend BFF possa responder em partes(Trabalhar com streams), assim podendo responder partes da tela antes que outras, ou até atualizando alguns valores após ter a tela carregada...
Sou um dev fullstack e essa abordagem que apresentei neste post vem me agradando muito, estou tendo bastante desempenho em construir soluções novas bem solidas e de qualidade.
Ficarei muito feliz em receber sugestões, dúvidas ou até mesmo criticas!
Obrigado por ler o meu post :D