Um projeto de estudo de uma aplicação web SPA com design criado por mim no figma, feito em Vue.js 3 com Typescript, Pinia, Tailwind CSS, componentes Vuetify e testes com Vitest, que integra uma API GraphQL gratuita do desenho Rick and Morty, e usa a ferramenta Vite.
Tem como proposta ser um site que pode ser utilizado por artistas ou curiosos para conhecer sobre o desenho, permitindo buscar personagens por nome, ou por categoria, e até se surpreender com personagens gerados aleatoriamente.
Design do projeto
Não sou designer, mas para aprender sobre UX e UI, elaborei todo o design desse projeto utilizando-se de técnicas de UX (User Experience) para definir as funcionalidades da página, e de padrões de UI (User Interface), seguindo o processo relatado a seguir.
Primeiro foi definido o problema do projeto "encontrar personagens do rick and morty para relembrar e se divertir com os amigos", depois de compreendido que já haviam soluções semelhantes ao projeto, efetuei uma pesquisa por referências para encontrar abordagens que poderiam ser utilizadas.
A partir daí pensei no conceito da solução, e defini que ela surgiu para facilitar a vida de quem precisa encontrar tipos de personagens do rick and morty, seja para desenhar, para desenvolver jogos do tema, ou simplesmente relembrar. E a sua característica seria possuir filtros e campo de busca que permitisse encontrar qualquer personagem do desenho.
Então realizei uma análise da jornada do usuário no projeto, entendendo as ações que o usuário poderia tomar na página para atingir o seu objetivo e os desafios que eles poderiam enfrentar para facilitar a definição do projeto. Desse entendimento criei um fluxograma da jornada do usuário na prática, pensando em todo fluxo de páginas e em como o usuário poderia interagir com cada funcionalidade da aplicação web.
Com tudo planejado fui em busca dos Patterns UI para esse tipo de aplicação, e selecionei para me inspirar os padrões Search Filters e Pagination, utilizados no projeto.
Neste projeto testei técnicas de desenvolvimento com BDD (Behavior Driven Development) no front-end, aprendi a pré-configurar um guia de estilo padrão com o Tailwind CSS, aprendi a usar o Pinia com testes Vitest, utilizei pela primeira vez a biblioteca Vuetify para os componentes e aprendi a criar queries GraphQL para integração com a API.
Diante dessa experiência de estudo cheguei a algumas conclusões sobre os tópicos citados, que foram compilados nas abas a seguir.
Apesar do BDD ser uma técnica de desenvolvimento que envolve outros membros como QAs, POs entre outros, e este projeto ser criado apenas por mim para estudo, criei todos os cenários de testes com notação Gherkin, de forma a adquirir habilidades de traduzir as funcionalidades criadas por mim para uma linguagem simples que possibilite a compreensão de qualquer envolvido no projeto e para treinar minha capacidade de desenvolver orientado a comportamento, no fluxo de criar o teste para falhar, desenvolver a funcionalidade para passar e refatorar o teste.
Com essa experiência pude perceber que criar os testes para interfaces antes delas estarem efetivamente desenvolvidas, pode ser tornar complexo, principalmente ao utilizar uma biblioteca de componentes como o Vuetify. Por isso é necessário que haja algum conhecimento prévio do funcionamento da biblioteca utilizada para que se tenha um desenvolvimento mais eficiente.
Em compensação, testes de unidade são os que lidam melhor com o BDD, pois testar uma função é mais fácil e mais eficiente do que testar como e quais dados serão exibidos na tela. Os testes de componentes Vue, podem ser considerados de integração, e por isso são mais difíceis de criar sem uma base desenvolvida em código.
Para interfaces o ideal é ir testando se os seletores esperados contém o conteúdo que deveria, como um título da página, ou a ação de botões, mas usando uma biblioteca de componentes o teste pode mudar e validar se o componente possui a propriedade esperada para exibição do título, por exemplo.
Mas no geral os testes escritos com notação Gherkin ficam mais fáceis de serem compreendidos, o que facilita a manutenção e refatoração durante o processo de desenvolvimento, isto é muito positivo e com a prática fica cada vez mais fácil descrever a funcionalidade conforme seu comportamento. Apesar de que alguns tipos de testes não façam tanto sentido possuir toda uma descrição do formato Gherkin, ainda sim é positivo escrevê-los assim, pois irá garantir que o teste cubra sempre aquele exato cenário.
Já havia utilizado o Tailwind anteriormente, mas foi a primeira vez que defini os padrões de estilo do projeto no começo do desenvolvimento em uma pré-configuração do tailwind.
Todo o projeto criei como uma pré configuração para meus projetos pessoais, de forma a deixar tudo mais prático, ampliando a produtividade dos meus estudos também.
Configurar animações css e media queries padrões facilita muitas alterações do projeto e garante que tudo esteja sempre padronizado, de forma que não fique perdido em arquivos SASS aleatórios ou em variáveis CSS esquecidas.
Não gosto da desorganização de inserir várias classes utilitárias diretamente nos componentes, por isso criei classes com a metodologia BEM e fiz a aplicação necessária nelas. Percebi que tive um aumento significativo da produtividade na escrita do css, mesmo sem ter decorado grande parte das classes Tailwind, o que é bem positivo.
No geral o ganho de produtividade compensa, mas para fazer sentido o uso do tailwind, é preciso ter um padrão de design tokens, e a partir desse padrão configurar as classes utilitárias do projeto, essa etapa inicial é o que fará a diferença.
Foi a primeira vez que utilizei componentes Vuetify em um projeto e pude concluir que é uma boa biblioteca que facilita o desenvolvimento por já vir com interações pré definidas e por possuir um mínimo de acessibilidade.
Mas há problemas para aplicar estilizações nas partes que não há personalização dos componentes da biblioteca, o que piora ao utilizar também o tailwind, e mesmo usando seletores específicos em alguns casos é impossível definir estilo de maneira simples.
Outro problema ocorre com os testes, que devido ao uso da biblioteca eles precisam estar muito bem desacoplados, com lógica separada, aumentando assim a quantidade de testes de unidade. Em consequência, testes de componente, que podem ser considerados testes de integração, ficam mais complexos, o que por um lado é uma desvantagem por outro lado pode ser considerado um benefício pois estes testes são demorados e no final se tem um ganho de tempo, mas você terá que confiar que os desenvolvedores do Vuetify testaram bem as funcionalidades do componente
Por fim posso concluir que se o objetivo é ganhar tempo a biblioteca irá atender bem, mas você terá uma personalização mais rígida, portanto se inventar demais no design o tempo que será gasto tentando aplicar esses estilos pode não compensar o seu uso, e além disso saiba que os testes de unidade podem levar mais tempo se ainda não domina o vue-test-utils e os composables do Vue.
Já havia criado projetos com gerenciamento de estados Vuex, e resolvi testar pela primeira vez o uso do Pinia. Ele é muito mais prático que o Vuex, por não precisar criar mutations para alterar o estado.
É muito mais fácil de configurar para o uso com Typescript, enquanto que no vuex é preciso criar uma key que possibilite a tipagem, no pinia não precisamos nem mesmo definir uma interface para a store de estado que tudo será automaticamente identificado. Também é um ponto muito positivo a facilidade de se criar stores, basta criar um arquivo e começar a definição com o defineStore.
O ponto negativo é que as stores com typescript são mais engessadas, é preciso escrever todas as actions e o state em um mesmo arquivo, o que pode ficar muito grande em alguns casos, e por isso é sempre ideal dividir em mais stores à medida que ela cresce. O vuex leva vantagem por permitir extrair as funções para arquivos individuais e importá-las para a store, e não é que o pinia impossibilite esta exportação, até é possível mas é uma prática que a documentação não aborda, recomendando apenas o uso de todas actions, computed e states dentro da store, pelo menos até o momento em o Pinia está na versão 2.1.4.
Mas vale muito a pena utilizar o Pinia por toda facilidade que ele oferece, quem está habituado com o Vuex aprende a lidar muito rapidamente com o Pinia, e como ele é o gerenciador de estados atualmente recomendado pelo Vue, recomendo começar seus projetos com ele.
Sobre o Vitest, ele é bem parecido com o Jest e é fácil de se acostumar. A principal vantagem do uso é sua rapidez de execução, e se optar pelo Vite no seu projeto é bom nem considerar o Jest, pois a suite de testes perfeita nesse caso é o Vitest que lida muito melhor com as variáveis de ambiente do Vite por exemplo.
Na minha experiência percebi que lidar com os mocks do Vitest é a parte mais complicada em relação ao Jest, algumas coisas mudam no uso dos espiões e na forma como os mocks são executados. Por isso, se tiver que migrar algum projeto com o Jest que possua mais de 600 testes com muitos mocks é bom ter consciência que poderá gastar um bom tempo ajustando os métodos que utilizou para mockar.
A conclusão é que se o projeto é novo e usa o Vite, sem dúvidas você deve optar pelo Vitest, mas se o projeto já existir com o Jest e você quiser mudar para o Vitest existem outras variáveis a serem consideradas para decidir.
Já conhecia o GraphQL e havia estudado brevemente sobre ele antes, mas precisava obter uma experiência em projeto, por isso escolhi a API do Rick&Morty feita em GraphQL.
Para começar considerei utilizar o Vue Apollo, mas com 230 issues abertas, 5 PRs e a última atualização lançada em novembro de 2021 resolvi não optar por ele. Sabendo que poderia usar GraphQL sem precisar de um Apollo Client, optei por fazer assim e ainda aprender sobre isso.
Dessa forma eu utilizava o playground disponibilizado pela API para gerar a query que precisava, evitando que erros fossem cometidos, podendo testar no navegador, e com a query pronta a inseria no projeto em uma classe especificando cada método para um tipo de busca a ser feito na API, e com a classe instanciada na store Pinia chamava o método que precisava dentro da Action. Não sei se essa seria a melhor forma de fazer isso, pois não tive muitos exemplos para me inspirar durante a construção do projeto, mas funcionou muito bem.
Pude concluir que o uso do GraphQL diretamente na requisição fetch sem um Apollo Client no geral é viável, no caso de acabar alterando alguma query sem querer o erro retornado na API mostra exatamente o que ficou errado. É claro que ter algo que me permitisse validar a query e exibir os possíveis erros no próprio código facilitaria o desenvolvimento, mas mesmo assim penso que ainda vale a pena considerar o uso do GraphQL sem um intermediador como o Vue Apollo.
Sobre o GraphQL, percebo que ele é mais complicado para tratar erros, é preciso entender muito bem o padrão de retorno da API em uso para que o tratamento seja eficiente, pois o status code faz falta. Mas a liberdade que ele possibilita ao front-end é o grande destaque, é um BFF (Back-end For Front-end) que adiciona muito poder para melhorias de performance.