Objetivo da Aula
Ao concluir esta aula, você será capaz de:
Calcular RICE score para priorizar user stories com múltiplos critérios
Implementar decomposição automática de user story em tasks técnicas via LLM
Usar LLM para identificar ambiguidades em requisitos antes de estimar
Completar os 2 TODOs do starter: calcularRICE e decomporEmTasks
Aplicar o framework RICE em situações onde critérios são incompletos
Por que isso importa
PMs e tech leads gastam horas discutindo priorização sem critérios objetivos. RICE (Reach, Impact, Confidence, Effort) transforma opiniões subjetivas em números comparáveis — e LLMs podem preencher gaps quando o PM não tem dados precisos.
Decomposição de user story em tasks é onde estimativas erram: “Adicionar login com Google” parece 1 sprint mas esconde 8 tasks (OAuth config, callback handler, session, testes, mobile, error states, etc.). LLMs que conhecem o stack identificam essas tasks ocultas.
Conceitos Fundamentais
Fundamento: Frameworks de PM para Arquitetos
RICE prioriza por Reach (quantos usuários impacta) × Impact (intensidade) × Confidence (certeza) / Effort (esforço). WSJF (SAFe) adiciona urgência temporal: Cost of Delay / Duration — uma feature que perde valor rápido tem prioridade maior mesmo com RICE similar. MoSCoW classifica por Must/Should/Could/Won't — define o escopo mínimo viável. O cone de incerteza formaliza que estimativas iniciais podem errar por fator de 4× para cima ou para baixo — o único jeito de reduzir o cone é dividir em entregas menores e aprender com cada uma. Estimativa como distribuição de probabilidade (intervalo de confiança) é mais honesta que número único: "2 a 4 sprints com 80% de confiança" comunica melhor risco do que "3 sprints".
Framework RICE
RICE = (Reach × Impact × Confidence) / Effort
- Reach: quantos usuários afeta por mês? (número)
- Impact: o quanto melhora para eles? (0.25=mínimo, 0.5=baixo, 1=médio, 2=alto, 3=massivo)
- Confidence: confiança na estimativa? (0-100%)
- Effort: pessoas×mês para completarRICE mais alto = prioridade mais alta
TODO 1: calcularRICE(historia)
function calcularRICE(historia) {
const { reach, impact, confidence, effort } = historia
if (!reach || !impact || !confidence || !effort) {
return null // dados insuficientes para calcular
}
const rice = (reach * impact * (confidence / 100)) / effort
return {
...historia,
rice_score: Math.round(rice * 10) / 10,
interpretacao: rice > 100 ? 'alta prioridade' : rice > 50 ? 'média prioridade' : 'baixa prioridade',
}
}Exemplos:
calcularRICE({ reach: 1000, impact: 2, confidence: 80, effort: 2 })
// → rice_score: 800 ← alta prioridade
calcularRICE({ reach: 100, impact: 1, confidence: 60, effort: 3 })
// → rice_score: 20 ← baixa prioridadeTODO 2: decomporEmTasks(historia) via LLM
async function decomporEmTasks(historia, client) {
const response = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 600,
system: `Você é um tech lead experiente. Decomponha user stories em tasks técnicas específicas.
Para cada task, estime: nome, descrição, dias_estimados, tipo (backend/frontend/infra/teste/docs).
Retorne JSON: {"tasks": [{...}, ...]}`,
messages: [{
role: 'user',
content: `User Story: ${historia.titulo}\nDescrição: ${historia.descricao || ''}\nStack: ${historia.stack || 'Node.js, React'}`,
}],
})
const texto = response.content[0].text
const i = texto.indexOf('{'), f = texto.lastIndexOf('}') + 1
const parsed = JSON.parse(texto.slice(i, f))
const total_dias = parsed.tasks.reduce((acc, t) => acc + (t.dias_estimados || 1), 0)
return { ...parsed, total_dias, confianca_estimativa: total_dias < 5 ? 'alta' : 'media' }
}Aprofundamento Técnico
Quando RICE Falha
Impact subjetivo: “massivo” para o VP de vendas é “médio” para o time de produto. Calibre Impact com dados históricos: quais features com Impact=2 geraram +X% de engajamento?
Confidence superestimado: Times iniciantes colocam 80-90% em tudo. Use regra: se não fez antes = 50%, se fez uma vez = 70%, se fez muitas vezes = 90%.
Effort subestimado: O LLM identifica tasks esquecidas. Regra de Hofstadter: sempre leva mais tempo do que você espera, mesmo quando você leva em conta a Lei de Hofstadter.
Identificação de Ambiguidades com LLM
async function identificarAmbiguidades(historia, client) {
const response = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 400,
messages: [{
role: 'user',
content: `Analise esta user story e identifique:
1. Ambiguidades que precisam de resposta do PM antes de estimar
2. Casos extremos não cobertos
3. Dependências com outros times/sistemas
User Story: "${historia.titulo}"
Critérios de aceite: ${historia.criterios_aceite?.join('; ') || 'não especificados'}`,
}],
})
return response.content[0].text
}Exemplos Anotados
Exemplo 1: RICE Scoring Completo
const historias = [
{ titulo: 'Login com Google', reach: 5000, impact: 2, confidence: 80, effort: 3 },
{ titulo: 'Dashboard analytics', reach: 200, impact: 3, confidence: 60, effort: 5 },
{ titulo: 'Dark mode', reach: 8000, impact: 0.5, confidence: 95, effort: 1 },
]
const scored = historias.map(calcularRICE).sort((a, b) => b.rice_score - a.rice_score)
// → Dark mode: RICE 3800 (alta prioridade)
// → Login com Google: RICE 2667 (alta prioridade)
// → Dashboard analytics: RICE 72 (média prioridade)Exemplo 2: Decomposição de “Login com Google”
User Story: "Como usuário, quero fazer login com Google para não criar senha"
Tasks geradas pelo LLM:
1. Configurar OAuth 2.0 no Google Cloud Console [infra, 1 dia]
2. Implementar endpoint /auth/google/callback [backend, 2 dias]
3. Criar sessão JWT após autenticação [backend, 1 dia]
4. Componente botão "Continuar com Google" [frontend, 0.5 dia]
5. Tratamento de erro (conta bloqueada, email já cadastrado) [backend, 1 dia]
6. Testes de integração OAuth [teste, 1 dia]
7. Docs de configuração para dev local [docs, 0.5 dia]
Total: 7 dias (estimativa alta confiança: 1.5 sprints)Padrões e Armadilhas
Padrões
Padrão 1: RICE relativo, não absoluto RICE 2667 não significa nada sozinho. Significa “3.7x mais prioritário que Dashboard analytics (RICE 720)”. Compare sempre dentro do mesmo backlog.
Padrão 2: Decomposição com stack explícito
// Inclua o stack para tasks mais específicas
`Stack: Next.js 14, Prisma, PostgreSQL, AWS S3`
// → LLM gera tasks de migração de schema Prisma, não genérico "database migration"Padrão 3: Confidence inversamente proporcional à novidade Feature nova para a empresa = Confidence 50%. Feature similar já feita = 80%.
Armadilhas
⚠️ Armadilha 1: Impact igual para tudo
// Se todas as historias têm Impact=2, RICE não diferencia
// Calibre: "Qual é a feature de maior impacto que já entregamos?" → Impact=3
// Calibre: "Qual teve menos impacto?" → Impact=0.5⚠️ Armadilha 2: LLM decompõe sem conhecer dependências
LLM: "Task: implementar SSO com Okta [2 dias]"
Realidade: Okta não está configurado — precisa de 2 sprints de infra antesSempre revisar com quem conhece o ambiente.
⚠️ Armadilha 3: JSON malformado do LLM
try {
const parsed = JSON.parse(texto.slice(i, f))
return parsed
} catch {
return { tasks: [], erro: 'LLM retornou JSON inválido' }
}Se não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
2 TODOs no starter.js:
TODO 1 — calcularRICE(historia):
function calcularRICE(historia) {
const { reach, impact, confidence, effort } = historia
const rice = (reach * impact * (confidence / 100)) / effort
return { ...historia, rice_score: Math.round(rice * 10) / 10 }
}TODO 2 — decomporEmTasks(historia, client): Use client.messages.create com system prompt instruindo JSON de tasks. Extraia com texto.indexOf('{') e texto.lastIndexOf('}').
Rode com node starter.js e observe as histórias rankeadas por RICE e dekompostas em tasks.
Agora você está pronto para o lab.