Processos de Software e Metodologias Ágeis
Modelos de Processo
| Modelo | Característica | Quando usar | Problema |
| Cascata | Fases sequenciais e lineares | Requisitos estáveis, projetos críticos | Inflexível a mudanças |
| Incremental | Entrega parcial em ciclos | Requisitos parcialmente conhecidos | Pode acumular dívida técnica |
| Espiral | Iterativo focado em riscos | Projetos grandes e complexos | Caro e complexo de gerenciar |
| Ágil | Iterativo, colaborativo, adaptável | Maioria dos projetos modernos | Difícil de escalar |
Scrum — Framework Ágil mais usado
Papéis do Scrum
Product Owner (PO): dono do produto, prioriza backlog.
Scrum Master: facilita o processo, remove impedimentos.
Dev Team: desenvolve e entrega o incremento.
Artefatos do Scrum
Product Backlog: lista priorizada de tudo a fazer.
Sprint Backlog: itens selecionados para a sprint.
Incremento: produto funcionando ao fim da sprint.
Eventos do Scrum
Sprint: ciclo de 1–4 semanas.
Planning: planejamento da sprint.
Daily: reunião diária de 15min.
Review: demonstração para stakeholders.
Retrospectiva: melhoria do processo.
User Story
Formato: "Como [usuário], quero [funcionalidade] para [benefício]"
Ex: "Como gestor, quero ver o relatório de vendas mensal para tomar decisões de estoque."
⚠ Definition of Done (DoD)
Critério acordado pela equipe que define quando um item está REALMENTE pronto. Ex: código revisado + testes passando + documentado + deployado em staging. Sem DoD, "pronto" significa coisas diferentes para cada pessoa.
Kanban
Quadro Kanban básico
To Do → In Progress → Review → Done
Regras: limite de WIP (Work In Progress) em cada coluna. Visualizar gargalos. Fluxo contínuo sem sprints fixos.
Exercício 1: Qual a diferença entre Scrum e Kanban?
→ Scrum usa sprints fixas com planejamento. Kanban é fluxo contínuo sem iterações.
Scrum: entrega a cada 2 semanas com cerimônias formais. Kanban: itens entram e saem do fluxo continuamente, sem ciclos. Scrum é melhor para desenvolvimento de produto. Kanban para suporte e operações.
Testes de Software
Pirâmide de Testes
Pirâmide de Testes (base → topo)
[ E2E / UI ] ← poucos, lentos, caros
[ Integração ] ← médios
[ Unitários ] ← muitos, rápidos, baratos (base!)
| Tipo | O que testa | Velocidade | Custo |
| Unitário | Função/método isolado | Muito rápido | Baixo |
| Integração | Interação entre módulos, banco, API | Médio | Médio |
| E2E (End-to-End) | Fluxo completo do usuário | Lento | Alto |
| Regressão | Funcionalidades anteriores não quebraram | Depende | Depende |
| Performance | Tempo de resposta sob carga | Lento | Alto |
Testes Unitários em Python com pytest
pip install pytest
# arquivo: calculadora.py
def soma(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("Divisão por zero!")
return a / b
# arquivo: test_calculadora.py
import pytest
from calculadora import soma, divide
def test_soma_basica():
assert soma(2, 3) == 5
def test_soma_negativos():
assert soma(-1, -1) == -2
def test_divide_normal():
assert divide(10, 2) == 5.0
def test_divide_por_zero():
with pytest.raises(ValueError):
divide(10, 0)
# Rodar: pytest test_calculadora.py -v
TDD — Test Driven Development
Ciclo TDD (Red → Green → Refactor)
1.
Red: escreve o teste → falha (função não existe ainda)
2.
Green: implementa o mínimo para o teste passar
3.
Refactor: melhora o código sem quebrar os testes
Repete o ciclo para cada funcionalidade.
⚠ TDD em Backend Python
TDD é muito valorizado no mercado. Em entrevista, saber escrever testes unitários com pytest e entender o ciclo Red-Green-Refactor é diferencial. Frameworks comuns:
pytest (Python),
unittest (nativo Python),
JUnit (Java).
Exercício 2: Por que os testes unitários são a base da pirâmide?
→ São rápidos, baratos e isolados — executam em milissegundos e não dependem de banco ou rede.
Uma suite com 1000 testes unitários roda em segundos. Com E2E, rodaria em horas. A pirâmide incentiva muitos unitários (detectam bugs cedo), menos E2E (só fluxos críticos).
Padrões de Projeto (Design Patterns)
Padrões de projeto são soluções reutilizáveis para problemas recorrentes no design de software. Divididos em 3 categorias: criacionais, estruturais e comportamentais.
Padrões Criacionais
# Singleton — garante uma única instância
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "conectado"
return cls._instance
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True — mesma instância!
# Factory — cria objetos sem expor a lógica de criação
class AnimalFactory:
@staticmethod
def criar(tipo):
if tipo == "cachorro": return Cachorro()
if tipo == "gato": return Gato()
raise ValueError(f"Animal desconhecido: {tipo}")
animal = AnimalFactory.criar("cachorro")
Padrões Estruturais
# Decorator — adiciona comportamento sem modificar a classe
def log_chamada(func):
def wrapper(*args, **kwargs):
print(f"Chamando {func.__name__}")
resultado = func(*args, **kwargs)
print(f"{func.__name__} concluído")
return resultado
return wrapper
@log_chamada
def processar_pedido(pedido_id):
print(f"Processando pedido {pedido_id}")
processar_pedido(42)
# Chamando processar_pedido
# Processando pedido 42
# processar_pedido concluído
Padrões Comportamentais
# Observer — notifica múltiplos objetos sobre mudanças
class EventoVenda:
def __init__(self):
self._observadores = []
def assinar(self, obs):
self._observadores.append(obs)
def notificar(self, dados):
for obs in self._observadores:
obs.atualizar(dados)
class EstoqueService:
def atualizar(self, dados):
print(f"Estoque: baixando {dados['produto']}")
class EmailService:
def atualizar(self, dados):
print(f"Email: confirmação enviada para {dados['cliente']}")
evento = EventoVenda()
evento.assinar(EstoqueService())
evento.assinar(EmailService())
evento.notificar({'produto': 'TV', 'cliente': 'Ana'})
# Strategy — intercambia algoritmos em tempo de execução
class OrdenadorContexto:
def __init__(self, estrategia):
self.estrategia = estrategia
def ordenar(self, dados):
return self.estrategia(dados)
ctx = OrdenadorContexto(sorted)
ctx.ordenar([3,1,2]) # [1,2,3]
| Padrão | Problema que resolve | Quando usar |
| Singleton | Garantir 1 única instância | Conexão DB, Logger, Config |
| Factory | Criar objetos sem hardcode do tipo | Quando o tipo varia em runtime |
| Decorator | Adicionar comportamento sem herança | Logging, auth, cache em funções |
| Observer | Notificar múltiplos sobre eventos | Eventos, webhooks, sistemas reativos |
| Strategy | Trocar algoritmos em runtime | Múltiplas formas de fazer algo |
| Repository | Abstrai acesso a dados | Separar lógica de negócio do banco |
Clean Code e DevOps
Princípios de Clean Code
Nomes significativos
Ruim: d, temp, x, data2
Bom: dias_ate_entrega, temperatura_celsius, valor_total
Nome deve revelar a intenção.
Funções pequenas
Função deve fazer uma coisa só. Se você não consegue nomear em menos de 3 palavras, provavelmente faz coisas demais.
DRY — Don't Repeat Yourself
Cada pedaço de conhecimento deve ter uma única representação. Código duplicado = bug duplicado quando você corrigir um e esquecer o outro.
YAGNI — You Ain't Gonna Need It
Não implemente funcionalidades especulativas. Só adicione o que é necessário agora. Código não escrito = zero bugs, zero manutenção.
# Ruim — Clean Code violations
def f(d, u):
if d > 0:
x = d * 0.1
u['bal'] -= x
return True
return False
# Bom — Clean Code
def aplicar_taxa_servico(valor_servico: float, conta: dict) -> bool:
TAXA_PERCENTUAL = 0.10
if valor_servico <= 0:
return False
taxa = valor_servico * TAXA_PERCENTUAL
conta['saldo'] -= taxa
return True
Git — Controle de Versão Essencial
git init # novo repositório
git clone # clonar repositório
git status # ver arquivos modificados
git add arquivo.py # preparar para commit
git add . # preparar todos
git commit -m "feat: add login endpoint" # salvar
git push origin main # enviar para remote
# Branches
git checkout -b feature/login # criar e mudar de branch
git merge feature/login # unir branch na atual
git pull origin main # atualizar local
# Convenção de commit (Conventional Commits)
# feat: nova funcionalidade
# fix: correção de bug
# docs: documentação
# refactor: refatoração sem mudar comportamento
# test: adicionar/modificar testes
CI/CD — Integração e Entrega Contínua
| Conceito | O que é | Ferramentas |
| CI — Integração Contínua | Testes rodam automaticamente a cada push | GitHub Actions, Jenkins, GitLab CI |
| CD — Entrega Contínua | Deploy automático para staging após CI passar | GitHub Actions, Vercel, Railway |
| CD — Deploy Contínuo | Deploy automático para produção | Requer confiança total no pipeline |
# GitHub Actions — exemplo .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with: {python-version: '3.11'}
- run: pip install -r requirements.txt
- run: pytest --cov=app tests/
⚠ Git Flow para Backend
main (produção) ← merge de → develop ← merge de → feature/X. Nunca commitar direto na main. Pull Request com code review antes de merge. Testes devem passar antes de qualquer merge.
Exercício 3: O que é dívida técnica?
→ Atalhos técnicos tomados agora que custarão mais caro no futuro para corrigir.
Como dívida financeira: você paga juros (em tempo de manutenção, bugs, dificuldade de adicionar features). Inevitável em algum nível, mas deve ser gerenciada conscientemente.
📝 Cola — Engenharia de Software
Scrum — Resumo
| Elemento | Descrição |
| Sprint | Ciclo de 1–4 semanas com entrega |
| Product Backlog | Lista priorizada de tudo a fazer |
| Daily | Reunião diária de 15min (o que fiz, farei, impedimentos) |
| Review | Demo do incremento para stakeholders |
| Retrospectiva | O que foi bem / mal / melhorar no próximo sprint |
Pirâmide de Testes
| Tipo | Quantidade | Velocidade |
| Unitários | Muitos (base) | ms |
| Integração | Médios | segundos |
| E2E | Poucos (topo) | minutos |
Padrões mais cobrados em entrevista
| Padrão | Uso típico em backend Python |
| Singleton | Conexão com banco, logger global |
| Factory | Criar serviços ou repositórios |
| Decorator | @login_required, @cache, @retry |
| Observer | Webhooks, eventos de domínio |
| Repository | Abstrai queries do banco (DAO) |
⭐ Regras de Ouro
Regra
TDD:
teste primeiro, código depois. Red → Green → Refactor
Regra
DRY: código duplicado = bug duplicado.
Extraia para função
Regra
YAGNI: não implemente o que não precisa agora —
KISS (Keep It Simple)
Regra
Nunca commitar direto na main —
Pull Request + Code Review
Regra
CI/CD: testes automáticos a cada push. Deploy automático após testes passarem
Regra
Função faz
uma coisa só. Nome revela a intenção. Sem comentários óbvios