Backlog DEEP, Histórias INVEST e Tarefas SMART

Atualizado em 29/12/2019 com os slides e vídeo!

Quem trabalha comigo há algum tempo sabe o quanto eu repito a frase “agile não é bagunça” e quando o assunto é o backlog do time, isso não pode ser menos verdade. Existe uma má interpretação do Manifesto Ágil e da própria cultura Lean-Agile em geral que entende que não se precisa ter documentação em projetos rodando sobre frameworks ágeis.

Pura mentira!

A grande mudança de mindset nos métodos ágeis é criar a documentação estritamente necessária e somente quando for necessária, ao invés de gastar meses escrevendo documentos de Visão do Produto, Especificações Funcionais e Não-Funcionais e por aí vai. Isso não quer dizer, no entanto, que jamais vamos ter este tipo de documentação ou algo próximo à elas, mas que vamos distribuir a sua produção ao longo de várias sprints conforme nosso entendimento for aumentando e a necessidade se torne emergente.

E por que eu falo que agile não é bagunça?

Porque justamente em um ambiente auto-gerenciável e sem metodologias prescritivas é que precisamos do mais alto grau de organização e isso começa com nosso requisitos ágeis. No artigo de hoje falarei sobre três acrônimos bem populares para ajudar na organização dos requisitos ágeis:

É importante ressaltar que estes acrônimos são norteadores para a criação e organização destes artefatos e de que não devem se tornar uma “religião” nem criar fanáticos que impeçam os projetos de prosseguirem apenas porque alguma demanda não atende 100% a todos requisitos do acrônimo. Use-os como guias e não como grilhões.

No final deste artigo você encontra este material em forma de slides e nesse link você vê o vídeo da minha palestra sobre este assunto.

Vamos começar?

Backlog DEEP

DEEP é um acrônimo para Detalhado, Estimado, Emergente e Priorizado e são as características que o Product Owner deve buscar sempre em seu backlog.

Detalhado quer dizer que o backlog deve ter os detalhes suficientes para garantir clareza que propicie execução, mas não detalhado em demasia que gere desperdício. Entenda que a necessidade de profundidade no detalhamento é proporcional à emergência de uso do backlog, ou seja, os itens que vão entrar na próxima sprints (mais emergentes) devem estar melhor detalhados, enquanto que os itens que vão entrar daqui a várias sprints, podem estar bem menos detalhados.

Detalhamento de Backlog
Detalhamento de Backlog

Estimado quer dizer que todo item quando chega a um nível de detalhamento suficiente deve ter uma estimativa de esforço associada a ele, uma vez que o backlog não é apenas uma ferramenta de trabalho, mas e planejamento. Essa estimativa pode ser em horas, em pontos, em t-shirt size, em E/EE/EEE ou o que você possa imaginar e que faça sentido para seu time. Essa estimativa inclusive lhe auxilia a entender se o nível de detalhes está bom o suficiente, pois via de regra itens de backlog com uma estimativa muito alta deveriam ser quebrados em itens menores (a técnica de Planning Poker ou de Nivelamento de Features ajuda nisso).

 

T-Shirt Size
T-Shirt Size

Emergente quer dizer que o backlog evolui conforme o Product Owner vai aprendendo sobre o produto e o mercado vai lhe dando feedback sobre seus lançamentos (seu MVP, por exemplo), ele não é estático. O constante refinamento do backlog permite que o produto reaja bem a mudanças de estratégia e de escopo, ao invés de se apegar a um planejamento waterfall. O segredo aqui é rever todo o backlog a cada ciclo construir-medir-aprender do Lean Startup.

Ciclo do Lean Startup
Ciclo do Lean Startup

Priorizado quer dizer que a ordem em que os elementos estão dispostos no backlog importa. Os itens mais prioritários devem estar ao topo, enquanto que os menos prioritários devem estar mais embaixo. Os critérios e técnicas utilizados para priorização variam muito de Product Owner para Product Owner, de produto para produto e de mercado para mercado. Para o Scrum, não importa qual é a sua técnica, mas sim que o resultado deve gerar valor para os clientes e para a empresa.

WSJF - Técnica de Priorização do SAFe
WSJF – Técnica de Priorização do SAFe

Histórias INVEST

O acrônimo INVEST é um trocadilho para dizer que devemos “investir” tempo na escrita de boas histórias de usuário, tema de outro artigo aqui do blog. INVEST significa Independente, Negociável, Valiosa, Estimável, Small (Pequena) e Testável.

Independente significa que uma boa história de usuário não depende de outras e que outras não dependem dela. Que qualquer história deveria poder ser desenvolvida em qualquer ordem, conforme a prioridade que o Product Owner determinar. Sabemos que isso não é lá muito fácil de se alcançar, mas é sempre bom chegar o mais próximo possível disso.

Negociável significa que toda boa história é uma co-criação, uma negociação entre profissionais de negócio e profissionais técnicos. Uma história deve capturar a essência de um requisito, mas não os seus detalhes, que devem ser criados de forma colaborativa e emergente. Ao longo do tempo, mais detalhes serão adicionados a cada história conforme o produto evolui e os usuários demonstram novos comportamentos. Aqui entram os 3C’s necessários em todas histórias: Card, Conversation e Confirmation.

Valiosa quer dizer que toda história deve agregar valor ao produto e principalmente, ao usuário-chave da mesma. Uma historia jamais deveria agregar valor apenas ao desenvolvedor ou apenas ao negócio, e sim sempre centrada no cliente. O Product Owner sempre se deve perguntar se ele tornará melhor a vida do cliente ao colocar aquela historia em produção. A técnica de Nivelamento de Features pode ajudar a determinar o quão valiosa é cada história.

Estimável é semelhante ao que já falamos no DEEP sobre o backlog. Para entregar um backlog estimado que me permita planejar meu roadmap de produto, é necessário ter histórias estimadas primeiro. E para conseguir estimar as histórias elas precisam ser pequenas e claras, com detalhes suficientes e bom nível de entendimento entre negócio e técnicos. Esta estimativa não precisa ser precisa, mas deve dar noções de grandeza que ajudem na tomada de decisão, priorização, etc.

Small (Pequena) para que seja possível entregá-la em no máximo uma sprint, caso contrário ela será um épico. O grande desafio obviamente é o equilíbrio entre histórias pequenas o suficiente para que seja possível estimar, mas não tão pequenas que não entreguem valor algum para o cliente. Na verdade esse é o desafio de todo o INVEST, conciliar todas as características desejáveis em uma história. Via de regra, uma história não deveria levar mais do que alguns dias de um par de programadores trabalhando nela, se está levando mais de uma semana é uma dica de que deveríamos pensar em quebrá-la.

Testável indica que toda história deve poder ser coberta de testes para validar se seus requisitos funcionais e não-funcionais foram atendidos, geralmente abordados nos critérios de aceitação da história. Uma história que não podemos testar para garantir seu funcionamento não é uma boa história, pois ou não está Independente ou é pequena demais e não entrega valor algum.

Livro para Agile Coaches
Livro para Agile Coaches

Tarefas SMART

E para terminar, o acrônimo SMART é o mais famoso dentro e fora da computação uma vez que é usado para definir muito mais do que tarefas de qualidade, mas boas métricas, bons objetivos e por aí vai. Isso porque SMART é um acrônimo para Specific (Específica), Mensurável, Alcançável, Relevante e Temporal.

Specific (Específica) indica que toda tarefa deve ter uma responsabilidade única, ser coesa com seu objetivo e entregar apenas uma parte de uma história de usuário. Para quem é programador, é o mesmo que aplicar o princípio SRP (Single Responsibility Principle) do SOLID para tarefas. Ser específica ajuda a história ser Alcançável, Mensurável e Temporal, além de garantir o entendimento de todos no time.

Mensurável é uma característica desejável para apoiar o planejamento da sprint. Se eu não tenho como medir uma tarefa, como sei se entregaremos ela a tempo? Aqui não importa a unidade de medida, embora o ágil encoraje muito mais o uso de pontos do que de horas, desde que a unidade faça sentido para todos no time e gere informação valiosa para o time e para a empresa.

Alcançável é um requisito básico para toda tarefa. O time tem que ter as competências e recursos necessários para conseguir entregar a tarefa. Simplesmente não adianta definir como prioridade uma tarefa que ninguém sabe fazer ou que vai levar tanto tempo que ela por si só deveria ser uma história ou épico. Definir tarefas inalcançáveis para o time é o primeiro passo para perder o time, até mesmo por isso que geralmente a atividade de quebra de histórias em tarefas e feitas pelo Dev Team e não pelo PO.

Relevante tem a ver com o valor que esta tarefa agrega ao todo da história. Se a tarefa não agrega em nada, ou seja, é irrelevante para a história, ela não deveria ser feita. Tarefas são quebradas para ajudar os desenvolvedores a organizarem seu trabalho, mas cada uma deveria poder ser explicada em como contribui para a história principal.

Temporal quer dizer que toda tarefa tem um tempo para ser realizada, ela tem de estar delimitada a uma timebox específica, previamente combinada entre os membros do time e utilizada para ajudar na priorização e planejamento da sprint.

Claro, nenhum desses acrônimos é bala de prata e usar todos eles juntos, todos os dias, é um desafio imenso. Mas não desista, é justamente esta busca pela perfeição no trabalho com backlog, histórias e tarefas que cria maturidade em times ágeis.

E você, conhece algum outro acrônimo que eu não citei aqui? Deixe nos comentários!

* OBS: curtiu o post? Então dá uma olhada no meu livro de Scrum e Métodos Ágeis e/ou no meu curso sobre o mesmo assunto!

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

Processamento assíncrono de tarefas com filas no RabbitMQ e Node.js

Um caso de uso de Node.js muito comum, como já expliquei em outros artigos antes, é o de construção de webapis e microsserviços que aguentam grande carga de requisições. Até aqui, isso não deve ser novidade para você.

No entanto, uma fraqueza do Node (e do JavaScript em geral) é a sua performance não tão boa quando o assunto é processamento pesado e/ou tarefas bloqueantes que demoram um tempo razoável para serem concluídas. Isso no Node.js pode ser um grande ofensor uma vez que o event loop trabalha com single thread, certo? Bloqueie esta thread principal e os demais clientes chamando sua API terão uma experiência bem ruim…

Seja nos casos em que o volume de requisições exceda a sua capacidade de resolvê-las rapidamente ou nos casos em que o processamento seja demorado, adotar uma arquitetura que opere de forma assíncrona não apenas garante que você vai conseguir atender todas requisições como vai fazê-lo em um tempo adequado.

No tutorial de hoje vou falar de como construir uma arquitetura simples, porém robusta, usando Node.js e RabbitMQ para processamento assíncrono de requisições recebidas em uma web API RESTful.

Processamento Assíncrono

O primeiro conceito que você tem de entender é que apesar do HTTP ser síncrono, já faz quase 20 anos que a Internet (e os sistemas que rodam nela) já entendeu que trabalhar de maneira assíncrona é uma forma de proporcionar experiências cada vez melhores aos usuários.

Em uma requisição síncrona, a request é enviada ao servidor, que a processa e devolve uma response. Tudo de uma vez só. Enquanto a response não é retornada, a conexão fica presa e o usuário fica esperando. Se demorar demais, a conexão pode ser encerrada abruptamente e o cliente terá de fazê-la de novo, sem saber exatamente o que acontecer nesta segunda chamada.

Em uma requisição assíncrona, a request é enviada ao servidor, que registra a mesma e automaticamente responde ao cliente que vai realizar a tarefa em breve, avisando-o de alguma maneira quando ela for concluída. Um outro processo cuida de processar essa requisição armazenada e notificar o cliente de alguma forma, se necessário.

A imagem abaixo ilustra um pouco dessa diferença.

Sync vs Async
Sync vs Async

Obviamente o segundo modelo é um pouco mais complexo de lidar, mas possui algumas vantagens muito interessantes.

Enquanto que processamento síncrono dá uma resposta mais direta e rápida para o cliente quando o servidor não está sobrecarregado de requisições, é quando a carga de chamadas às suas APIs é muito alta que ele se mostra inviável. Neste caso, apenas registrar as requisições, para processá-las em uma fila, por exemplo, garante que todos vão ser atendidos, cada um no seu tempo e nenhuma request vai ser dropada.

Assim, pensando nessa arquitetura, eu proponho neste tutorial o uso de RabbitMQ, uma tecnologia gratuita e open-source escrita em Erlang para ser usada como fila para as suas requisições, visando processamento assíncrono pelo Node.js.

RabbitMQ

O MQ no nome do Rabbit vem de Message Queue ou Fila de Mensagens, o que é exatamente o que ele é. O RabbitMQ é hoje a tecnologia de fila mais popular do mercado e fornece integração com todas as tecnologias comerciais mais utilizadas, incluindo aí Node.js. Ele é construído com a linguagem funcional Erlang e implementando o protocolo AMQP (Advanced Message Queue Protocol ou Protocolo Avançado de Filas de Mensagens).

Um dos possíveis casos de uso do RabbitMQ é a construção de arquiteturas para processamento assíncrono usando o padrão Producer/Consumer (Produtor/Consumidor), onde de um lado eu vou ter um produtor que envia mensagens pra uma fila (queue) e de outro lado um consumidor que é notificado que uma nova mensagem chegou, para processá-la. Existem arquiteturas mais complexas possíveis de serem feitas, com N para N, mas meu intuito aqui é manter simples neste primeiro momento.

Para efeitos mais práticos e simples, imagine que de um lado eu tenho uma API (producer) que recebe uma grande carga de requisições, ela enfileira essas requisições no Rabbit e um worker (consumer) vai processando essas mensagens uma a uma, conforme ele vai conseguindo dar conta.

A imagem abaixo ilustra uma possibilidade como essa, onde aquele canal no meio é onde fica o RabbitMQ.

Producer/Consumer
Producer/Consumer

Para rodar o RabbitMQ na sua máquina você vai precisar ter o Erlang instalado e depois pode baixar o Rabbit e executá-lo via linha de comando mesmo. A área de downloads dá as melhores instruções para instalação conforme o seu sistema operacional.

Com tudo instalado, eu costumo subir um servidor de filas do Rabbit usando o utilitário rabbitmq-server dentro da pasta sbin, como no comando abaixo (em Windows ajuste o path do cd e você não precisa do ./ no início do comando também)

Quando o servidor sobe corretamente você deve ver algo parecido com a imagem abaixo no seu terminal.

RabbitMQ funcionando
RabbitMQ funcionando

Cliente RabbitMQ em Node.js

O RabbitMQ possui clientes nas mais variadas tecnologias, incluindo Node.js como já mencionei antes. Uma vez com o servidor do RabbitMQ rodando, crie uma nova pasta e rode um npm init para iniciar um novo projeto Node.js nela.

Você tem de instalar as seguintes dependências no seu projeto:

  • express
  • body-parser
  • amqplib

Vamos criar um módulo JavaScript que vai encapsular a nossa lógica de produzir e consumir mensagens, bem como de criar a fila no Rabbit. Esse módulo depois será usado pela webapi e pelo worker (note que uso promises aqui).

Esse módulo é bem simples, possui 4 funções e expõe apenas duas, uma que vai ser usada pelo producer (sendToQueue) e outra pelo consumer (consume).

A primeira função, connect, é autoexplicativa, ela carrega a dependência do pacote amqplib e conecta-se na URL do servidor RabbitMQ, retornando o canal de comunicação. Essa função é usada pelas demais e é a recomendação, abrir sempre o canal de comunicação para garantir que não terá problemas com conexão.

A segunda função createQueue, é chamada pelas outras duas para garantir a existência, mas não se preocupe pois ela é idempotente, ou seja, depois de criada, ela não criará repetida e nem dará erro de que já existe. É mais uma recomendação de boa prática.

A terceira função, sendToQueue, será usada pelo producer (webapi) e na minha implementação ele está esperando um objeto JSON como argumento da função, sendo que ele serializa o mesmo para ser enviado ao Rabbit. Você pode ter várias filas diferentes, então esta função espera como argumento o nome da fila onde você vai adicionar essa mensagem.

E por fim, a função consume, que será usada pelo consumer (worker). Essa função espera um callback que é a função do cliente dessa lib que vai ser disparada toda vez que entrar uma mensagem nova na fila, é a função que vai processar a requisição agendada.

Agora vamos criar o produtor e o consumidor.

Produtor e Consumidor

Nossa API de exemplo será muito simples, uma vez que o objetivo aqui não é ensinar a criar webapis. Apenas copie e cole o código abaixo em um arquivo webapi.js na raiz do projeto:

Essa API espera um POST em um endpoint /task com um JSON no body da requisição. Ela apenas pega esse body e joga pra fila.

Da mesma forma, nosso worker de exemplo será muito simples, uma vez que não é o foco do artigo. Apenas copie e cole o código abaixo em um arquivo worker.js na raiz do projeto:

Esse worker é muito simples, ele apenas fica escutando a fila1 (a mesma em que o producer vai jogar as mensagens) e quando chega alguma coisa lá, o callback pega a mensagem e apenas imprime o conteúdo no console.

Testando e Além

Uma vez que você já tenha o servidor de RabbitMQ rodando, testar é muito simples, basta subir a webapi via terminal e depois subir o worker em outro terminal, em qualquer ordem.

Você deve começar o teste pelo producer, ou seja, abra o POSTMAN e envie um objeto JSON qualquer via POST para localhost:3000/task que isso deve disparar a mensagem pra fila que deve ser consumida pelo worker quase imediatamente.

Claro, este é um consumer meeega simples. Consumers reais vão processar dados da mensagem, fazer operações em banco e até mesmo chamar outras APIs se necessário, principalmente para avisar que essa requisição já foi processada. Você pode querer também alterar a interface para dar uma resposta ao usuário e por aí vai.

Você pode ainda explorar mais possibilidades desta arquitetura como o padrão com múltiplos consumers concorrentes (1xN) ou ainda o padrão Pub-Sub (Publish/Subscribe) onde podemos ter uma relação de NxN.

Mas enfim, a ideia deste artigo era te ajudar a fazer o Rabbit funcionar com Node.js e espero que você tenha conseguido. Caso contrário, apenas baixe os meus fontes usando o formulário ao final do tutorial.

Até a próxima!

Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu curso sobre programação web com Node.js!

Curso Node.js e MongoDB

9 anos de LuizTools

TDC 2019
TDC 2019

Neste dia 19/12/19 o meu blog comemora 9 anos de vida. Ele coincide com o tempo que tenho de graduado em Ciência da Computação, pois foi justamente quando me formei na faculdade que decidi que queria compartilhar o que sabia e o que estava recém aprendendo com outras pessoas.

Quando eu comecei, mexia apenas com C#, basicamente, e minha ideia era apenas compartilhar (e até mesmo arquivar) alguns códigos e projetos que poderiam ser úteis para outros desenvolvedores. As ferramentas do Luiz. No entanto, logo o blog se tornou mais do que isso e passei a estudar outras plataformas e a ensinar o pouco que sabia sobre elas por aqui também.

Hoje, 323 posts depois, o blog que já passou por várias reformulações, tem duas linhas claras de conteúdo: desenvolvimento de software (atualmente em Node.js) e métodos ágeis. Quer você goste de um assunto, ou de outro, semanalmente tem um post novo aqui no blog e minha newsletter chega à caixa de email de mais de 14 mil assinantes (no final desse post tem um formulário para se inscrever).

Vou aproveitar esta oportunidade para compartilhar alguns números com os leitores, bem como os melhores posts aqui do blog, baseados no número de leituras que cada um teve.

Você sabia que…

  • todos os meses, 37 mil leitores visitam o meu blog?
  • que 75% dos meus leitores são homens e que quase metade deles tem entre 25 e 34 anos?
  • que 5% dos meus leitores são de fora do país?
  • que SP, RJ e MG, nessa ordem, são os estados com mais visitantes no meu blog?
  • que 81% dos visitantes usam o Google Chrome para ler meus posts?
  • que 34% dos meus leitores usam um dispositivo móvel para ler meus posts?
  • que menos de 2% do meu tráfego vem das minhas redes sociais, como Facebook, Youtube, LinkedIn e Twitter (me segue aí!)?

Você já leu estes posts aqui? São os que o pessoal mais gosta dentre todos os 323 escritos até o momento:

E você sabia que já lancei diversos livros que surgiram a partir de conteúdos aqui do blog? Vários deles são best-sellers da Amazon e já venderam mais de 6.793 cópias juntos!

Além disso possuo dois cursos online à venda aqui no blog, sobre minhas duas áreas de expertise atualmente, sendo que já possuo mais de 466 alunos somados!

E que venha 2020 e o décimo ano de vida do blog!