Como calcular a velocidade em times de desenvolvimento

Sempre costumo dizer em meus treinamentos que “ágil não é bagunça”. A prova disso é a disciplina necessária para conseguir pôr em prática as 13 páginas do Scrum Guide, fora a quantidade de estudo que demanda as técnicas complementares como User Stories, Pair Programming, Kanban, Planning Poker e muito mais. Mas algo pouco debatido e muitíssimo importante é a parte de métricas ágeis do time.

Mas porque eu preciso de métricas em times ágeis?

Para que exista um plano de melhoria contínua concreto em execução junto ao time.

Sem métricas o time simplesmente pode rodar o ágil na sua forma mais básica, mas não estará melhorando continuamente o que é um grande risco. Estudiosos dos processos japoneses de manufatura, de onde o Lean surgiu (Toyota) e de onde o Scrum foi baseado, são categóricos em afirmar que todo processo enxuto de produção (logo os processos ágeis também) sofrem deterioração ao longo do tempo se não estão sempre em contínuo esforço de melhoria.

Ou seja, agilidade é uma jornada, não um destino.

Logo, se para me manter ágil devo sempre estar buscando a melhoria contínua e para que possa melhorar continuamente de maneira sustentável e assertiva, preciso de métricas. Afinal, o que não é medido não é gerenciado, como diria William Demming.

Isso fica ainda mais evidente quando você como Scrum Master full-time ou Agile Coach (meu caso) deve estar olhando para mais de um time ao mesmo tempo, mas não subestime o poder de ter métricas sob constante vigilância mesmo em times pequenos e avulsos.

No artigo de hoje, vamos falar da métrica mais popular, a Velocidade!

Você vai ver neste artigo:

  1. Velocidade (Velocity)
  2. Velocidade no Azure Boards
  3. Velocidade no Jira Software
  4. Velocidade Manual
  5. E quando a velocidade vai mal?

Vamos lá!

Velocidade (Velocity)

Essa é a métrica mais básica que todo Scrum Master ou Agile Coach tem de saber mensurar. Em algum momento alguém vai lhe questionar: qual a velocidade do seu time?

Não existe uma única unidade de medida, sendo as mais populares:

  • Horas: muito comum, apesar de comumente falha, herdada do waterfall;
  • Pontos: me refiro a Story Points (oriunda das User Stories) e não aos Pontos de Função e Pontos de Caso de Uso, também do waterfall. É muito utilizada como Scrum e XP. Falo mais dela no artigo de estimativas.
  • Tamanho de Camiseta: ordem de grandeza em P, M, G, etc  para cada item, como os tamanhos de uma camiseta (t-shirt size no original). Possui racional parecido com a de Pontos e se desprende ainda mais do conceito de “horas/homem”;
  • Contagem de Itens: ou issue count, você não estima, apenas conta o número de itens mesmo, muito utilizada em Kanban e de boa utilidade em times mais maduros;

Velocity funciona desde que você seja honesto, escolha uma unidade que funcione para o seu time e que você acompanhe a mesma, sem ficar mudando. O objetivo é você conhecer o ritmo do seu time para que seja possível identificar e fazer ajustes quando há variação pra menos ou para seguir melhorando os resultados no dia a dia.

Além disso, ter uma boa métrica de velocidade auxilia na previsibilidade do roadmap do Product Owner, obviamente sempre respeitando o bom senso e a máxima de que “a única constante em software é a mudança”.

Mas como medir a velocidade do time?

Os métodos ágeis são empíricos, logo, baseiam-se em experiência prática passada para poder tirar conclusões sobre o futuro próximo. Sendo assim, o único jeito de saber a velocidade do time é fazendo com que ele rode de uma a três sprints, no mínimo, com a mesma formação, para ter uma média e poder descobrir essa métrica.

Independente da unidade escolhida, você terá de registrar o montante planejado (estimado) e compará-lo ao fim do período com o montante efetivamente realizado (DONE). Lembrando que na agilidade não existe “quase pronto” ou “parcialmente entregue”. É fez ou não fez.

Muito importante ressaltar também que a velocidade de um time é reflexo de todo um contexto que envolve: tecnologia, perfis de pessoas, experiência do time, quanto tempo trabalham juntos, o quanto conhecem do projeto, etc. Qualquer alteração nesse sensível contexto irá provocar oscilações na velocidade. Quando estas oscilações são pequenas, não há problema, mas oscilações drásticas indicam riscos ao projeto e devem ser resolvidas.

Mais importante ainda é ressaltar que jamais você deve comparar a velocidade de dois times. Medimos a velocidade de um time para compará-lo sempre com ele mesmo, jamais com os outros.

Abaixo, vou explicar como medir a velocidade nas duas ferramentas de gestão ágil de projetos mais populares em corporações e na sequência dou mais algumas dicas para fazer à mão ou em ferramentas mais limitadas que não possuam relatórios de velocidade.

Livro para Agile Coaches
Livro para Agile Coaches

Velocidade no Azure Boards/DevOps

Na ferramenta Azure Devops a velocidade (Velocity) é calculada automaticamente no Product Backlog, desde que você use o campo Effort dos Product Backlog Items/User Stories (dependendo do seu template) corretamente. Você encontra esta informação no canto superior direito da tela, na visão de Product Backlog.

Também é possível adicionar um widget Velocity no dashboard do time, como abaixo.

  • Barra azul claro representa o montante planejado;
  • Barra verde escura, o montante finalizado na sprint (DONE);
  • Barra verde clara, o montante finalizado depois da sprint terminar;
  • Barra azul escuro, o montante que não foi finalizado;
Velocity
Velocity

O gráfico mostra essas barras sprint a sprint (últimas 5 sprints), além de ter um resumo da velocidade média no canto superior direito.

Velocidade no Jira Software

Na ferramenta Jira Software, a velocidade é calculada automaticamente no relatório Gráfico de Velocidade, desde que você utilize o campo de estimativa apropriado.

Qual é o campo de estimativa correto?

Se nas configurações do board principal do projeto a métrica de estimativa é Story Points, use o campo Story Points para estimar e com isso a velocidade será calculada por ele.

Agora se a configuração do board está como Estimativa de Tempo Original (horas), use este campo durante o preenchimento das issues para que o relatório saia correto.

E por último, se a configuração está como Contagem de Itens (Issue Count), então não há a necessidade do lançamento de qualquer estimativa, pois as Stories serão contadas apenas.

  • Barra cinza significa o montante planejado;
  • Barra verde significa o montante finalizado na sprint (DONE);

As barras são calculadas sprint a sprint e dependem que você esteja iniciando e encerrando as sprints corretamente na ferramenta, caso contrário a informação estará errada.

Além disso, logo abaixo do gráfico, na mesma página do relatório, você encontra as mesmas informações, em formato textual.

Se quiser dominar esta ferramenta, dá uma olhada no curso abaixo.

Curso Jira

Velocidade “manual”

Caso você esteja utilizando alguma ferramenta que não lhe forneça os cálculos automáticos, como o Trello, você pode pode registrar e calcular de maneira manual, não é um processo complicado, apenas mais trabalhoso.

Minha sugestão é que você comece utilizando um Burndown Chart (clique no link se não conhecer). Uma vez que você tenha ele (no artigo do link eu forneço uma planilha para calcular no Excel) alimentado corretamente, basta que ao final de cada sprint você tome nota em uma planilha do planejado x realizado (canto superior esquerdo e canto inferior direito do burndown, respectivamente).

Após você ter registrado o planejado x realizado de umas 3 sprints, basta calcular a média ou mediana e você terá a tão sonhada métrica de velocidade do seu time para lhe ajudar com o projeto.

E quando a Velocidade vai mal?

A métrica de velocidade, assim como todos os indicadores existentes, servem a um único propósito: provocar reflexão.

Assim, não tire nenhuma conclusão imediata ao ver a métrica de velocidade ao final de uma sprint. Pare, pense, reflita, converse com o time. Se a métrica aparentemente está ruim, traga para uma retrospectiva, esse é um ótimo gancho para o time debater melhoria contínua e para, por exemplo, o Scrum Master identificar os principais gargalos que possam estar atrapalhando a produtividade time.

É importante frisar que a velocidade é do time, e não de uma pessoa. Os problemas devem ser sempre analisados de maneira sistêmica e nunca apontando um dedo a alguém. Principalmente considerando que na maioria dos casos que tive a oportunidade de experienciar, o problema não era uma pessoa, mas comunicação, dependências, tecnológico, etc.

Neste outro artigo, falo de métricas para Agile Coaches.

* OBS: curtiu o post? Dá uma olhada no meu curso sobre o mesmo assunto clicando no banner abaixo!

Curso de Scrum e Métodos Ágeis
Curso de Scrum e Métodos Ágeis

Como fazer upload de arquivos no AWS S3 em Node.js

Anteriormente eu escrevi um tutorial aqui no blog de como fazer upload de arquivos em Node.js, usando as bibliotecas Formidable e Multer. Se você não sabe como fazer isso ainda, esse é um pré-requisito para este tutorial, então volte lá e leia o outro tutorial!

No entanto, em aplicações web profissionais, quer elas sigam a metodologia de 12-Factor App ou não, você NÃO DEVE armazenar os arquivos carregados (que fizeram upload) na sua aplicação junto ao servidor da mesma. Ao invés disso, você deve armazenar em um serviço próprio para armazenamento de arquivos.

Alguns motivos incluem:

  • o servidor da sua aplicação deve ser descartável, principalmente se estiver usando Docker, mas os arquivos carregados não são descartáveis;
  • o custo de armazenamento do servidor da sua aplicação muitas vezes é maior que o custo de armazenamento de um serviço de armazenamento;
  • quanto maior o tamanho do servidor da sua aplicação, mais difícil é para fazer backups e restaurações, e arquivos carregados impactam muito no tamanho;
  • centralizar os arquivos carregados em um serviço de armazenamento lhe permite uma gestão melhor e mais apurada;

Entendido este ponto, se você for ter muitos arquivos carregados na sua aplicação, é hora de procurar uma solução melhor para armazená-los. Dependendo do tipo de conteúdo, periodicidade de acesso, necessidades específicas de busca, etc existem diversas soluções que podem ser usadas.

Arquivos simples de baixa criticidade, em aplicações pequenas? Que tal o Google Drive (tutorial aqui)!

Arquivos em grande quantidade mas com baixa frequência de acesso (como backups e “arquivo morto”)? Que tal o AWS Glacier?

Documentos e outros arquivos de cadastro com informações que precisam ser auditadas, consultadas, preocupação com LGPD, etc? Procure por ECMs (Enterprise Content Management) como o Alfresco.

Para os demais cenários, eu recomendo o AWS S3 (sigla para Simples Storage Service).

O S3 é um disco virtual, que a Amazon chama de bucket (balde), onde você cria e faz a gestão de diretórios e arquivos de qualquer tipo. Ele pode ser de acesso público ou privado, pode estar “atrás” de CDNs (como o AWS CloudFront) para baixar a latência de acesso, pode ser integrado com soluções Serverless, pode disparar eventos na fila da Amazon (o SQS) e muito mais.

Ou seja, ele é muito mais do que uma pasta ‘uploads’ no servidor da sua aplicação seria, e tudo isso por um preço bem baixo, baseado em centavos de dólar por GB de armazenamento e mais alguns centavos de dólar por GB de download cada vez que um arquivo é requisitado.

Você vai ver neste tutorial:

  1. Setup do Bucket
  2. Setup do Projeto
  3. Upload no S3

Vamos lá!

#1 – Setup do Bucket

O primeiro passo obviamente é você ter uma conta na AWS, se autenticar no seu painel e ir na área de credenciais de segurança, que ficam dentro da sua conta de usuário (o menu com o seu nome no topo).

Uma vez dentro da área de credenciais de segurança, crie chaves de acesso (caso ainda não possua), lembrando que você pode ter até duas chaves apenas e que a Amazon não fornece backup, então guarde-as em um lugar seguro.

As chaves são compostas de um Access Key e de um Access Secret, sendo este último o mais “sensível” e que não deve ser compartilhado com ninguém. Usaremos estas informações mais tarde.

Agora vá no menu de Serviços na sua conta da AWS e procure por S3, para acessar a tela de listagem de buckets, como abaixo. Clique na opção Criar bucket em laranja.

Abrirá uma tela de configuração do bucket, onde inicialmente você tem de dar um nome ao mesmo, a região onde ele será criado (crie próximo do seu servidor de aplicação) e permissões de acesso, que geralmente o recomendado é que seja privado, a menos que esteja criando um servidor de arquivos público.

Se estiver lidando com arquivos de conteúdo sensível, você pode habilitar a opção de criptografia dos dados do disco e até do versionamento do mesmo, caso precise voltar em algum ponto do tempo. Note que essas opções consumirão mais espaço e consequentemente sua conta ficará maior no final do mês.

Você será direcionado para a tela de listagem de buckets novamente e clicando no nome do seu bucket você irá para uma área onde pode mudar as configurações realizadas mas, principalmente, gerenciar os arquivos de seu bucket: pode criar e excluir pastas, fazer upload e download de arquivos, etc.

Importante salientar que a exclusão de pastas ou até mesmo do próprio bucket, só podem ser feitos quando os arquivos dentro da pasta ou do bucket tiverem sido todos excluídos. Este é um mecanismo de segurança contra exclusão acidental de pastas e do bucket em si.

Curso Node.js e MongoDB
Curso Node.js e MongoDB

#2 – Setup do Projeto

Aqui vou considerar que você já tem uma aplicação web em Express funcionando e que ela já faz upload de arquivos para o servidor. Você deve ter um código parecido com este aqui, onde um arquivo é recebido via POST e salvo no servidor.

Caso não entenda nada do código acima, recomendo realizar primeiro o tutorial de upload de arquivos. Caso entenda mas não tenha o projeto acima, você pode fazer o download através do formulário ao final deste tutorial ou simplesmente adaptar os códigos a seguir.

Em seu projeto Node.js e instale nele duas dependências, o AWS SDK e o dotenv.

O AWS SDK é a biblioteca de componentes prontos para usarmos os recursos da AWS em Node.js. Já o dotenv é um popular pacote para fazer gestão de variáveis de ambiente e configurações da sua aplicação.

Como o AWS SDK exige uma série de configurações de ambiente para funcionar adequadamente, usaremos o dotenv para fazer isto.

Agora, crie um arquivo criar arquivo .env na raiz do seu projeto, com o seguinte conteúdo.

Lembra das credenciais de acesso que criamos no início do tutorial? Pois é, precisaremos delas aqui, coloque o access key e o access secret neste arquivo, nos referidos campos.

O AWS_REGION você também determinou quando criou o bucket, mas aqui deve ir somente a sigla dele. Você consegue bem fácil na sua conta, é só ver a região que está listada no topo da sua conta e usar a sigla dela na configuração do .env, será algo como us-east-1.

O nome do bucket em si também foi definido na criação e você não deve ter dificuldades em achar.

#3 – Upload no S3

Agora que temos a infraestrutura e o projeto criados e configurados, é hora de construirmos o código que enviará os arquivos do nosso servidor para o bucket no S3.

Crie um arquivo s3Client.js na raiz do seu projeto e inclua o código abaixo dentro dele, que comentarei a seguir.

A primeira linha é apenas um require para carregar o AWS SDK que instalamos antes e o fs, para podermos ler o arquivo do nosso servidor que queremos enviar para a Amazon.

Abaixo, temos duas funções, a primeira que é a que faz o upload para o S3, e que vou explicar melhor abaixo, e uma segunda que deixei de brinde, que é para pesquisar pastas e arquivos no seu S3.

No uploadFile, que é o nosso foco aqui, nas primeiras linhas eu instancio um objeto S3 com uma classe do pacote AWS-SDK e leio os bytes do arquivo que vou enviar para a nuvem da Amazon.

A seguir, configuro os parâmetros deste meu envio: o nome do bucket (que estou pegando do dotenv), o nome de destino do arquivo (key) e o conteúdo em bytes do mesmo (body). Opcionalmente eu posso passar o Content-Type/Mime-Type do arquivo, caso seja de algum tipo que a AWS não reconheça sozinha. Se ela não reconhecer, você sempre terá de fazer download do arquivo quando tentar acessar o mesmo, já se ela reconhecer como vídeo, por exemplo, poderá assistir o vídeo no navegador.

Note que chamei uma função .promise() ao fim do upload. Isso porque, por padrão, o upload espera um callback e se quisermos trabalhar com Promises, precisamos desta última chamada que adicionei. Também note que estou retornando apenas a propriedade Location do do data, que é a URL do seu arquivo no S3.

Após exportar nossa função no s3Client.js, vamos voltar ao código em que fazemos upload para o servidor da aplicação e vamos alterar o código para que, uma vez que o arquivo chegue no servidor, a gente envie ele para a AWS usando nosso s3Client.

Aqui, modifiquei o callback da função parse do Formidable para que envie o arquivo que acabamos de fazer upload para o S3, usando nosso client. Atenção ao fato de que files é o objeto do Formidable que traz os arquivos submetidos no formulário e filetoupload é o name do campo file do meu HTML, contendo as propriedades name (nome original do arquivo) e path (caminho do arquivo já no meu servidor).

Utilizei de Async/Await para que a legibilidade fique mais simples e pego a URL retornada e imprimo na tela da aplicação.

Antes de testar nossa aplicação, você deve carregar as variáveis de ambiente, o que pode ser feita no código mas eu cada vez mais tenho preferido colocar no próprio comando de inicialização mesmo, como abaixo (package.json).

Agora suba a sua aplicação com npm start e teste o upload que deve aparecer lá no seu painel do S3, na Amazon.

Se você tiver um erro do tipo “AccessDenied: Access Denied” quer dizer que as suas credenciais no dotenv estão erradas, inválidas ou que escreveu o nome das variáveis erroneamente. Nos dois primeiros casos, recomendo que volte ao passo inicial de setup aqui do tutorial e na área de credenciais, exclua as existentes e recrie.

Já se escreveu erroneamente o nome das variáveis de ambiente no arquivo .env, apenas refaça esta etapa aqui no tutorial. Elas são carregadas automaticamente e por causa disso precisam estar 100% iguais ao que manda a documentação da AWS, que é o que apresentei mais cedo.

Que tal um upload de arquivos para o S3 disparar uma função serverless/Lambda na AWS?

Além disso, caso você trabalhe forte o conceito de testes unitários, pode ser útil aprender a mockar as APIs da AWS em seus testes.

Deixa aí nos comentários!

Quer ver na prática como utilizar o S3 (e vários outros serviços da AWS) para, por exemplo, hospedar aplicações em ReactJS? Conheça meu curso clicando no banner abaixo!

Curso FullStack
Curso FullStack

Como fazer upload de arquivos em Node.js

Formulário de Upload

Atualizado em 09/04/2021!

Eventualmente alguém me pergunta como fazer upload de arquivos em Node.js. Como é um assunto que já está na minha pauta há algum tempo, resolvi fazer este tutorial pra ajudar o pessoal. Você vai ver que não é algo muito difícil e este tutorial vai ser bem curto.

Parto do princípio aqui que você já sabe o básico de Node.js, JavaScript e de HTML, conhecimentos estes que podem ser obtidos em outros artigos aqui do blog, em meu livro, em meu curso ou até mesmo no meu canal do Youtube.

Vamos começar instalando o express-generator, pacote que nos ajuda a criar aplicações web com ExpressJS, o mais famoso web framework para Node.js (você vai precisar de permissão de administrador no terminal de linha de comando):

Agora mande criar um novo projeto Express usando o comando abaixo, onde chamo o projeto de fileupload:

Após entrar na pasta e instalar as dependências com npm install, instale a dependência formidable, que utilizaremos para lidar com o upload de arquivos em Node.js, dentre tantas alternativas existentes na Internet.

Agora vá na pasta views e abra o arquivo index.ejs para editarmos o HTML do projeto, deixando-o como abaixo:

Note que não tem nada demais aqui, apenas um formulário com um campo de upload de arquivo, mas repare que o formulário possui o enctype como multipart/form-data, isso é muito importante para que upload funcione!

Se você executar esta aplicação com npm start verá algo como abaixo:

Formulário de Upload
Formulário de Upload

Agora vamos programar o comportamento desta página. Fazemos isso indo na pasta routes e abrindo o arquivo index.js, onde temos as rotas da tela inicial.

Adicione a nova rota abaixo dentro deste arquivo:

O que fazemos aqui?

Carregamos a extensão formidable que instalamos há pouco, recebemos o form POSTado pelo usuário e salvamos o arquivo através da função form.parse. Se você testar agora já deve estar funcionando.

File Uploaded
File Uploaded

Mas…onde que o arquivo foi salvo?

Por padrão ele fica salvo em uma pasta temporária no seu computador. Para mudar isso, vamos modificar nosso código anterior para que usando a biblioteca fs (file system) do Node possamos mover o arquivo que fizemos upload para a mesma pasta do seu projeto:

Note que carreguei o módulo fs lá no início do código e que depois uso este módulo para mover o arquivo de lugar no sistema operacional usando a função renameSync (que dispensa o uso de callbacks e promises). Para definir ONDE é este lugar de destino, usei o path.join para montar um caminho contendo o __dirname (pasta atual deste módulo), voltar uma pasta (..) e com isso chegar na raiz do projeto.

Já o arquivo que fiz upload é facilmente encontrado usando o argumento files, que é o terceiro da função form.parse.

O resultado na tela é esse:

File Moved
File Moved

Mas no seu computador o arquivo que você fez o upload estará disponível na pasta raiz do seu projeto.

Fácil, não é?!

Curso FullStack

Bônus: Mais uma opção

Agora caso tenha problemas com o formidable (eu nunca tive), você pode usar a dependência Multer:

E uma forma de utilizá-lo é essa:

Você pode usar o código acima reaproveitando a mesma view do exemplo anterior e o arquivo será salvo com nome aleatório na pasta uploads, na raiz do seu projeto.

Além disso, convém você não deixar os seus arquivos no mesmo servidor da aplicação. Para upload para serviços de armazenamento em nuvem, recomendo o AWS S3.

Espero ter ajudado!

Curtiu este tutorial? Conheça o meu curso online de Node.js e MongoDB para fazer aplicações web e APIs incríveis com esta fantástica plataforma. Basta clicar no banner abaixo!

Curso Node.js e MongoDB

Tutorial CRUD em Node.js com driver nativo do MongoDB – Parte 3

Lista de Clientes com Bootstrap

Atualizado em 01/04/2021!

O tutorial de hoje é uma continuação de uma série bastante acessada aqui no blog, onde ensino como fazer um sistema de cadastro bem simples em Node.js, usando o web framework ExpressJS e o banco de dados não-relacional MongoDB. Ou seja, o famoso CRUD.

Nesta terceira e última parte, introduzo um conceito importante de construção de interfaces que é a modularização da página através do recurso de partial views do EJS (view-engine que estamos usando com ExpressJS) e ensino como dar um “tapa” no visual usando o framework front-end Bootstrap, muito utilizado mundialmente para estruturar aplicações web responsivas e elegantes.

Para conseguir acompanhar todos os códigos, é importante que você tenha realizado a parte anterior ou pelo menos baixe os códigos-fonte que se encontram no formulário ao final do tutorial anterior (parte 2). Caso prefira assistir um vídeo, a primeira parte dessa séria pode ser resumida com este vídeo abaixo que é uma aula gratuita do meu curso de Node.js e MongoDB.

Aproveite!

O conteúdo do post é:

Vamos lá!

Atenção, uma versão ainda mais completa deste tutorial está disponível em videoaula em meu curso de Node.js e MongoDB.

Curso FullStack

O que são Partial Views?

É muito comum quando estamos construindo aplicações web que certas porções de nossas views (telas) acabem se repetindo. Por causa disso, todas as linguagens de programação para web possuem recursos de partial views, ou seja, de modularização da interface a partir de “partes” da tela que são construídas separadas e depois são montadas em conjunto para que o usuário veja apenas o resultado final, completo.

Fazendo uma analogia com o que fazemos no código backend do Node.js, uma partial view é como se fosse um módulo NPM, que depois usamos o require para carregá-lo em nosso código. Em outras plataformas isso é chamado de import, include, using, etc.

Nossa aplicação é bem simples, possui apenas três views: index, new e error, conforme você vê na imagem abaixo.

Estrutura do projeto
Estrutura do projeto
Essas views por sua vez também são mega simples, logo, não há uma reeeaaal necessidade de usar partial views aqui, usaremos mais a título de conhecimento. No entanto, esse conceito é muito poderoso e além de tornar seu código de front-end mais elegante e fácil de ler, ele torna a programação de novas páginas muito mais produtiva, pois sempre aproveitaremos elementos genéricos da interface que serão criados apenas uma vez.

Se olharmos agora para as views index e new, você deve notar que existem muitas tags em comum no início e no fim delas. É por aí que vamos começar a melhorar.

Estrutura que se repete
Estrutura que se repete

Partial views com EJS

Não é de hoje que eu uso EJS (Embedded JavaScript) em meus tutoriais e neste não será diferente. Apesar de não ser a view-engine (motor de visualização) padrão do ExpressJS (esse título é do PUG/Jade), ele é meu favorito pois a curva de aprendizado é ridiculamente baixa, considerando que usa HTML + JS, coisa que todo dev web está careca de saber.

Como não poderia deixar de ser, o EJS possui a funcionalidade de criar partial views (lembro dos meus tempos de ASP.NET em que chamávamos isso de MasterPages e WebUserControls…). Isso é bem fácil de fazer, comece criando um arquivo top.ejs (top=topo) na sua pasta views e nele vamos colocar toda a parte comum que teremos no topo de todas páginas do nosso sistema, que é apenas o HTML abaixo por enquanto:

Note que nesta top.ejs estamos usando algumas variáveis JS que devem vir do backend, através do model passado na função render do Node.js, lembra?

Agora vamos criar mais um arquivo novo, o bottom.ejs (bottom=rodapé), também na pasta views e nele vamos colocar toda a parte comum que teremos no rodapé de todas páginas do nosso sistema, que é apenas o HTML abaixo por enquanto:

E agora, como fazemos para as demais views do projeto usarem essas partial views para compor a sua estrutura?

Bem simples, vamos começar pela index.ejs, remova a parte do topo do arquivo que é repetida ao arquivo top.ejs e no lugar desse pedaço, deixe como abaixo, usando o comando ‘include’ para “incluir” a partial view na primeira linha do arquivo:

Note que já incluí também o include para o bottom.ejs no final do arquivo. Na hora que o arquivo HTML vai ser construído para ser enviado ao browser para renderização, o EJS vai ler essa linha e entender que parte desse HTML está em outro arquivo. Ele vai ir nesse outro arquivo, copiar o conteúdo de lá e colar bem nesse local.

Assim, com esses dois includes, nós mantemos nossa aplicação modularizada em três pedaços: topo, centro e rodapé, facilitando manutenção e aumentando o reuso de código.

Sim, reuso de código, pois agora nas páginas new.ejs e error.ejs nós podemos fazer os mesmos includes para não ter de repetir aqueles blocos iniciais e finais de HTML. Os ganhos agora são pequenos, mas no futuro, são enormes pois facilitam muito a evolução e manutenção do sistema web.

Eu não vou colocar aqui o código dos outros dois arquivos ejs com os includes, embora você possa baixar o projeto completo no final desse artigo deixando seu e-mail.

Depois de fazer estas alterações, coloque sua aplicação Node para rodar (não esqueça de subir o banco MongoDB também) e você vai ver que nada mudou para o usuário, que a tela continua renderizando do mesmo jeito e que as alterações só servem para ajudar o programador a trabalhar melhor mesmo.

Um dos grandes ganhos desta abordagem vem agora: manutenção. Vamos adicionar o framework front-end Bootstrap nessa aplicação pra dar um “tapa” no visual dela e vamos fazer isso de maneira muito fácil porque já deixamos a aplicação preparada para este tipo de alteração.

Adicionando o Bootstrap

Eu não vou me prolongar muito na teoria do Bootstrap por aqui pois falo bastante disso no meu livro Programação Web com Node.js. Inclusive aquele “B” na capa é o símbolo do Bootstrap (os outros símbolos são o JavaScript, o HTML5 e o MongoDB).

Basicamente o Bootstrap é um framework front-end muito popular no mundo inteiro, fornecendo uma estrutura e comportamentos padronizados que muitos devs web sabem como mexer, acelerando o desenvolvimento e manutenção de qualquer sistema que use Bootstrap como padrão para front-end.

É como se os sites tivessem a mesma estrutura básica, entende?

Apesar da estrutura básica ser a mesma, a aparência pode variar enormemente através da customização de arquivos de estilo (CSS).

A aplicação do Bootstrap em um projeto web se dá através de seus arquivos de CSS e de seus arquivos de JavaScript.

Vamos começar adicionando as duas dependências do Bootstrap (obtidas no site oficial), sendo que a primeira, de CSS, deve ser adicionada no topo do nosso arquivo top.ejs, substituindo a chamada original de CSS que estava lá:

Como adicionamos esta linha no top.ejs, TODAS as páginas que incluem essa partial-view vão estar agora com o CSS do Bootstrap. Isso é produtividade na programação!

Note que também adicionei duas meta-tags, conforme sugerido na página do Bootstrap, para garantir máxima compatibilidade com os recursos do framework, como a responsividade em dispositivos móveis.

Agora, vamos adicionar o script JS necessários pro Bootstrap funcionar corretamente no arquivo bottom.ejs. Ele deve ser adicionado logo antes da tag de fecha-body:

Só o fato de termos feito essas adições já vão gerar alguns efeitos visuais na nossa aplicação, como pode ver na imagem abaixo:

Mas para despertar todo o “poder embelezador” do Bootstrap em nossa aplicação nós temos de fazer alguns ajustes na nossa estrutura, bem como usar algumas classes CSS definidas pelo Bootstrap.

Assim, vamos começar definindo uma “div class container” que vai englobar todo o conteúdo do body das páginas. Para fazer isso, basta adicionar o conjunto de tags div abaixo, com a abre-div no top.ejs e a fecha-div no bottom.ejs, de modo que ambas fiquem dentro do body.

Note que só mudou uma linha, logo acima do H1, bem no final do top.ejs. Já no bottom.ejs, também só vai mudar uma linha, que fica bem no início do arquivo:

Após essa adição, teremos mais um ajuste perceptível nas páginas já existentes, que ficarão com uma margem e mais centralizadas. A div container faz a sua página funcionar em um grid-system de 12 colunas virtuais, ou seja, o Bootstrap permite que você organize o conteúdo das suas páginas em 12 blocos de tamanhos iguais, como em um Lego. Desde que você siga esta regra cuidadosamente, a sua aplicação web será responsiva, alterando a sua largura conforme a tela do aparelho que estiver acessando a mesma.

E isso é só o início!

Customizando a aparência

Eu poderia ficar aqui durante muitas e muitas horas escrevendo sobre Bootstrap, então vou ser breve. Vamos apenas dar uma embelezada na página para te mostrar o poder do framework e depois vamos encerrar o tutorial. Fica a seu critério depois se aprofundar, seja em meu livro ou na documentação oficial.

Uma vez adicionado a div container, que é o principal bloco da sua página, vamos personalizar os botões, ou os elementos que queremos que se pareçam com botões. Para isso, basta usarmos duas classes em cada elemento “btn btn-primary” para os botões principais e apenas “btn” para os secundários.

Cada âncora ou submit/button deve ficar parecida com o HTML abaixo:

O botão primário é azul no Bootstrap, mas isso obviamente você pode alterar sobrescrevendo ou editando o CSS original do Bootstrap, ou ainda através de templates que você pega na Internet. As classes CSS de botão também já adicionam um efeito de sombra ao passar o mouse por cima deles, o chamado “hover”.

Para “fechar” a tela inicial, vamos customizar a tabela além do botão, para ela ficar bem bacanuda. Para isso, além de usar o padrão HTML5 para tabelas (com thead, tbody, etc), vamos adicionar uma série de classes a saber:

  • table: classe padrão Bootstrap para tabelas;
  • table-bordered: com linhas nas bordas;
  • table-striped: com linhas “zebradas”;
  • table-hover: com sombra quando passa o mouse;
  • table-dark (no cabeçalho): pro cabeçalho ficar escuro;

O código final que lista os clientes cadastrados pode ser visto abaixo, e substitui a lista antiga:

Fechando de vez esta tela, atualize o código de paginação para ele ficar estilizado conforme recomendado pelo Bootstrap:

Com estas alterações, nossa tela inicial ficará muito melhor do que anteriormente, como mostra a imagem abaixo (coloquei btn-danger ao invés de btn-primary nos botões de exclusão):

Lista de Clientes com Bootstrap

Agora a segunda tela, de cadastro de cliente (new.ejs). Além de ajustarmos os botões com as classes que mencionei antes, vamos ajustar o form HTML conforme instruções do próprio Bootstrap:

O resultado, você confere na imagem abaixo (os tamanhos são ajustáveis, mas por padrão ele é responsivo):

Cadastro com Bootstrap

E com isso encerramos o tutorial de hoje e acredito que esta série sobre o CRUD com driver nativo do MongoDB. Qualquer dúvida que você tiver, deixe aí nos comentários que terei o maior prazer em responder.

Interessado em mais conteúdos sobre Node.js e MongoDB, clique no banner abaixo e conheça o meu curso em videoaulas sobre o assunto!

Curso Node.js e MongoDB
Curso Node.js e MongoDB

Tutorial CRUD em Node.js com driver nativo do MongoDB – Parte 2

Lista de Clientes com Bootstrap

Atualizado em 31/03/2021!

O tutorial de hoje é uma continuação de um outro tutorial aqui do blog, muito acessado aliás, onde ensino como fazer um sistema de cadastro bem simples em Node.js, usando o web framework ExpressJS e o banco de dados MongoDB. Ou seja, o famoso CRUD.

Nesta segunda parte, parto para um conceitos mais avançados em cima do mesmo projeto: paginação de resultados.

Para conseguir acompanhar todos os códigos, é importante que você tenha realizado a parte anterior ou pelo menos baixe os códigos-fonte que se encontram no formulário ao final do tutorial anterior. Caso prefira assistir um vídeo, o tutorial anterior pode ser resumido com este vídeo abaixo que é uma aula gratuita do meu curso de Node.js e MongoDB. Aproveite!

Neste tutorial você vai ver:

Vamos lá!

Atenção, este mesmo tutorial está disponível em videoaula em meu curso de Node.js e MongoDB.

Paginação com Node.js e MongoDB

Nossa aplicação simplesmente lista todos os documentos da nossa coleção no MongoDB, sem qualquer distinção. Nas primeiras duas etapas deste tutorial vamos restringir isso, primeiramente através de uma paginação de resultados e depois através de uma busca.

Conforme trato em detalhes no artigo Tutorial MongoDB para iniciantes em NoSQL: Parte 2, fazemos paginação no MongoDB usando as funções skip e limit de maneira apropriada.

A função skip indica ao MongoDB que deve-se ignorar um número x de resultados da consulta na hora de retornar do servidor de banco. Já a função limit diz ao Mongo que ele deve retornar apenas um número limitado de documentos, independente se a busca retornaria mais elementos normalmente. Ambas funções devem ser usadas após um find, como veremos a seguir.

A lógica para criar paginação é bem simples: determine um tamanho de página, por exemplo 10 elementos, descubra o total de elementos que a consulta retornaria, por exemplo 21 elementos, e depois dividida o total pelo tamanho de página, arredondando sempre pra cima. Pronto, você tem a quantidade de páginas para aquela consulta! Neste exemplo de 21 elementos com uma paginação de tamanho 10, serão 3 páginas, sendo que as duas primeiras terão exatamente 10 elementos e a última apenas 1.

Entendeu?

Para determinar o tamanho de página ideal para seu sistema você tem de levar em consideração a performance da sua aplicação e a experiência do seu usuário. Muitas páginas com poucos elementos é fácil do banco retornar, mas ruim pro usuário ficar navegando. Poucas páginas com muitos elementos é o oposto e o segredo está no equilíbrio. Neste exemplo, ficaremos com tamanho 10 mesmo, para fins de teste.

Curso FullStack

Paginação de Resultados em Node.js

Então nosso primeiro passo será modificar uma function já existente no módulo db.js da nossa aplicação para que ela retorne os resultados de maneira paginada, como abaixo.

Note que comecei definindo uma constante com o tamanho das páginas sendo 5. Depois, adicionei um novo parâmetro na função findAll que espera a página que a aplicação deseja apresentar. Este parâmetro eu uso para calcular o skip, ou seja, quantos elementos da consulta eu devo ignorar. Se a página for a primeira, o skip será zero e serão mostrados os primeiros 10 elementos. Se a página for a segunda, o skip será 10 pela fórmula e serão mostrados os elementos das posições 11 a 20 (ordinal, ou 10 a 19 considerando um array zero-based).

Agora vamos modificar onde esta função findAll é chamada: na pasta routes, módulo index.js, que vamos modificar a rota GET padrão em dois pontos.

Primeiro, apenas para adicionar o parâmetro página nela. Note que coloquei o parâmetro no path como sendo opcional (?) e se ele não tiver sido passado na URL, será atribuído como um. Esse truque do || para atribuir um valor default eu ensinei no artigo 15 Dicas de JavaScript, lembra?

Certifique-se de que esta rota seja a última do arquivo index.js, logo antes do module.exports!

Como as rotas são testadas da primeira até a última para ver qual que processará a requisição deixaremos esta pro final para não interferir nas demais avaliações.

Agora execute a aplicação e teste a index passando a página na URL, como abaixo. Note que tive de adicionar muitos customers no banco de dados para podermos ter alguma paginação.

Paginação funcionando via URL
Paginação funcionando via URL

Mas obviamente não faremos nosso usuário ter de mudar parâmetros na URL para acessar as páginas, certo?

Está curtindo o post? Para uma formação ainda mais completa como programador web recomendo meu livro sobre programação web com Node.js clicando no banner abaixo!

Paginação de resultados com ExpressJs e EJS

Para que o usuário saiba quantas páginas existem e para que consiga acessar as mesmas, vamos ter de criar uma lógica para construir o HTML de paginação no frontend e uma lógica para retornar algumas informações importantes no backend.

Vamos começar pelo backend que é mais a minha praia. XD

Abra seu arquivo db.js novamente e vamos criar uma function countAll que retorna a quantidade de documentos na coleção customers. Note que atualizei o module.exports com a nova função e também exportando a constante com o tamanho de página.

Agora na routes/index.js, mais especificamente no nosso GET default (a última rota do arquivo), vamos ajustar as chamadas para construir o model com as informações que precisaremos no frontend EJS:

Note que recebo a quantidade de clientes na base através de um await novamente (pois a função countAll é assíncrona, tenho de usar await para esperar seu retorno). A cereja do bolo fica para o cálculo de quantidade de páginas que fizemos ali, dividindo o total de documentos pelo tamanho da página, usando a constante existente no módulo db.js. Ah sim, você não esqueceu de expor esta constante no module.exports, certo?

Agora que nosso model está completo, vamos mexer na index.ejs, nossa view inicial da aplicação para renderizar a quantidade total de elementos e o HTML de paginação para que o usuário possa navegar entre as páginas:

Esse código eu coloquei bem no final do arquivo EJS, onde antes ficava apenas o botão de Cadastrar novo cliente. Se você fez tudo certo até aqui, quando testar novamente você deve ver o seguinte resultado na interface da listagem:

Paginação funcionando
Paginação funcionando

Melhorando usabilidade da paginação

Para encerrar este tutorial, vamos adicionar uma perfumaria para melhorar ainda mais a usabilidade desta página: a página atual não deve ter link, apenas as demais páginas, assim, o usuário saberá em que página ele se encontra atualmente.

Vamos iniciar ajustando o model retornado no nosso index.js para informar também a página atual solicitada pelo usuário:

Note que a mudança foi bem sutil, apenas uma nova propriedade no JSON ‘pagina’.

Para fazer a lógica necessário para que o HTML ora tenha link, ora não tenha, basta adicionar um if na lógica de construção do nosso EJS usando a informação da página oriunda do model:

Ou seja, se a variável de iteração ‘i’ for diferente da página atual, escreve um link HTML na tela, caso contrário, escreve apenas o número da página. Visualmente falando temos a imagem abaixo como referência:

Indicando a página atual
Indicando a página atual

Note como ficou evidente que estamos na página 2, pois não tem link pra ela!

Outras melhorias poderiam incluir legendas quando se passa o mouse sobre as páginas, links de próxima página e página anterior, lógica para quando tivermos muitas páginas (e se tiver 100 páginas, como ficará a tela?) e até mesmo informação textual de que você está vendo os itens x a y da página z.

Mas…isso fica para você pensar meu amigo ou minha amiga! 🙂

No próximo post desta série, você confere como modularizar melhor as suas páginas EJS e como estilizar tudo com Bootstrap. Confira neste link!

Gostou do tutorial? Quer aprender ainda mais sobre Node.js, ExpressJS, EJS e MongoDB comigo? Conheça meu curso de Nodejs e MongoDB clicando no banner abaixo!

Curso Node.js e MongoDB
Curso Node.js e MongoDB