Módulo 02 — Fundamentos da Engenharia de Software

Onde estamos. No módulo anterior combinamos por que a engenharia de software existe e o que a separa de “saber programar”. Agora vamos descer um degrau e pisar no chão onde tudo acontece: o processo. Quero que você chegue à aula entendendo o que é um processo de software, quais atividades ele sempre contém, por que a manutenção — e não o desenvolvimento — domina o custo de um sistema ao longo da vida, e por que tantas ideias erradas sobre software ainda sabotam projetos inteiros.

Deixe-me abrir com uma pergunta que parece ingênua e não é. Se dois times recebem o mesmo pedido, com as mesmas pessoas e o mesmo prazo, por que um entrega um sistema sólido e o outro entrega um amontoado de código que ninguém consegue manter? A resposta raramente está no talento individual. Está no como — na sequência de decisões, atividades e verificações que cada time seguiu, com ou sem consciência disso. Esse “como”, quando o tornamos explícito e repetível, é o que chamamos de processo de software. É o assunto que sustenta praticamente tudo o que estudaremos adiante.

O que é um processo de software

Um processo de software é o conjunto estruturado de atividades que uma equipe realiza para produzir e evoluir um sistema. Repare na palavra estruturado: não estamos falando de uma coleção aleatória de tarefas, e sim de atividades relacionadas entre si, com ordem, dependências e propósito. Ian Sommerville define processo justamente como essa sequência de atividades que levam à produção de um produto de software, e insiste que não existe um processo ideal universal — existe o processo adequado ao problema, à equipe e ao contexto. Um sistema de controle de voo, onde uma falha custa vidas, pede um processo rigoroso e documentado; um aplicativo experimental de uma startup pede um processo leve e rápido de ajustar. Ambos são engenharia; o que muda é a dosagem.

Por mais que os processos variem, quatro atividades genéricas aparecem em todos eles, ainda que com nomes e pesos diferentes. Você já as encontrou no módulo anterior, e aqui elas voltam como espinha dorsal do processo.

NotaAs quatro atividades genéricas de qualquer processo

Especificação: definir o que o sistema deve fazer e sob quais restrições ele deve operar. Projeto e implementação: organizar a estrutura interna e produzir o software que atende à especificação. Validação: verificar que o software construído corresponde ao que era necessário e desejado. Evolução: modificar o software em resposta a mudanças de necessidade ao longo do tempo.

O que distingue os processos entre si não é a presença dessas atividades, mas a forma como elas são organizadas no tempo: se acontecem em fases sequenciais bem separadas, se acontecem em ciclos curtos e repetidos, se acontecem de forma quase simultânea. Essa organização é o que dá origem aos diferentes modelos de ciclo de vida que estudaremos adiante. Por ora, guarde a ideia de que toda equipe especifica, projeta e implementa, valida e evolui — a diferença está no arranjo.

flowchart LR
    A[Especificação] --> B[Projeto e Implementação]
    B --> C[Validação]
    C --> D[Evolução]
    D -. muda a necessidade .-> A
    C -. reprova .-> B
    style A fill:#cfe2ff,stroke:#084298
    style B fill:#d1e7dd,stroke:#0f5132
    style C fill:#fff3cd,stroke:#664d03
    style D fill:#f8d7da,stroke:#842029

Dirigidos a plano ou ágeis: uma primeira distinção

Já que a diferença entre processos está no arranjo das atividades, vale antecipar a grande divisão que percorrerá o semestre inteiro. De um lado, temos os processos dirigidos a plano: neles, procura-se planejar antecipadamente o máximo possível — requisitos, projeto, cronograma — e o progresso é medido em relação a esse plano. De outro, temos os processos ágeis: neles, o planejamento é incremental e distribuído ao longo do trabalho, de modo que o processo se ajusta continuamente às mudanças de necessidade do cliente. Não pense nisso como uma escolha entre “certo” e “errado”. Sommerville é explícito ao dizer que quase todos os processos reais misturam elementos das duas abordagens; a pergunta prática não é “plano ou agilidade?”, mas “quanto de cada, para este problema?”.

Um sistema com requisitos estáveis, alto risco de falha e forte necessidade de documentação tende a se beneficiar de mais plano; um sistema cujo próprio cliente ainda descobre o que quer, num mercado que muda rápido, tende a se beneficiar de mais agilidade. Aprofundaremos isso ao estudar os modelos de ciclo de vida e os métodos ágeis; por ora, quero apenas que você tenha o eixo na cabeça, porque ele reaparecerá em quase toda decisão de processo.

O modelo em camadas de Pressman, aprofundado

No módulo anterior apresentei rapidamente a imagem de Roger Pressman da engenharia de software como camadas que se apoiam umas nas outras. Agora quero aprofundá-la, porque ela é mais do que um desenho bonito: é uma tese sobre prioridades. Pressman organiza a engenharia de software em quatro camadas, e a ordem em que elas se sustentam não é arbitrária.

Na base de tudo está o foco na qualidade. Para Pressman, a qualidade é o “chão de fábrica” sobre o qual a engenharia repousa — um compromisso de fundo, uma cultura, sem a qual nada acima faz sentido. Não é uma etapa que se executa e conclui, e sim uma atitude que permeia cada decisão. Sobre esse compromisso repousa a camada de processo, que Pressman descreve como o adesivo que mantém as demais camadas unidas: é o processo que define quais métodos serão aplicados, em que ordem e sob quais critérios de controle. Sobre o processo estão os métodos, que fornecem o “como” técnico de cada atividade — como levantar requisitos, modelar, projetar, testar. E, no topo, estão as ferramentas, que automatizam e dão suporte aos métodos, e que quando bem integradas fazem a informação produzida por uma alimentar outra.

flowchart TB
    F[Ferramentas] --> M[Métodos]
    M --> P[Processo]
    P --> Q[Foco na Qualidade]
    style Q fill:#d1e7dd,stroke:#0f5132,stroke-width:2px
    style P fill:#cfe2ff,stroke:#084298
    style M fill:#e2d9f3,stroke:#59359a
    style F fill:#fff3cd,stroke:#664d03

A tabela a seguir resume o papel de cada camada e o erro típico de quem a ignora. Estude a última coluna com atenção, porque ela descreve patologias que você encontrará em projetos reais.

Camada Papel O erro de ignorá-la
Foco na qualidade Compromisso de fundo que dá sentido a tudo Construir rápido algo que não presta e retrabalhar sem fim
Processo Define e organiza a sequência do trabalho Cada projeto reinventa a roda, sem previsibilidade nem aprendizado
Métodos Técnicas concretas de cada atividade Executar as atividades por intuição, com resultados inconsistentes
Ferramentas Automação e apoio aos métodos Automatizar o caos, ou confundir dominar a ferramenta com fazer engenharia

A lição de prioridade permanece a mesma, e agora você entende melhor por quê: uma ferramenta poderosa sobre um processo caótico só produz caos mais depressa. Por isso investimos primeiro em qualidade, processo e métodos, e tratamos ferramentas como apoio, jamais como o coração da disciplina.

Os princípios que guiam a prática

Camadas e atividades descrevem a estrutura do trabalho, mas há um nível ainda mais fundamental: os princípios que orientam cada decisão dentro dessa estrutura. Pressman reúne um conjunto de princípios que atravessam qualquer atividade de engenharia, e quero destacar cinco que considero a bússola da prática cotidiana.

O primeiro é fornecer valor a quem usa. Toda funcionalidade, todo requisito, toda linha de código existe para servir a alguém; quando perdemos de vista o usuário, produzimos software tecnicamente correto e humanamente inútil. O segundo é manter a simplicidade. Diante de duas soluções que resolvem o problema, a mais simples quase sempre vence, porque será mais fácil de entender, testar e mudar — complexidade desnecessária é dívida que se paga por toda a vida do sistema. O terceiro é manter a visão do produto: uma equipe que perde a noção do todo produz partes que não se encaixam, e por isso alguém precisa guardar a coerência do conjunto acima das conveniências locais. O quarto princípio, que me é especialmente caro, é produzir pensando em quem virá manter o software — escrever hoje de modo que outra pessoa, amanhã, consiga entender e modificar. O quinto é estar aberto à evolução: assumir desde o início que o software vai mudar, e projetá-lo para acomodar mudança em vez de resistir a ela.

ImportanteA ideia central que você deve carregar

Esses princípios não são regras decorativas de um manual; são a diferença entre um profissional que constrói para o momento e um que constrói para a vida do sistema. Repare que quatro dos cinco princípios olham para além do agora: o usuário, o todo, o mantenedor futuro, a mudança inevitável. A imaturidade técnica quase sempre se manifesta como excesso de foco no presente imediato.

O custo real: desenvolvimento contra manutenção

Chegamos a um dos fatos mais contraintuitivos e mais importantes deste módulo. Quando um iniciante imagina o custo de um software, ele pensa no esforço de escrevê-lo pela primeira vez. A realidade da engenharia é quase o oposto: para um sistema de vida longa, a maior parte do custo total não está no desenvolvimento inicial, mas na manutenção que vem depois. A literatura clássica de engenharia de software — Sommerville e Pressman entre outros — é consistente ao afirmar que a manutenção domina o custo de vida de um sistema, frequentemente ultrapassando com folga o custo de construí-lo. Não vou cravar um número exato, porque ele varia muito conforme o tipo de sistema, mas a direção é inequívoca: manter custa mais do que criar.

Por que isso acontece? Porque software de vida longa muda o tempo todo: corrige-se defeitos, adapta-se a novos ambientes, adiciona-se funcionalidades, ajusta-se a novas leis. E, como vimos, cada mudança arrisca introduzir novos defeitos e corrói a estrutura interna. Um sistema que roda por dez anos passa a maior parte desses dez anos sendo mantido, não sendo criado.

flowchart LR
    D[Desenvolvimento inicial<br/>fatia menor do custo] --> M[Manutenção ao longo da vida<br/>fatia maior do custo]
    M -->|corretiva| M1[corrigir defeitos]
    M -->|adaptativa| M2[adaptar a novos ambientes]
    M -->|evolutiva| M3[novas funcionalidades]
    M -->|preventiva| M4[melhorar a estrutura]
    style D fill:#cfe2ff,stroke:#084298
    style M fill:#f8d7da,stroke:#842029,stroke-width:2px
    style M1 fill:#fff3cd,stroke:#664d03
    style M2 fill:#fff3cd,stroke:#664d03
    style M3 fill:#fff3cd,stroke:#664d03
    style M4 fill:#fff3cd,stroke:#664d03

A consequência é prática: se a manutenção é onde o dinheiro é gasto, então decisões que a facilitam — nomes claros, estrutura limpa, testes, documentação — não são luxo, são economia. Aqui os princípios de Pressman e o fato do custo se encontram: produzir pensando em quem virá manter deixa de ser gentileza e passa a ser a decisão economicamente mais racional que um engenheiro pode tomar.

Deixe-me tornar isso concreto com código, porque é onde o abstrato vira hábito. Considere uma função que calcula o valor de uma parcela com juros. A primeira versão “apenas funciona”.

// Escrito às pressas, pensando só em fazer passar hoje
double p(double v, double j, int n) {
  return (v * j * (1 + j)) / ((1 + j) - 1) * n;
}

Quem mantém esse código daqui a um ano estará em apuros. O que é j? É taxa mensal ou anual? A fórmula está correta? Não há como saber sem reconstruir o raciocínio do autor a partir do zero — e cada hora gasta nisso é custo de manutenção. Compare com a versão a seguir, escrita para quem virá depois.

/// Calcula o valor da parcela fixa de um financiamento pelo
/// sistema de amortização francês (Price).
/// [valorFinanciado] em reais; [taxaMensal] como fração (0.02 = 2%);
/// [numeroParcelas] deve ser positivo.
double calcularParcela({
  required double valorFinanciado,
  required double taxaMensal,
  required int numeroParcelas,
}) {
  if (numeroParcelas <= 0) {
    throw ArgumentError('numeroParcelas deve ser positivo.');
  }
  if (taxaMensal == 0) {
    return valorFinanciado / numeroParcelas;
  }
  final fator = _pow(1 + taxaMensal, numeroParcelas);
  return valorFinanciado * (taxaMensal * fator) / (fator - 1);
}

double _pow(double base, int expoente) {
  var resultado = 1.0;
  for (var i = 0; i < expoente; i++) {
    resultado *= base;
  }
  return resultado;
}

A segunda versão custou mais linhas e mais cuidado, e um iniciante poderia chamá-la de exagero. No entanto, ela documenta as unidades, nomeia os parâmetros de modo que a chamada se leia como uma frase, trata o caso de taxa zero e rejeita entradas inválidas em vez de devolver um número sem sentido. Quem a mantiver amanhã entende a intenção sem arqueologia. Essa diferença — invisível para quem só pensa em “fazer funcionar” — é exatamente a mentalidade que este módulo quer assentar em você.

Os mitos do software, desfeitos um a um

Pressman abre sua obra combatendo um conjunto de crenças arraigadas que ele chama de mitos do software: ideias que parecem razoáveis, que se repetem por hábito e que, no entanto, levam projetos ao fracasso. Ele os agrupa por quem os sustenta — gestão, cliente e desenvolvedor — e quero desfazê-los com você, porque reconhecê-los é meia defesa contra eles.

Um mito é perigoso justamente porque soa sensato. Ninguém repete uma bobagem óbvia; repetimos meias-verdades que já foram úteis em outro contexto e que aplicamos onde não valem. Por isso, ao estudar cada mito, pergunte-se com honestidade: eu já acreditei nisto?

Comecemos pelos mitos de gestão, sustentados por quem coordena. O mais comum é acreditar que basta ter um manual de padrões e procedimentos na estante para que a equipe produza bem — como se a existência do documento garantisse seu uso e sua adequação. Outro é o mito de que, se um projeto atrasa, adicionar mais programadores o acelera; na prática, incorporar gente a um projeto atrasado costuma atrasá-lo ainda mais, porque o tempo gasto integrando e comunicando os recém-chegados supera o ganho de mãos extras. E há o mito de que terceirizar o desenvolvimento resolve o problema por si só, quando uma organização que não sabe gerir seus próprios projetos também não saberá gerir um fornecedor.

Passemos aos mitos do cliente, sustentados por quem encomenda o software. O primeiro é supor que uma declaração geral de objetivos é suficiente para começar a construir, e que os detalhes se resolvem depois — subestimando quanto requisitos vagos custam adiante. O segundo, ainda mais teimoso, é acreditar que requisitos podem mudar livremente a qualquer momento porque “software é flexível” e a mudança sai barata. É verdade que software muda mais facilmente que concreto, mas o custo de uma mudança cresce dramaticamente conforme o projeto avança: alterar um requisito no início é barato; alterá-lo depois de o sistema estar construído pode ser caríssimo.

Encerramos com os mitos do desenvolvedor, e estes são os que mais me interessam, porque são os seus. O primeiro é acreditar que, uma vez que o programa “funciona” e foi entregue, o trabalho terminou — quando, como acabamos de ver, a maior parte do esforço na vida do sistema vem depois da primeira entrega. O segundo é supor que a única medida real de progresso é código executável rodando, desprezando as atividades de especificação, projeto e revisão que evitam retrabalho caro. O terceiro é a ilusão de que a qualidade só pode ser avaliada depois que o programa está rodando, ignorando que revisões técnicas de requisitos e de projeto encontram defeitos muito mais cedo e muito mais barato do que os testes. A tabela abaixo condensa esses mitos e a realidade que os desfaz.

Quem sustenta O mito A realidade
Gestão Ter o manual de padrões basta para produzir bem O que importa é o uso real e adequado do processo, não o documento
Gestão Projeto atrasado? Ponha mais gente Integrar gente a projeto atrasado tende a atrasá-lo mais
Cliente Uma ideia geral basta para começar Requisitos vagos geram retrabalho caro adiante
Cliente Mudar requisitos é barato, software é flexível O custo da mudança cresce fortemente com o avanço do projeto
Desenvolvedor Entregou e rodou, acabou o trabalho A manutenção é a maior parte do custo de vida do sistema
Desenvolvedor Só código rodando é progresso real Especificação, projeto e revisão previnem retrabalho e são progresso
Desenvolvedor Qualidade só se avalia com o programa pronto Revisões técnicas acham defeitos mais cedo e mais barato
DicaComo usar esta lista

Não decore os mitos como itens de prova. Use-os como espelho ao longo do curso: sempre que você se pegar pensando “isso a gente resolve depois” ou “já funciona, então está pronto”, desconfie — há uma boa chance de que um destes mitos esteja falando por você.

Como este módulo se conecta ao restante do curso

Aqui você consolidou os fundamentos que dão sustentação a tudo o que vem: o que é processo e quais atividades genéricas o compõem, a tensão entre plano e agilidade, o modelo em camadas de Pressman com a qualidade na base, os princípios que guiam a prática, o peso econômico da manutenção e os mitos que sabotam projetos. Adiante, cada modelo de ciclo de vida que estudarmos será um arranjo diferente das quatro atividades genéricas; cada técnica de requisitos, projeto e teste será um método sobre a camada de processo; e a ênfase em manutenibilidade que atravessa o curso é a resposta direta ao fato de que manter custa mais do que criar.

Síntese

Retenha três ideias desta conversa. A primeira é que processo é o “como” tornado explícito e repetível, composto sempre pelas mesmas quatro atividades genéricas — especificar, projetar e implementar, validar e evoluir — arranjadas de formas que vão do dirigido a plano ao ágil. A segunda é que a manutenção, e não o desenvolvimento inicial, domina o custo de vida de um sistema, o que transforma clareza, simplicidade e cuidado com o mantenedor futuro em decisões econômicas, não estéticas. A terceira é que os mitos do software — de gestão, de cliente e de desenvolvedor — são perigosos porque soam sensatos, e que reconhecê-los é a primeira defesa contra eles. Chegue à aula com essas três ideias assentadas, porque construiremos os próximos módulos sobre elas.

Para consolidar antes da aula: escolha um dos mitos do desenvolvedor e tente defendê-lo em voz alta como se você acreditasse nele; depois, refute-o com seus próprios argumentos. Se você conseguir fazer os dois lados com convicção, entendeu por que esses mitos são difíceis de matar — e por que vale a pena.