Todo sistema atende dois tipos de exigência: o que ele faz (requisitos funcionais) e quão bem ele faz (requisitos não funcionais). Funcionalidade é fácil de demonstrar — ou o botão funciona, ou não. Qualidade é traiçoeira: "rápido", "seguro" e "confiável" não significam nada até virarem número com meta. Este material mostra como transformar atributos de qualidade em requisitos não funcionais (RNF) mensuráveis, e como medi-los de verdade — localmente, em Docker, sem nuvem e sem custo.


1 · Por que requisitos não funcionais quebram projetos

Projetos raramente fracassam porque a funcionalidade não existe. Eles fracassam porque a funcionalidade existe, mas lenta demais, instável demais ou insegura demais para ser usada. O carrinho de compras funciona — mas leva 8 segundos para abrir na Black Friday. O relatório calcula certo — mas derruba o banco quando dez pessoas o abrem juntas. A API responde — até alguém mandar dez mil requisições e ela começar a retornar erro 500.

Esses são problemas de requisito não funcional. E eles têm uma característica perversa: só aparecem sob carga, em produção, no pior momento. Por isso a engenharia séria os trata como cidadãos de primeira classe — escritos, medidos e validados desde cedo, exatamente como se faz com os funcionais.

⚠️ O custo do "depois a gente otimiza". RNF descobertos tarde são caríssimos: muitas vezes exigem mudar arquitetura, banco ou infraestrutura — não uma linha de código. Medir cedo e localmente é a forma barata de descobrir o limite antes que o cliente descubra por você.

2 · SWEBOK e ISO/IEC 25010: o vocabulário da qualidade

Para não cair no "achismo", a Engenharia de Software tem um corpo de conhecimento consolidado: o SWEBOK (Guide to the Software Engineering Body of Knowledge, mantido pelo IEEE). Ele dedica uma área inteira a Software Quality e trata qualidade como atributo mensurável, não opinião. Para nomear esses atributos, o SWEBOK aponta para um modelo de referência: a ISO/IEC 25010, que organiza a qualidade de produto de software em características e subcaracterísticas.

Requisito funcional × requisito não funcional

A distinção fundamental

  • Requisito Funcional (RF): o que o sistema faz — uma função, uma regra de negócio, uma transformação de entrada em saída.
  • Requisito Não Funcional (RNF): quão bem o sistema faz — os atributos de qualidade, os famosos "-ilidades" (performance, confiabilidade, segurança, usabilidade…).

No nosso projeto: "mostrar o ticket médio por categoria" é um RF. "Responder essa consulta em menos de 800 ms no p95 com a base completa da OLIST" é o RNF que diz o quão bem aquele RF precisa ser entregue.

Repare: o RNF só faz sentido amarrado a um cenário concreto (qual consulta, qual volume de dados, qual percentil). RNF solto — "o sistema deve ser rápido" — é decoração, não requisito.

3 · Os eixos de RNF e a pergunta de cada um

A ISO/IEC 25010 dá um mapa dos atributos de qualidade. Estes são os seis eixos que mais viram requisito não funcional na prática — cada um responde a uma pergunta diferente:

⚡ Performance Efficiency

É rápido e econômico em recursos sob carga?

Ex.: p95 da consulta < 800 ms; CPU do container < 70%.
🛡️ Reliability

Continua funcionando e se recupera de falhas?

Ex.: taxa de erro < 1% durante o teste de carga.
🔒 Security

Protege dados, segredos e acessos?

Ex.: nenhuma credencial hardcoded; imagem sem CVE crítica.
🎨 Usability

É fácil de entender e usar?

Ex.: o dashboard é navegável sem manual.
🔧 Maintainability

É fácil de mudar, testar e evoluir?

Ex.: análise estática sem smell crítico.
📦 Portability

Roda em outro ambiente sem dor?

Ex.: sobe igual com um docker compose up.

Na aula prática o foco recai sobre os eixos que dão métrica objetiva rodando localmente: performance, reliability e eficiência de recursos. Os demais (usability, portability) também importam, mas são medidos de outra forma — voltaremos a isso na seção 7.

4 · Anatomia de um bom RNF

O erro mais comum é escrever um RNF que ninguém consegue verificar. Um RNF bom é uma frase testável: dá para apontar um número, uma ferramenta e um veredito (passou / não passou). Use esta estrutura mental:

Estrutura de um RNF mensurável

  1. Eixo de qualidade — qual atributo (performance, reliability…).
  2. Cenário/condição — sob qual carga, qual volume de dados, qual operação.
  3. Métrica (SLI) — o indicador concreto que será medido (ex.: latência p95).
  4. Meta (SLO) — o valor-limite aceitável (ex.: < 800 ms).
  5. Forma de verificação — a ferramenta e o método que produzem o número.
❌ RNF ruim (não verificável)
"O sistema deve ser rápido e suportar muitos usuários."

✅ RNF bom (verificável)

"Com a base completa da OLIST carregada, a consulta de ticket médio por categoria deve responder em < 800 ms no p95 sob 50 usuários virtuais simultâneos, medido com k6, mantendo taxa de erro < 1%."

5 · O projeto base: um stack SRE

Para medir qualidade precisamos de um sistema real para medir. O projeto base é um pequeno pipeline de dados conteinerizado — repositório github.com/afonsolelis/20261sre-primeironome-ultimonome — que sobe inteiro com um comando.

🧱 O que sobe em Docker

  • ClickHouse — banco analítico colunar (portas 8123 HTTP / 9000 nativo). É onde as consultas pesadas rodam.
  • MinIO — storage S3-compatível, funcionando como data lake local (console em :9001).
  • ingestor — worker que lê os arquivos do MinIO e carrega no ClickHouse.
  • dashboard — aplicação Streamlit (porta 8501) que consulta o ClickHouse e desenha os gráficos.
  • *-init — containers idempotentes de provisionamento (criam buckets, schema, etc.).
# o fluxo de ponta a ponta docker compose up -d → CSVs no MinIO → ingestão → análise no dashboard

Por que esse stack é ótimo para estudar RNF

  • É um pipeline de dados real: tem I/O de disco/rede, query analítica pesada e uma UI — três fontes de carga distintas.
  • Tudo é conteinerizado, então dá para medir CPU, memória e I/O por container.
  • Ele ainda não tem observabilidade — instrumentá-lo é justamente o seu trabalho na aula.
  • A carga é gerada por consultas analíticas reais sobre a OLIST, não por dados sintéticos sem sentido.

Onde olhar no repositório: docker-compose.yaml (serviços) · app/ (Streamlit + ingestor) · sql/ (schema e views) · tests/.

6 · O dataset OLIST

A carga de verdade vem dos dados. Usamos o Brazilian E-Commerce Public Dataset by Olist (disponível no Kaggle) — dados reais de marketplace no Brasil.

📦 O que é

  • ~100 mil pedidos reais entre 2016 e 2018.
  • 9 tabelas relacionadas, distribuídas em CSV.
  • orders · order_items · payments · reviews · products · customers · sellers · geolocation · category.

🎯 Por que serve para medir RNF

  • Volume real — dá para gerar carga de verdade.
  • Joins pesados — pedido × item × produto × pagamento estressam CPU, memória e I/O.
  • Cardinalidade alta — ótimo para enxergar latência p95/p99.

Exemplo de pergunta analítica: "ticket médio por categoria e por estado, mês a mês" — um join de quatro tabelas que vira uma carga de leitura significativa no ClickHouse. É exatamente esse tipo de consulta que transformamos em cenário de teste.

7 · O que dá para medir localmente

Nem todo atributo de qualidade se mede num laptop sem nuvem. A boa notícia é que os que mais doem em produção — performance, confiabilidade e uso de recursos — são justamente os mais fáceis de medir localmente. Use esta regra:

Regra prática

Se você consegue gerar carga e ler um número, dá para medir localmente. O que sobra vira requisito qualitativo com critério de aceite (avaliado por inspeção ou teste com usuário).

✅ Mensuráveis localmente

  • Performance: latência (p50/p95/p99) e throughput (req/s).
  • Reliability: taxa de erro e disponibilidade sob carga.
  • Eficiência de recursos: CPU, memória e I/O por container.
  • Security (parcial): scan de imagem e análise estática de código.
  • Maintainability (parcial): linters e métricas de complexidade.

🟡 Difíceis só localmente

  • Usability: precisa de gente usando (teste com usuário).
  • Portability: exige rodar em ambientes diferentes de verdade.
  • Disponibilidade real (SLA): precisa de produção e tempo de operação.

8 · Ferramentas locais por eixo

O critério de seleção é simples: a ferramenta precisa rodar offline, em container, e cuspir um número que dê para comparar antes/depois. Escolha pelo menos uma por categoria.

Categoria Ferramentas (todas com imagem Docker) O que medem / encontram
⚡ Carga & Performance k6, Locust, Apache Bench (ab), wrk, Artillery Latência, throughput e taxa de erro sob carga controlada.
📊 Observabilidade Prometheus + Grafana, cAdvisor, node_exporter, OpenTelemetry, Loki, Jaeger/Tempo Métricas, logs e traces consolidados em dashboard.
🔒 Segurança Trivy (imagem), OWASP ZAP (web), Bandit / Semgrep (código) CVEs, segredos expostos e falhas de código (SAST).
🔧 Recursos & Código docker stats, cAdvisor, ruff / flake8, radon (complexidade) CPU/memória por container e saúde/complexidade do código.
⚠️ Cuidado com o gerador de carga. Se o k6/Locust rodar no mesmo laptop que o sistema sob teste, eles competem por CPU. Para cargas maiores, observe se o gargalo está no sistema ou na própria ferramenta de teste — e, quando possível, limite os recursos do container de teste.

9 · Observabilidade: os 3 pilares + RED/USE

Medir não é só "rodar e olhar". Observabilidade é a capacidade de entender o estado interno do sistema pelo que ele emite. Ela se apoia em três pilares:

📈 Métricas

Números agregados ao longo do tempo. Prometheus coleta, Grafana mostra, cAdvisor expõe CPU/memória por container.

📝 Logs

O que cada serviço escreve, evento a evento. Loki + Promtail centralizam e tornam pesquisável.

🔗 Traces

O caminho de uma requisição atravessando os serviços. OpenTelemetry + Jaeger/Tempo mostram onde o tempo foi gasto.

Para não medir tudo sem critério, há dois métodos clássicos que dizem o que observar:

RED × USE — dois mapas para não se perder

  • RED (para serviços/requisições): Rate (taxa de requisições), Errors (taxa de erro), Duration (latência). É a visão de quem chama o serviço.
  • USE (para recursos): Utilization (uso), Saturation (fila/saturação), Errors (erros do recurso). É a visão de quem opera a máquina.

Na prática: use RED para olhar o dashboard/ClickHouse como serviço e USE para olhar CPU, memória e disco de cada container.

Plugando observabilidade no compose

Como o stack já é conteinerizado, basta adicionar os serviços de observabilidade ao mesmo docker-compose.yaml:

services: prometheus: { image: prom/prometheus } grafana: { image: grafana/grafana } cadvisor: { image: gcr.io/cadvisor/cadvisor }
  • O cAdvisor já enxerga automaticamente todos os containers do stack.
  • O Grafana pluga no Prometheus como fonte de dados e você monta os painéis.
  • O k6 pode exportar suas métricas direto para o Prometheus, então o teste de carga e os recursos aparecem no mesmo dashboard.

10 · Métricas por eixo: do conceito ao número

Antes de medir, é preciso entender o que cada número significa — principalmente os percentis, que é onde mais gente erra.

Latência e percentis (p50 / p95 / p99)

A média de latência mente. Se 99 requisições levam 100 ms e uma leva 10 s, a média ainda parece boa — mas há um usuário furioso. Por isso usamos percentis:

  • p50 (mediana): metade das requisições foi mais rápida que esse valor. É a experiência "típica".
  • p95: 95% foram mais rápidas; os 5% piores ficaram acima. É o padrão de SLO mais comum.
  • p99: só 1% ficou acima. Mostra a "cauda" — os casos raros mas dolorosos.

Throughput vs. latência

Throughput é quantas requisições por segundo (req/s) o sistema consegue processar. Os dois andam juntos: conforme o throughput sobe, em algum ponto a latência dispara — esse "joelho" da curva é a capacidade prática do sistema.

⚡ Performance

Latência p50 / p95 / p99, throughput (req/s), tempo da query.

Ferramenta: k6 / Locust contra o :8501 e o HTTP do ClickHouse.
🛡️ Reliability

Taxa de erro (%), requisições falhas, disponibilidade durante a carga.

Ferramenta: métricas de erro do k6 + status no Grafana.
💻 Recursos

CPU (%), memória (MB), I/O de disco e rede — por container.

Ferramenta: cAdvisor + Prometheus + docker stats.
🔒 Segurança

Nº de CVEs por severidade, segredos expostos, findings de SAST.

Ferramenta: Trivy na imagem + Bandit no código Python.
⚠️ Sempre registre o baseline. Meça antes de qualquer mudança. Sem um ponto de partida, é impossível afirmar que algo melhorou ou piorou — você só terá uma opinião.

11 · SLI, SLO, baseline e a caça ao gargalo

Número solto não decide nada. Para virar decisão de engenharia, o número precisa de uma meta e de contexto.

O trio que organiza tudo

  • SLI (Service Level Indicator) — o indicador que você mede. Ex.: p95 da consulta.
  • SLO (Service Level Objective) — a meta para esse indicador. Ex.: p95 < 800 ms.
  • Baseline — o valor atual medido, o ponto de partida.

A análise é comparar medido × meta e dar um veredito: ✅ ok · 🟡 atenção · 🔴 estourou.

Achando o gargalo

O segredo é correlacionar carga, recursos e latência no mesmo intervalo de tempo. Os padrões mais comuns:

Sintoma observadoProvável gargalo
Latência sobe e a CPU do banco saturaGargalo no banco (query/CPU)
Erro sobe sem nenhum recurso saturarLimite de conexões ou timeout
Memória cresce sem parar e não voltaVazamento de memória (memory leak)
Throughput trava num teto com CPU ociosaContenção de I/O ou lock

Fechamento de cada eixo

Para cada eixo medido, escreva uma linha: métrica · valor · meta · veredito · 1 hipótese de melhoria. Exemplo: Performance · p95 · k6 · 640 ms (meta < 800 ms) → ✅ ok.

12 · Roteiro prático (as 3 etapas)

A aula de 2 horas se divide em três blocos de mão na massa. Use este roteiro como guia de execução.

Etapa 1 — Rodar o projeto com a OLIST (≈40 min)

📝 Passo a passo

  1. Clone o repositório e entre na pasta.
  2. cp .env.example .env e ajuste as variáveis.
  3. docker compose up -d — sobe ClickHouse, MinIO, ingestor e dashboard.
  4. Suba os CSVs da OLIST para o bucket do MinIO (console em :9001).
  5. Dispare/observe o ingestor carregando os dados no ClickHouse.
  6. Abra o Streamlit em :8501 e valide os gráficos.

✅ Funcionou se: docker compose ps mostra tudo healthy; SELECT count() FROM orders retorna > 0; o dashboard abre sem erro com dados da OLIST.

🔧 Travou? docker compose logs -f ingestor para ver o erro · confira as credenciais do MinIO no .env · confirme que os CSVs foram para o bucket correto.

Etapa 2 — Escolher e subir as ferramentas (≈20 min)

Com base na tabela da seção 8, escolha pelo menos uma ferramenta por categoria e suba-as em container. No mínimo: um gerador de carga (k6 ou Locust) e o trio de observabilidade (Prometheus + Grafana + cAdvisor). Justifique cada escolha — por que essa e não outra.

Etapa 3 — Medir, observar e analisar (≈30 min)

📝 Roteiro

  1. Suba o stack de observabilidade (Prometheus + Grafana + cAdvisor).
  2. Escreva um teste de carga (k6) que consulta o dashboard/ClickHouse.
  3. Rode a carga e observe p95, throughput e taxa de erro.
  4. No Grafana, acompanhe CPU/memória por container durante o teste.
  5. Anote o baseline de cada métrica.

Pergunta-guia: "Quando a carga dobra, o que estoura primeiro — a CPU do ClickHouse, a memória do dashboard ou a latência da query?"

13 · Entrega e critérios

A entrega prova que você mediu — não apenas que rodou.

📦 Entrega mínima

  • Projeto rodando com dados da OLIST (print do dashboard).
  • Tabela de RNF mensuráveis: eixo → métrica → ferramenta → valor.
  • Resultado do teste de carga: p95, throughput e taxa de erro.
  • Print do Grafana com CPU/memória durante a carga.
  • Uma análise curta + 1 hipótese de melhoria.

🛠️ Como apresentar

  • Liste as ferramentas escolhidas e o porquê.
  • Mostre o baseline de cada métrica.
  • Aponte o gargalo encontrado, com evidência.
Formato da linha: Performance · p95 · k6 · 640 ms (meta < 800 ms) → ✅ ok

🚀 Próximo nível

Levar a mesma observabilidade para a nuvem (AWS) e transformar os baselines em SLOs com alertas — o sistema passa a avisar antes de violar a meta, não depois.

14 · Glossário e referências

TermoDefinição rápida
RNFRequisito Não Funcional — diz quão bem o sistema faz algo (atributo de qualidade).
SWEBOKGuia do corpo de conhecimento da Engenharia de Software (IEEE); tem área dedicada a qualidade.
ISO/IEC 25010Modelo de qualidade de produto de software referenciado pelo SWEBOK.
SLIService Level Indicator — o indicador que você mede (ex.: p95).
SLOService Level Objective — a meta para o SLI (ex.: p95 < 800 ms).
BaselineO valor atual medido, ponto de partida para comparação.
p95 / p99Percentis de latência: 95% / 99% das requisições foram mais rápidas que esse valor.
ThroughputVolume de requisições processadas por unidade de tempo (req/s).
REDRate, Errors, Duration — método de observabilidade de serviços.
USEUtilization, Saturation, Errors — método de observabilidade de recursos.
CVECommon Vulnerabilities and Exposures — vulnerabilidade conhecida catalogada.
SASTStatic Application Security Testing — análise de segurança do código estático.

🔗 Para ir além

  • SWEBOK Guide (IEEE) — área de Software Quality.
  • ISO/IEC 25010 — modelo de qualidade de produto.
  • Google SRE Book — capítulos de SLI/SLO e error budget.
  • Documentação do k6, Prometheus, Grafana e Trivy — guias oficiais de cada ferramenta.
  • Repositório da aula: github.com/afonsolelis/20261sre-primeironome-ultimonome