Executando verificação de segurança...
1

Os desafios e aprendizados de criar e publicar um pacote open source

Neste post, vou compartilhar minha experiência ao desenvolver um pacote para o GraphQL com Nest.js, abordando desde os problemas enfrentados até as soluções implementadas, os desafios superados e os aprendizados adquiridos ao longo do caminho.


O problema

Tudo começou entre 2021 e 2022, quando trabalhei em um projeto que enfrentava um problema recorrente: a necessidade de criar um arquivo para cada relacionamento em nossas entidades. Para cada relacionamento era necessário criar um novo dataloader, nomeá-lo, ajustar as entidades, chaves e retorno.
Isso gerava uma sobrecarga de arquivos e não era possível simplesmente copiar e colar, pois os relacionamentos variavam muito em estrutura e chaves. Apesar das tentativas, ninguém da equipe conseguiu encontrar uma solução efetiva.

Meses depois, em um projeto diferente, o mesmo problema apareceu novamente. Meu líder técnico me desafiou a buscar uma solução, e foi aí que a jornada começou.


Construindo a solução

Pesquisa e provas de conceito

Comecei a estudar sobre decorators e metadados, mergulhei no código do Nest.js e do pacote GraphQL oficial para o framework. Além disso, explorei o funcionamento do nextTick dentro do event loop no Node.js. Esse conhecimento inicial foi essencial para criar as primeiras provas de conceito.

No entanto, essas primeiras versões apresentavam vários problemas: baixa performance, vazamento de memória e uso inadequado de estruturas de dados.

Desafios de performance

Uma das soluções iniciais usava JSONPath para mapear chaves, mas isso trouxe perdas significativas de desempenho. Após testes de carga em uma aplicação real, percebi que minha abordagem aumentava o tempo médio de resposta em cerca de 8ms por requisição. Esse tempo estava longe do aceitável, e precisei repensar a implementação.

Após muitas tentativas e estudos, identifiquei o JSONPath como o principal culpado. Com a ajuda do ChatGPT (obviamente), criei uma nova implementação. O resultado? O tempo médio caiu de 8ms para menos de 0,1ms. Um resultado mais que satisfatório para a solução que estava sendo desenvolvida.


Tornando a API intuitiva

Desenvolver ferramentas para desenvolvedores é um desafio muito diferente de criar soluções para usuários finais. Enquanto aplicações tradicionais focam na interface ou na funcionalidade de uma API REST, por exemplo, ferramentas voltadas para desenvolvedores precisam ser claras, consistentes e se integrar bem ao ecossistema existente. Sem falar que desenvolvedores são mais críticos quanto as ferramentas que utilizam.

No início, a API que criei para o pacote tinha um design funcional, mas não era exatamente intuitiva. Essa percepção ficou clara após conversas e feedbacks do meu time.

Inspirado pelo decorator @Field do NestJS/GraphQL, decidi reformular a API para algo mais natural e alinhado com o que os desenvolvedores do ecossistema já estavam acostumados. Foi um processo de tentativa e erro, buscando equilibrar simplicidade e funcionalidade. Por fim, cheguei a uma API que não apenas cumpria sua função, mas também oferecia uma experiência mais fluida, intuitiva e integrada ao ecossistema do framework.


Testando e garantindo qualidade

Testes automatizados

No início, só havia testes manuais. Sabendo que isso não seria suficiente, comecei pelos testes E2E. Configurei um ambiente com Vitest e uma aplicação de teste, incluindo uma abstração do supertest + codegen para facilitar requisições e ter uma integração completa com TypeScript.

Durante os testes, vários edge cases apareceram, revelando problemas que eu não havia previsto. Um dos casos mais desafiadores foi lidar com relacionamentos circulares. Para resolver isso, adotei a técnica de Lazy Loading, que permite carregar os dados sob demanda, evitando problemas de referência cruzada e melhorando o desempenho geral.

Depois dos E2E, passei para testes unitários. Esses também revelaram mais casos não mapeados, que precisei corrigir.


Aprendizados

  • Feedback: Ouvir a opinião de outros desenvolvedores foi essencial para melhorar a API e alinhar a ferramenta com as expectativas do time.

  • Importância dos testes: Edge cases podem passar despercebidos até que você os encontre nos testes.

  • Frustração faz parte: Momentos difíceis no desenvolvimento são comuns, mas persistir é essencial para alcançar o resultado desejado.


    PS: Não ganhei 1 centavo fazendo isso, apenas o aprendizado de como funciona o Nest.js


Saiba mais

Se você ficou curioso sobre o nestjs-decorated-dataloaders, confira o repositório no GitHub: https://github.com/gabrieljsilva/nestjs-decorated-dataloaders.
https://www.npmjs.com/package/nestjs-decorated-dataloaders

Feedbacks e contribuições são sempre bem-vindos!

Carregando publicação patrocinada...