Módulo 08 — Modelagem de Requisitos: Casos de Uso e Histórias de Usuário

Onde estamos. No módulo anterior aprendemos a levantar e registrar requisitos: descobrir o que o sistema precisa fazer e sob quais restrições. Agora damos o passo seguinte. Ter uma lista de requisitos é uma coisa; organizá-los de modo que sejam compreensíveis, discutíveis e verificáveis é outra. Aqui você vai aprender duas linguagens para modelar requisitos de comportamento — casos de uso e histórias de usuário — e, tão importante quanto, entender quando cada uma serve melhor.

Deixe-me abrir com uma provocação honesta. Você já viu uma especificação escrita como uma lista interminável de frases começando com “o sistema deve”: cadastrar clientes, validar o CPF, emitir relatórios. Não são erradas, mas têm um problema silencioso: descrevem funções isoladas e perdem o fio da meada. Quem lê não enxerga quem usa o sistema, para quê, nem em que ordem. A modelagem de requisitos existe para devolver esse fio: em vez de funções soltas, ela conta histórias de uso — alguém, com um objetivo, interagindo com o sistema até obter um resultado que lhe interessa. É sobre essas duas maneiras de contar essas histórias que vamos conversar.

O papel da modelagem de requisitos

Um requisito bruto, isolado, é ambíguo — não diz quem o usa, em que contexto, nem o que se espera quando algo dá errado. Modelar é dar forma a esse material para que comunique intenção. Uma boa modelagem serve a três públicos: ao usuário e ao cliente, que reconhecem no modelo o próprio negócio e validam se entendemos corretamente; à equipe de desenvolvimento, que o usa como ponte para o projeto; e à equipe de teste, que precisa saber o que verificar. Guarde essa ideia dos três leitores — ela explica a diferença entre casos de uso e histórias adiante.

Bezerra, ao tratar de análise e projeto orientados a objetos, insiste que a modelagem de requisitos é a fronteira entre o problema e a solução: de um lado, as necessidades reais das pessoas; do outro, o software que construiremos. Se essa tradução falhar, todo o esforço posterior resolverá o problema errado com perfeição técnica — o pior dos desperdícios.

Casos de uso: a anatomia de uma interação

O caso de uso descreve o comportamento do sistema do ponto de vista de quem o utiliza. A ideia, popularizada na UML e discutida em profundidade por Larman, é simples e poderosa: em vez de descrever o que o sistema tem, descrevemos o que alguém consegue fazer com ele. Precisamos de dois conceitos fundamentais.

O primeiro é o ator: qualquer entidade externa ao sistema que interage com ele para atingir um objetivo. Atenção à palavra “externa”: o ator não faz parte do sistema, ele o usa. Pode ser uma pessoa em um papel — cliente, atendente, administrador —, mas também outro sistema ou um dispositivo. E há uma sutileza a reter: o ator é um papel, não uma pessoa concreta. A mesma pessoa pode ser, em momentos diferentes, o ator “atendente” e o “administrador”. Modelamos papéis, porque é o papel que define objetivos e permissões.

O segundo conceito é o caso de uso: uma sequência completa de interações entre um ou mais atores e o sistema, que produz um resultado de valor observável para algum ator. “Sequência completa” significa que ele vai do início ao fim de um objetivo, não é um passo isolado; “valor observável” significa que, ao final, o ator obteve algo que lhe interessava. “Realizar uma venda” é um caso de uso; “clicar no botão salvar” não é — é só um passo dentro de algo maior.

ImportanteO erro mais comum de quem começa

Iniciantes transformam cada tela ou botão em um caso de uso, produzindo dezenas de “casos” minúsculos que não contam história nenhuma. O teste é sempre o mesmo: qual objetivo do ator este caso satisfaz? Se a resposta for “nenhum, é só um passo intermediário”, você não tem um caso de uso, tem um fragmento de outro.

O diagrama de casos de uso

O diagrama de casos de uso é a visão panorâmica: mostra, de uma vez, quais atores existem e quais objetivos cada um pode alcançar. Não descreve como nada acontece — para isso serve a descrição textual —, mas oferece um mapa das fronteiras do sistema. É a primeira coisa que mostro a um cliente, porque ele reconhece os próprios papéis e valida o escopo.

A UML desenha atores como bonecos e casos de uso como elipses dentro de uma caixa que representa a fronteira do sistema. O Mermaid não tem tipo nativo para isso, então usaremos um flowchart: nós retangulares para atores, arredondados para casos de uso, ligações indicando quem participa de quê. Considere a venda em uma pequena loja.

flowchart LR
    Cliente[Cliente]
    Atendente[Atendente]
    Gerente[Gerente]

    UC1(["Realizar venda"])
    UC2(["Consultar produto"])
    UC3(["Aplicar desconto"])
    UC4(["Emitir relatório"])
    UC5(["Cadastrar produto"])

    Cliente --- UC2
    Atendente --- UC1
    Atendente --- UC2
    Atendente --- UC3
    Gerente --- UC4
    Gerente --- UC5
    Gerente --- UC3

    style Cliente fill:#cfe2ff,stroke:#084298
    style Atendente fill:#cfe2ff,stroke:#084298
    style Gerente fill:#cfe2ff,stroke:#084298
    style UC1 fill:#d1e7dd,stroke:#0f5132
    style UC2 fill:#d1e7dd,stroke:#0f5132
    style UC3 fill:#fff3cd,stroke:#664d03
    style UC4 fill:#d1e7dd,stroke:#0f5132
    style UC5 fill:#d1e7dd,stroke:#0f5132

Veja o que esse mapa comunica sem esforço: o cliente só consulta produtos; o atendente vende e aplica descontos no balcão; o gerente administra e também aplica descontos. “Aplicar desconto” é compartilhado por dois atores — pista de um comportamento reutilizável, exatamente o tipo de relação de que falaremos agora.

Fluxo principal, fluxos alternativos e exceções

O diagrama mostra que casos de uso existem; a riqueza está em descrever como cada um transcorre. E aqui aparece o conceito que separa o modelo ingênuo do maduro: raramente uma interação segue um único caminho. Todo caso de uso tem um fluxo principal, ou cenário de sucesso, que é a sequência ideal — tudo dá certo, o ator faz o esperado e obtém o resultado. Mas a realidade tem desvios, e por isso descrevemos também os fluxos alternativos e as exceções.

Um fluxo alternativo é um caminho válido diferente do principal: o cliente paga com cartão em vez de dinheiro — não é erro, é variação legítima que também leva ao sucesso. Já uma exceção é um desvio provocado por condição de erro: o pagamento é recusado, o produto não tem estoque, a conexão cai. Larman ressalta que a maior parte da complexidade real — e dos defeitos — mora nesses fluxos que não são o caminho feliz. Quem só modela o fluxo principal descreve o sistema fácil de construir e ignora o difícil de operar.

DicaOnde estão os requisitos escondidos

Ao terminar o fluxo principal, faça a pergunta incômoda em cada passo: “e se isto falhar?”. Cada resposta é um fluxo de exceção que, se não for modelado agora, virá cobrar seu preço como defeito em produção. Modelar exceções é o antídoto barato para o retrabalho caro.

As relações entre casos de uso: inclusão, extensão e generalização

Ao modelar vários casos de uso, percebemos que alguns comportamentos se repetem ou se relacionam. A UML oferece três relações, e não confundi-las importa, porque cada uma comunica uma intenção diferente.

A inclusão («include») representa um comportamento sempre executado como parte de outro. É a fatoração de um trecho comum: se “Realizar venda” e “Devolver produto” ambos precisam “Validar cliente”, extraímos esse caso como incluído por ambos. É obrigatória e incondicional.

A extensão («extend») representa um comportamento opcional, acionado sob certa condição, acoplado a um ponto do caso base. “Aplicar cupom” pode estender “Realizar venda”, mas só se o cliente apresentar um cupom. A diferença: inclusão é “sempre acontece”; extensão é “às vezes, sob condição”.

A generalização aplica-se a atores e a casos de uso e expressa “é um tipo de”. Um ator “Gerente” pode ser generalização de “Atendente”, herdando seus objetivos e acrescentando os próprios. Entre casos, “Pagar com cartão” e “Pagar com dinheiro” podem especializar um “Efetuar pagamento” genérico.

A tabela a seguir consolida as três relações, porque a confusão entre elas é uma das falhas mais frequentes em modelos de casos de uso.

Relação Notação Intenção Condicional?
Inclusão «include» Fatorar comportamento comum e obrigatório Não, sempre executa
Extensão «extend» Acoplar comportamento opcional em um ponto Sim, sob condição
Generalização Seta de herança Expressar “é um tipo de” entre atores ou casos Não se aplica

A descrição textual estruturada de um caso de uso

O diagrama é o índice; a descrição textual é o conteúdo, onde registramos passo a passo como a interação transcorre. Bezerra recomenda uma estrutura padronizada, e um gabarito fixo garante que ninguém esqueça as pré-condições, os fluxos alternativos ou as exceções. Um caso de uso bem descrito contém o nome e o objetivo, os atores, as pré-condições (o que precisa ser verdade para começar), o fluxo principal numerado, os alternativos, as exceções e as pós-condições (o que passa a ser verdade ao final).

Veja um esboço da descrição do caso de uso “Realizar venda”, em forma resumida para você reconhecer o gabarito.

Caso de uso: Realizar venda. Ator principal: Atendente. Pré-condição: atendente autenticado, caixa aberto. Fluxo principal: (1) informa os produtos; (2) o sistema calcula o total; (3) informa a forma de pagamento; (4) o sistema registra o pagamento e emite o comprovante. Fluxo alternativo (3a): pagamento com cartão exige autorização da operadora. Exceção (2a): produto sem estoque interrompe a venda com aviso. Pós-condição: venda registrada, estoque atualizado.

Repare como essa descrição revela requisitos que a frase “o sistema deve permitir vender” jamais tornaria explícitos: autenticação, controle de caixa, integração com a operadora e baixa de estoque. Modelar é, em grande parte, tornar visível o que estava implícito.

Histórias de usuário: o requisito enxuto do mundo ágil

Vamos à segunda linguagem. As histórias de usuário nasceram nos métodos ágeis e têm espírito bem diferente. Enquanto o caso de uso busca completude e detalhe antecipado, a história busca o mínimo para iniciar uma conversa: ela não é o requisito completo, é uma promessa de conversa sobre ele. Essa é a filosofia ágil: em vez de especificar tudo de uma vez, especificamos o suficiente para começar e detalhamos na hora de construir.

A forma mais difundida segue três partes: “Como <papel>, quero <objetivo> para <benefício>”. Por exemplo: “Como cliente, quero consultar o preço de um produto para decidir se vou comprá-lo”. A genialidade discreta está na terceira parte: ela obriga a justificar por que a funcionalidade importa, e muitas morrem — merecidamente — quando alguém tenta preencher o “para” e descobre que não há benefício real.

O “para <benefício>” não é decoração: é o filtro de valor da história. Se você não consegue completar essa parte com um benefício honesto para o papel citado, provavelmente está diante de uma funcionalidade que ninguém pediu. Escreva sempre as três partes, e desconfie das histórias que resistem à terceira.

Os critérios INVEST

Como saber se uma história está bem escrita? O acrônimo INVEST reúne seis qualidades e virou o padrão de fato. Uma boa história deve ser Independente — desenvolvível sem depender de outra; Negociável — ponto de partida para conversa, não contrato rígido; Valiosa — entrega valor perceptível; Estimável — a equipe avalia o esforço; Pequena (small) — cabe num ciclo curto; e Testável — há jeito objetivo de verificar se foi cumprida. A tabela detalha cada critério e o sintoma de sua violação.

Critério O que exige Sintoma da violação
Independente História autônoma, sem acoplamento forte “Só dá para fazer depois daquela outra”
Negociável Espaço para conversa, não contrato fechado Detalhes de implementação travados cedo demais
Valiosa Valor perceptível ao usuário ou ao negócio Ninguém sabe dizer para que serve
Estimável Clareza suficiente para dimensionar o esforço “Não faço ideia de quanto tempo leva”
Pequena Cabe em um ciclo curto de trabalho História que “nunca termina”
Testável Existe critério objetivo de aceitação Impossível dizer se está pronta

Critérios de aceitação e o backlog

Se a história é enxuta e negociável, o que a torna testável? Os critérios de aceitação: condições concretas e verificáveis que definem quando ela está pronta. Enquanto a história diz o que se quer, os critérios dizem como saberemos que foi entregue. Para a consulta de preço, poderiam ser: o preço inclui impostos; produtos sem estoque aparecem como indisponíveis; a busca por nome parcial retorna resultados. Cada critério pode ser confirmado ou negado — é essa objetividade que fecha a lacuna deixada pela concisão da história.

O conjunto das histórias ainda não desenvolvidas forma o backlog do produto: uma lista viva e priorizada de tudo que o produto pode vir a ter. Ele evolui continuamente. As do topo tendem a ser pequenas e detalhadas, prontas para desenvolver; as do fundo, grandes e vagas, aguardando refinamento. Essa priorização contínua garante que a equipe esteja sempre trabalhando no que tem mais valor agora.

O domínio em código Dart

Antes de comparar as abordagens, quero ancorar tudo em algo concreto. Toda modelagem aponta para um modelo de domínio — as entidades e regras do negócio que o software manipula. O diagrama de classes a seguir mostra o domínio da loja, com as entidades que emergiram da descrição dos casos de uso.

classDiagram
    class Produto {
        +String nome
        +double preco
        +int estoque
        +bool disponivel()
    }
    class ItemVenda {
        +int quantidade
        +double subtotal()
    }
    class Venda {
        +DateTime data
        +double total()
        +adicionar(Produto, int)
    }
    class Cliente {
        +String nome
    }
    Venda "1" *-- "*" ItemVenda : contém
    ItemVenda "*" --> "1" Produto : refere
    Venda "*" --> "0..1" Cliente : associada a

Traduzindo o modelo para Dart, obtemos as entidades com suas regras encapsuladas. Note como cada classe carrega comportamento, não só dados — o subtotal de um item e o total de uma venda pertencem ao próprio objeto.

class Produto {
  final String nome;
  final double preco;
  int estoque;

  Produto(this.nome, this.preco, this.estoque);

  bool disponivel(int quantidade) => estoque >= quantidade;
}

class ItemVenda {
  final Produto produto;
  final int quantidade;

  ItemVenda(this.produto, this.quantidade);

  double subtotal() => produto.preco * quantidade;
}

class Venda {
  final DateTime data;
  final Cliente? cliente;
  final List<ItemVenda> itens = [];

  Venda(this.data, {this.cliente});

  void adicionar(Produto produto, int quantidade) {
    if (!produto.disponivel(quantidade)) {
      throw Exception('Estoque insuficiente para ${produto.nome}');
    }
    itens.add(ItemVenda(produto, quantidade));
    produto.estoque -= quantidade;
  }

  double total() =>
      itens.fold(0.0, (soma, item) => soma + item.subtotal());
}

class Cliente {
  final String nome;
  Cliente(this.nome);
}

Perceba a ligação direta entre requisito e código: a exceção lançada em adicionar quando falta estoque é exatamente o fluxo de exceção do caso de uso “Realizar venda”. O requisito não morreu no documento; reapareceu, encarnado, como regra do domínio. Essa continuidade entre requisito e implementação é o que buscamos ao modelar com cuidado.

Casos de uso ou histórias de usuário: uma comparação honesta

Chegamos à pergunta que já deve ter se formado na sua cabeça: qual usar? A resposta honesta é que elas não competem tanto quanto parecem — servem a contextos diferentes, e escolher errado custa caro.

O caso de uso brilha quando o sistema tem interações complexas, muitos fluxos alternativos e exceções, e quando há necessidade de documentação detalhada e duradoura — sistemas críticos, contratos formais, domínios regulados. Sua força é a completude: um caso de uso bem escrito sobrevive à equipe que o criou. Sua fraqueza é o peso: escrever e manter descrições completas é caro, e em mudança rápida esse detalhamento envelhece antes de ser usado.

A história de usuário brilha em contextos ágeis e de descoberta incremental, onde os requisitos amadurecem com o uso do produto. Sua força é a leveza e o convite à conversa: barata de escrever, fácil de repriorizar, focada no valor. Sua fraqueza é depender da conversa presencial e da memória da equipe — uma história isolada comunica pouco, e funciona mal como documentação de longo prazo porque foi concebida para ser efêmera.

NotaO critério prático de escolha

Quanto maior a necessidade de documentação formal, completa e durável, mais o caso de uso compensa. Quanto maior a incerteza e a velocidade de mudança, mais a história compensa. Muitas equipes maduras combinam as duas: histórias para conversar e priorizar no dia a dia, casos de uso para documentar os fluxos críticos que precisam sobreviver ao tempo.

Síntese

Retenha três ideias. A primeira: modelar requisitos é dar forma e história ao material bruto — em vez de funções soltas, contamos quem usa o sistema, para quê e o que acontece quando algo dá errado; é nos fluxos de exceção que mora a complexidade real. A segunda: casos de uso e histórias têm filosofias opostas — o caso de uso busca completude e permanência, com atores, fluxos e relações de inclusão, extensão e generalização; a história busca o mínimo para iniciar uma conversa, guiada pelo papel-objetivo-benefício e pelos critérios INVEST. A terceira: a escolha é contextual, não ideológica — documentação durável pede casos de uso, mudança rápida pede histórias, e nada impede combiná-las.

Para consolidar antes da aula: escolha um sistema que você usa todo dia e escreva, para uma mesma funcionalidade, um esboço de caso de uso (com fluxo principal e uma exceção) e uma história de usuário no formato completo com dois critérios de aceitação. Ao comparar os dois textos lado a lado, você sentirá na prática a diferença de filosofia que discutimos, e é essa percepção que quero que você traga.