Reconstrução ágil: (re)criando um produto em tempo recorde

Como um novo framework e colaboração transversal revolucionaram nossa forma de construir interfaces

Morgana Johann
16 min readMar 25, 2024
Interfaces de usuário do Console, produto criado

Antes de começar, um adendo: este artigo foi escrito colaborativamente com o

, Software Engineering Manager e minha ex-dupla de trabalho. Aqui vamos trazer o ponto de vista de gestão e de liderança técnica de nossas áreas de expertise. Eu sou a Morgana, Product Design Manager.

O palco

Dois times independentes: Design de UI/UX e Engenharia de Software. Demandas diferentes, prioridades diferentes.

Tínhamos um Design System sendo criado internamente por estes mesmos mantenedores, o que estava possibilitando adicionar a nossa identidade visual ao produto — porém, demandava uma implementação completa do zero. E, com novas implementações, consequentemente surgiam novos bugs e correções. Além disso, mesmo tendo produtos utilizando os mesmos componentes visuais e lógicas de navegação, encontrávamos experiências diferentes entre eles. Mantendo, assim, nosso processo de desenvolvimento mais lento e inconsistente do que gostaríamos.

Desafios no Ciclo de Desenvolvimento

Parte da nossa aplicação era legada, o que dificultava fazermos melhorias tanto no código quanto de experiência e interface. O tempo de desenvolvimento de novas funcionalidades era um processo árduo, burocrático e que passava por uma série de etapas desde a concepção até a entrega em produção.

Problemas novos surgiam diariamente e, a cada necessidade de resolução de um problema ou criação de uma funcionalidade, estudos precisavam ser feitos pelo time de UX/UI Design e alinhados com stakeholders e engenheiros durante o processo, ou posteriormente, para entender se era tecnicamente viável desenvolver a solução.

Este processo levava tempo, pois muitas vezes uma série de novos problemas só surgiam durante o desenvolvimento. Percebiam-se questões que eram pré-requisitos para entrega, mas que não tinham sido previstas na fase de descoberta e ideação. Ou ainda, após a entrega da solução, lidávamos com o surgimento de bugs advindos dessas situações não previstas. Isso nos forçava a pausar o trabalho e voltar para etapas que considerávamos já vencidas, como análise, concepção, aprovação, desenvolvimento e, por fim, nova validação.

Nestas variantes, os itens que mais se destacavam negativamente para uma entrega eram:

  • Tempo de desenvolvimento de um novo produto ou feature
  • Inconsistências de sistema, tanto visuais quanto comportamentais
  • Resolução de problemas, como bugs e erros de frontend
  • Códigos legados que dificultavam atualizar jornadas e funcionalidades dependentes de backend.

O primeiro passo

Para iniciar o processo de reconstrução da interface, tínhamos alguns objetivos principais traçados:

  • Definições claras para uso de elementos de interface
  • Padronização visual e de experiência para o produto
  • Diminuir a curva de aprendizado e desenvolvimento
  • Acelerar o tempo de entrega de novas UIs
  • Reduzir retrabalho na validação de UI’s (CSS, HTML, design responsivo, etc)
  • Viabilizar testes de novas experiências diretamente no código e facilmente replicáveis.

Com 75% dos componentes codificados, documentados e prontos para uso, decidimos abandonar nosso Design System. Afinal, criar um sistema de design para sustentar um produto já existente não é tarefa fácil. A partir disso, nosso primeiro movimento foi buscar uma biblioteca de componentes de mercado, que fosse popular e open source, e atendesse às necessidades visuais e tecnológicas do nosso produto. Assim, conseguiríamos pular toda a etapa de criação de componentes e lógicas de interação para podermos focar em outras necessidades.

A partir dos pontos problemáticos identificados, adotamos um modelo de testes que chamamos de Sprint Hack. Mesmos desafios de um hackathon, mas no período de uma sprint, onde um pequeno grupo de Desenvolvedores e Designers trabalharam em conjunto em busca de uma solução de mercado pronta e bem resolvida, de acordo com os objetivos delimitados para o projeto.

Planilha onde pontuávamos as bibliotecas testadas pelo time

A primeira aposta: uso de IA — Inteligência Artificial

É notório que o uso de IA está cada vez mais popular em diversos setores do mercado, principalmente quando falamos de tecnologia. A promessa de automatização e absorção de atividades burocráticas, por exemplo, é algo que continuamente percebemos como promessas por diversas ferramentas do mercado.

Gerar uma aplicação por meio de inteligência artificial pode parecer algo simples quando observamos superficialmente, mas no momento que começamos a nos aprofundar no que diz respeito às necessidades do cliente, regras de negócio e manutenção de um sistema, o caos começa a surgir.

Foi logo no início da nossa jornada por bibliotecas de mercado que nos deparamos com algo extremamente promissor: uma IA que transforma designs em código de front-end. A partir do momento em que começamos a analisar esta possibilidade, outros concorrentes começam a surgir.

Locofy.ai

Fundada em 2021 por Honey Mittal e Sohaib Muhammad, a empresa, sediada em Singapura, surgiu na interseção da crescente necessidade de soluções de design para código e os avanços em Machine Learning (ML). Rapidamente ganhou notoriedade pois prometia a conversão de designs prontos feitos em ferramentas como Figma diretamente para o código.

E, assim como promete, funciona muito bem. Quando realizamos nossos testes e POC (proof of concept / prova de conceito), era possível conectar o design de um site/aplicação no Figma e exportá-lo para uma linguagem/framework como HTML, CSS e JavaScript puros. Ou ReactJS, por exemplo.

A arquitetura do projeto era criada seguindo as boas práticas do mercado, como estrutura de diretórios, nomenclatura de arquivos, técnicas de implementação, etc. Além disso, era possível conectar o código gerado diretamente a um repositório do GitHub para versionamento, vincular o repositório a um serviço de Hosting — como a Vercel, por exemplo, e finalizar com um domínio pronto rodando sua aplicação. A I.A. da aplicação era capaz de identificar estruturas que poderiam se tornar componentes e agrupá-las de forma organizada dentro do codebase do projeto. Enfim, fenomenal.

Mas, nem tudo são flores:

Como mencionamos: conforme se afunilam as necessidades novos requisitos vão surgindo. Normalmente, um código de uma média/grande aplicação não é mantido por apenas um único desenvolvedor. E mudanças diretamente no código se fazem necessárias para atender algumas demandas que a IA ainda não estava pronta para atender:

  • Como realizar a chamada para um API?
  • Como re-estruturar uma organização de diretórios e arquivos e fazer com que a IA entenda essa mudança como uma evolução?

Da mesma forma que ocorre hoje nas outras ferramentas de IA do mercado (exemplo DALL-E para geração de imagens), a cada interação uma nova imagem é gerada, não sendo possível realizar mudanças pontuais na imagem que foi gerada na interação anterior. Isso garante fidelidade e consistência entre as versões.

Exemplo:

Comando 1: "Crie uma imagem de um balde cheio de gatos" // Comando 2: "Altere essa mesma imagem para que todos gatos sejam pretos"

E esta particularidade se refletia a nível de código: cada versão de design atualizada fazia com que a IA re-gerasse boa parte do código existente na versão anterior. Para um projeto estático isso não seria um problema. Mas, como vimos anteriormente, implementações adicionadas "na mão” pelos desenvolvedores seriam perdidas a cada pequena modificação feita na ferramenta de Design. Um exemplo prático seria trocar a borda de um botão: isso poderia fazer com que todo código que já havia sido ajustado e integrado fosse perdido, gerando assim horas de retrabalho.

Trocar a borda de um botão é algo que um desenvolvedor leva segundos para fazer, mas correr o risco de levar horas para fazer “diff’s” de código para manter o que já estava integrado somente porque uma borda mudou de cor não parece uma boa ideia.

Outras ferramentas de IA testadas:

Realizamos testes, também, com o Plasmic e com DhiWise. Mas todas apresentaram um ou mais pontos importantes faltantes que nos impediam de seguir. Se todas juntassem suas principais funcionalidades talvez tivéssemos algo mais próximo da realidade que precisávamos. Inclusive, tivemos contato diretamente com desenvolvedores destas soluções, que estavam sempre abertos a sanar dúvidas e receber sugestões de melhoria. Mas cada produto tem o seu Release Plan e muitas dessas nossas solicitações estavam fora dele.

Nos deparando com esse tipo de cenário, aposentamos a ideia de usar a IA para esse fim (por enquanto).

Primeiro paredão: seguir com a codificação

Decidimos então deixar o uso da IA em stand-by e voltamos para a ideia de codificar algo “do zero”, mas em menor proporção. Essa proposta nos levou à ideia de utilizar frameworks ou bibliotecas de mercado, já bem resolvidas, que pudessem ser customizadas de forma fácil e consistente.

Alguns requisitos iniciais foram definidos, com o objetivo de possibilitar termos um caminho claro nessa etapa. Depois que fossem atingidos, poderíamos afunilar mais o escopo e elencar novos pontos focados na entrega final. Para o início, os objetivos eram:

  • A biblioteca deveria ter atualizações recentes
  • Ter uma versão estável
  • Contar com uma grande adoção no mercado
  • Ser flexível a ponto de poder ser customizada
  • Ser customizável de forma fácil de entender e propagar.

Neste momento estávamos indiferentes quanto à tecnologia da biblioteca, passamos por hipóteses em Vue, Angular, React e até Flutter. A ideia era, de fato, explorar o que nos era oferecido. Assim que conseguíssemos filtrar um pouco das possibilidades, afunilaríamos as buscas em torno das nossas necessidades.

Então seguimos por mais uma sprint em busca de algo que atendesse os nossos objetivos. E nessa lista entraram opções muito atraentes:

Flutter, Flowbyte, Preline, Vuetify, Shadcn-UI, Carbon Design System, Primer, PrimeVue (familia Prime — suporta Java, Ruby, React, Vue, Angular, etc).

Segundo paredão: definindo a tecnologia

O time era muito forte em JavaScript, mas com um grupo com vivência maior em VueJS. Logo, React necessitaria de um tempo de rampagem e Flutter geraria uma curva de aprendizado ainda maior. Algumas bibliotecas foram rapidamente eliminadas por alguns fatores bem relevantes:

  • Documentação desatualizada: o time não conseguiu encontrar informações de uso já no início dos testes
  • Baixa manutenção: muito tempo sem receber atualizações
  • Baixa adesão da comunidade: pouco popular, relatos em fóruns de reclamações e problemas
  • Muito recente: promissoras, mas ainda não maduras o suficiente
  • Número baixo de componentes prontos e estáveis.

Prólogo da definição

Enquanto um pequeno de time de 3 desenvolvedores e 2 designers faziam testes e experimentos, outras evoluções começaram a ocorrer de forma orgânica: a definição de uma metodologia de trabalho, um novo formato de condução dos desafios pelo time e a construção de uma proposta para padrões de arquitetura do novo projeto.

Como mencionamos no início deste artigo, o formato de trabalho vigente na empresa era definido em dois “silos”: Product Design e Engenharia.

Product Design ideava, desenhava, concebia as interfaces, analisando a experiência e usabilidade versus as necessidades de negócio. E, num efeito cascata, Engenharia entrava posteriormente para desenvolver o produto em cima desses conceitos. Nesta nova formação, os membros começaram a trabalhar e discutir juntos. Ideais começaram a surgir diretamente no código ao invés de serem primeiro exploradas em uma ferramenta como o Figma, por exemplo. Muitas provas de conceito foram canceladas no início da jornada, já evitando perda de tempo, pois empecilhos técnicos eram detectados com antecedência.

Uma dinâmica de como e onde estruturar o projeto começou a surgir e, ao final deste experimento, já tínhamos uma ideia sólida de como estruturar toda arquitetura do projeto, inclusive integrando com CI/CD para realização de releases.

O CSS handmade ficou de lado

Conforme o time foi explorando diversas bibliotecas na hackasprint de avaliação, notamos o uso de uma lib para CSS muito popular, que foi criada em meados de 2017 e evitava a necessidade dos hands-on direto em código CSS, fornecendo todas propriedades da linguagem de estilos através de seletores prontos: o TailwindCSS.

Apesar de não termos a flexibilidade de gerir um codebase CSS de forma mais reaproveitável, o Tailwind nos dava uma velocidade incrível no desenvolvimento. E ainda tinha uma curva de aprendizado muito curta, pois para usá-lo bastava conhecer CSS.

Terceiro paredão: o surgimento do vencedor

Após uma sanitização dos dados encontrados nessas explorações, o time apresentou o que foi estudado e o mapeamento de prós e contras gerado. Com essas informações claras, o time, gerentes e stakeholders concordam em eleger o PrimeVue com a biblioteca de componentes a ser usada pela empresa.

Planilha com as bilbiotecas testadas no “final round” e suas respectivas avaliações.

O PrimeVue é uma parte da família “Prime” de bibliotecas de interface de usuário, que começou com o lançamento do PrimeFaces, uma biblioteca popular para JavaServer Faces (JSF). A história do PrimeFaces remonta ao seu surgimento como uma solução para a construção de interfaces de usuário ricas para aplicações web em Java. Desde então, o ecossistema Prime evoluiu para atender a diversas plataformas e frameworks, incluindo Angular com o PrimeNG, React com o PrimeReact, e Vue com o PrimeVue.

Dentre os principais quesitos listados como necessidades pelo time, esta biblioteca contemplava quase todos:

  • Ampla comunidade
  • Atualização contínua
  • Suporte abrangente
  • Altamente customizável, baseada em tematizações.
  • Integrada ao Figma
  • Tecnologia Vue3
  • Suporte a TailwindCSS.

PrimeVue UI Kit

Um dos grandes diferenciais dessa biblioteca era a funcionalidade extra chamada Prime Vue UI Kit. Um pacote de definições que interligava todos os componentes ao Figma, incluindo tokens de tematização. Ou seja, era possível criar todo o design no Figma utilizando diretamente as definições de componentes do PrimeVue. E também ter acesso ao nomes e valores do tokens que eram definidos dentro do arquivo SCSS do tema. Dessa forma, ficava bem mais fácil de atualizar o tema com novas definições, dando a identidade do produto onde quer que fosse aplicado. Além de possibilitar uma estrutura base igual (ou muito parecida) entre Figma e código, facilitando a interação entre design e desenvolvimento.

Mesmo sendo uma feature paga, o valor justificava toda a agilidade que o time ganharia nesse desenvolvimento.

O primeiro projeto

Como motivador de toda essa demanda de descobrimento havia um grande propósito além da redução no tempo de desenvolvimento: migrar o atual sistema de gestão de serviços conhecido como Real-Time Manager (a.k.a RTM) para este novo modelo.

Em resumo, o RTM é um monolito estruturado sobre a linguagem Python (2.7.* — já sem suporte e deprecada desde 2020) e o maior empecilho em evoluí-lo é devido às grandes mudanças em relação a versão corrente 3.12.* . Como é de se esperar, essa atualização consumiria muito esforço e consequentemente geraria muito custo. Além de uma série de outras dificuldades relacionadas a manter a segurança da aplicação sem um suporte da comunidade, bem como a impossibilidade de uso de features mais robustas e performáticas que a versão atual da tecnologia disponibiliza.

A intenção era migrar todo o RTM para um modelo client-side, que seria capaz de efetuar todas as operações existentes no atual sistema via chamadas de API e não mais via processamento e renderização feito via backend. Logo, queríamos ter um repositório único, sem complexidade de abordagens micro-frontend, iframes ou múltiplos repositórios separados por módulos.

Dessa forma, surgiu a ideia da iniciativa do Console Kit: um monolito frontend, criado utilizando PrimeVue, TailwindCSS e Vue com Vite para seu desenvolvimento, temátizavel e passivo de ser hosteado em qualquer infraestrutura, pois teria acesso às API’s de forma independente e sem necessidade de configuração.

A cereja do bolo: o repositório deveria ser open source. Aberto para que a comunidade, clientes e desenvolvedores pudessem contribuir pró-ativamente por meio do processo de pull requests, bem como abrir issues relacionadas a bugs ou melhorias que vissem como viável para o projeto.

Arquitetura do projeto

Dogfooding como premissa

“Dogfooding é uma prática especialmente popular na indústria de desenvolvimento de software. Significa que uma empresa testa completamente seus produtos primeiro em si mesma, usando-os como os usuários finais fariam.” — Fonte: Jetbrains

Como estamos falando de uma aplicação toda em JavaScript (Vue), é plausível rodá-la em qualquer server que entregue conteúdo estático, porém queríamos mais. Queríamos que a aplicação fosse executada dentro dos servidores da Azion, utilizando o conceito de Edge Applications. Isso foi possível graças ao uso da CLI da empresa, que permitiu que cada usuário fizesse o deploy do seu próprio console, da sua estação de trabalho, via linha de comando. Ou que criássemos uma configuração de CI/CD utilizando GitHub workflows para realizar o deploy da aplicação.

Este processo foi concluído com sucesso e hoje, tanto no ambiente de preview quanto em produção, todo o deploy é realizado via GitHub Workflow + CLI da Azion.

A estrutura de blocos

Até aqui, já tínhamos uma estrutura robusta: uma arquitetura bem definida e uma biblioteca de componentes prontos de mercado. Diferentemente do nosso design system, com essa escolha não precisaríamos passar por todo o processo de desenhar componentes, garantir seus estados de interação, acessibilidade e demais regras. Isso já existia por default, acelerando consideravelmente o processo para a reconstrução de uma UI. Mas buscávamos ainda mais agilidade e consistência na experiência do produto.

Foi nesse momento que nos brilhou aos olhos a PrimeBlocks, da própria PrimeVue: uma biblioteca com blocos de interface já prontos. Ou seja, diversos componentes PrimeVue agrupados formando um bloco para uso específico, como formulários, headers, dialogs e etc. Porém, a própria PrimeBlocks, por mais robusta que seja, não atendia nossas necessidades de interface. Não conseguiríamos usá-la para resolver nossas jornadas de usuário, pois estávamos lidando com um produto bastante complexo. Mas nos inspiramos nesse conceito para criar a nossa própria biblioteca de blocos de UI.

Seguindo esta linha, o time de design fez um mapeamento meticuloso da interface do produto, a fim de entender quais eram as jornadas padrão existentes e quais blocos seriam necessários para abranger toda a interface do produto. Juntamente com os desenvolvedores, foram definidos os blocos que criaríamos e a forma de desenvolvimento de cada um deles. O foco era termos esses assets com funcionalidades já bem definidas, como responsividade, comportamento e estilo, e que pudessem ser replicados diretamente em protótipo ou no código como um componente (por de trás dos panos era um componente). Assim, cada bloco poderia ser atualizado e propagado de forma rápida e segura.

Mapeamento de quais categorias de blocos seriam utilizadas em cada seção do produto.

Dessa forma, após mais ou menos três meses de trabalho entre mapeamento, criação e desenvolvimento, ganhou vida o que estamos chamando de Azion Blocks: uma biblioteca Figma e uma biblioteca no código, idênticas, com todos o nosso blocos de interface.

Site com os Azion Blocks codados

Os ganhos e resultados

Com a abordagem baseada no conceito de blocos, usando Tailwind para o CSS, e estruturando a UI e UX baseada nos componentes existentes da PrimeVue, o esforço se afunilou em tematizar o framework e investir o tempo restante para definir jornadas de usuário, melhorar a experiência do produto e aplicar as funcionalidades desejadas para o desenvolvimento.

Em um comparativo de eficácia, seguindo premissas de que tivéssemos uma API CRUDL (Create, Read, Update, Delete and List) já disponível, o tempo para desenvolvimento caiu de 1 ou 2 semanas para 2 dias de desenvolvimento. Uma listagem de dados, vindos de uma API, levava cerca de 10 minutos para ser implementada, seguindo os padrões previamente definidos.

Ainda, o tempo para criação de protótipos diminuiu drasticamente. Com a utilização dos blocos de UI e de componentes já prontos, não era mais necessário que o designer fizesse folhas de handoff especificando cada pequeno comportamento para os desenvolvedores. Isso já estava definido por default e implementado nos blocos. Com isso, o tempo para criação de uma tela de interface no Figma fica em torno de 10 ou 15 minutos.

Além desses números, consistência visual e experiência unificada de uso dos produtos foram resultados que conseguimos alcançar. Além de aplicarmos melhorias de interface e experiência já na primeira entrega. Pontos que, no modelo de arquitetura anterior, eram bastante difíceis de serem alcançados.

Os ganhos e resultados

Observe que nem tudo é milagre, estes tempos contam com algumas premissas: que a API esteja pronta, que as regras de negócio sejam simples e preferencialmente validadas do lado da API, deixando para o frontend apenas validações mais básicas relacionadas ao formato da informação e obrigatoriedade de dados que precisam ser preenchidos para serem enviados.

Conforme o uso de toda essa estrutura ia acontecendo, algo esperado era que esses tempos de implementação aumentassem um pouco. Isso devido à adição de novos padrões, como a implementação de testes automatizados, validação de cobertura pré-commit e acoplamento de bibliotecas para validação de campos e regras de negócio, que exigiram um ramp-up do time no entendimento e aplicação dessas tecnologias. Para saber mais sobre elas: utilizamos o VueValidate/Yup, que é bastante flexível e abrangente em suas regras.

O início das implementações, desde a criação os blocos até a virada de interfaces, se deu em Agosto de 2023. No final de fevereiro de 2024 já tínhamos migrado 100% dos produtos da plataforma. Ficando em aberto apenas alguns ajustes finos, correção de bugs de baixa prioridade e definições de arquitetura para liberação de algumas funcionalidades mais complexas, trabalho que já está sendo feito pelo time.

Ou seja, em 07 meses construímos toda a arquitetura de base e viramos todos os produtos da empresa para a nova UI, algo em torno de 20 jornadas diferentes. Especificamente para a migração da interface da plataforma, de maneira que pudesse ser customizada e ajustada, bem como suportasse novas definições de UI/UX de maneira muito ágil, estima-se que foram necessários 04 meses.

Interface da plataforma RTM (esquerda) versus interface da plataforma Console (direita)

Enfim, UX Engineering

O time provisório que se formou com 3 desenvolvedores e 2 designers maturou, evoluiu e chegou à formação oficial, hoje chamada de UX Engineering (UXE), com 12 desenvolvedores, 4 designers e 2 managers (que aqui vos escrevem).

A metodologia de desenvolvimento passou a ser muito mais próxima, sem a existência de silos. Muitas provas de conceito começaram a ser feitas diretamente em código, deixando para o Figma só a concepção de novas experiências e para fins de estudos, antes das soluções entrarem na esteira de desenvolvimento.

O processo foi de muito aprendizado para todos os envolvidos, evoluímos desde hard-skills até as soft-skills voltadas para relacionamento entre o time, propagação de conhecimento, alinhamento contínuo e reports assertivos sobre a evolução e andamento dos projetos.

Um grande case que pode ser acessado diretamente GitHub ou ser testado na plataforma, resultado de todo esse processo: Azion Console.

De olho nos clientes

Seguindo a premissa do dogfooding, as primeiras versões do Console foram testadas internamente dentro da empresa. Desenvolvedores e analistas que costumam utilizar o produto foram encorajados a realizar suas tarefas prioritariamente no Console e, caso encontrem algum problema ou dificuldade, reportem o bug para o time.

Testes de usabilidade foram feitos, em parceria com UX Research, com nichos específicos de público, a fim de entender se a proposta dessa nova experiência está sendo clara e bem vinda. Como resultado desses testes, ajustes frequentes são aplicados e/ou documentados para futuros releases.

Planilha com a documentação dos testes de usabilidade realizados

Atualmente, estamos em fase de Preview. Ou seja, o Console está liberado para alguns usuários específicos, a fim de coletarmos métricas de uso e realizarmos testes mais aprofundados. A expectativa é que ele seja lançado para General Availability (GA) até o final do primeiro semestre de 2024.

Conclusão: é só o começo

Tentamos retratar aqui um resumo (isso é um resumo, acreditem) sobre o quão desafiador e animador foi vivenciar essa experiência e participarmos de algo chamado “re-evolução” na maneira de desenvolver interfaces e trabalhar em conjunto.

Fica aqui nosso agradecimento a todos os envolvidos, principalmente ao nosso time incrível. Com certeza esse será um projeto que entra para a classificação de inesquecível, sendo esse apenas o começo de tudo que ainda está por vir 🚀

--

--