Capítulo 19: Engenharia de Software e Decomposição Algorítmica

🎯 Objetivo da Aula

Programar em alto nível não é apenas escrever linhas de código: é projetar arquiteturas de software funcionais e escaláveis. Antes de abrir a IDE e digitar comandos, um engenheiro de software precisa entender como quebrar um problema gigantesco em partes pequenas, independentes e testáveis (Top-Down Design).

Nesta aula, você aprenderá a:

  1. Aplicar o método de Decomposição Top-Down para resolução de problemas complexos.
  2. Implementar o princípio de Separação de Responsabilidades (Single Responsibility Principle - SRP).
  3. Adotar técnicas de Programação Defensiva (blindagem contra falhas de digitação do operador).
  4. Construir um subsistema modular completo de controle de estoque com operações de cadastro, listagem e auditoria.

📥 Material de Apoio e Código-Fonte da Aula:


🏢 O Cenário Prático (Seu Desafio)

Situação: O almoxarifado de peças da FastLog opera sem informatização, gerando perdas financeiras por falta de controle do valor total estocado e duplicidade de cadastros. A gerência solicitou um software em terminal que gerencie até 3 produtos em memória, permitindo:

  1. Cadastrar Produtos (com validação de preços e quantidades positivas).
  2. Listar Estoque (com exibição tabular alinhada).
  3. Calcular Patrimônio Total (somatório financeiro de todos os itens).
  4. Pesquisar Produto por Nome (com alerta de não encontrado).

Missão: Projetar e programar esse sistema dividindo rigorosamente as tarefas em funções especializadas, sem concentrar toda a lógica no bloco inicio().


🧠 Fundamentos: A Metodologia Top-Down

1. Decomposição Top-Down (Do Todo para as Partes)

Em vez de tentar resolver o sistema inteiro de uma só vez, nós o quebramos em módulos hierárquicos:

graph TD
    Root["Sistema de Estoque FastLog WMS"] --> M1["Módulo 1: Interface & Menu (funcao vazio)"]
    Root --> M2["Módulo 2: Entrada & Cadastro (funcao vazio)"]
    Root --> M3["Módulo 3: Relatórios & Listagem (funcao vazio)"]
    Root --> M4["Módulo 4: Cálculos Financeiros (funcao real)"]
    Root --> M5["Módulo 5: Busca por SKU (funcao vazio)"]
    
    style Root fill:#8e44ad,stroke:#fff,color:#fff
    style M1 fill:#2980b9,stroke:#fff,color:#fff
    style M2 fill:#2980b9,stroke:#fff,color:#fff
    style M3 fill:#2980b9,stroke:#fff,color:#fff
    style M4 fill:#27ae60,stroke:#fff,color:#fff
    style M5 fill:#e67e22,stroke:#fff,color:#fff

2. O Princípio da Responsabilidade Única (SRP)

Cada módulo deve ter um único motivo para mudar:

  • A função de Cadastro só se preocupa em ler dados e validar se são positivos.
  • A função de Listagem só se preocupa em desenhar a tabela formatada.
  • A função de Cálculo só se preocupa em fazer a matemática e devolver o número.

📖 Exemplo Guiado: Subsistema Modular de Estoque

Código do Programa:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
programa 
{
	// Variáveis Globais (Banco de Dados em RAM)
	cadeia nomes[3]
	inteiro quantidades[3]
	real precos[3]
	inteiro totalCadastrados = 0

	// 1. Módulo de Cadastro com Programação Defensiva
	funcao vazio cadastrar_itens() 
	{
		escreva("--- CADASTRO DE 3 PRODUTOS DO LOTE ---\n")
		para (inteiro i = 0; i < 3; i++) 
		{
			escreva("Nome do Produto #", i+1, ": ")
			leia(nomes[i])

			// Validação defensiva da quantidade
			faca 
			{
				escreva("Quantidade em Saldo (> 0): ")
				leia(quantidades[i])
				se (quantidades[i] <= 0) 
				{
					escreva("[ERRO]: A quantidade deve ser positiva!\n")
				}
			} enquanto (quantidades[i] <= 0)

			// Validação defensiva do preço
			faca 
			{
				escreva("Preço Unitário (R$ > 0): ")
				leia(precos[i])
				se (precos[i] <= 0.0) 
				{
					escreva("[ERRO]: O preço deve ser maior que zero!\n")
				}
			} enquanto (precos[i] <= 0.0)

			escreva("--------------------------------------\n")
		}
		totalCadastrados = 3
		escreva(">> [SUCESSO] 3 itens registrados com sucesso!\n")
	}

	// 2. Módulo de Listagem
	funcao vazio listar_estoque() 
	{
		se (totalCadastrados == 0) 
		{
			escreva(">> [AVISO] Nenhum produto cadastrado no momento.\n")
		} 
		senao 
		{
			escreva("==================================================\n")
			escreva(" ID | NOME DO PRODUTO        | QTD  | PREÇO (R$)  \n")
			escreva("----+------------------------+------+-------------\n")
			para (inteiro i = 0; i < totalCadastrados; i++) 
			{
				escreva(" #", i+1, " | ", nomes[i], "\t\t | ", quantidades[i], " un | R$ ", precos[i], "\n")
			}
			escreva("==================================================\n")
		}
	}

	// 3. Função com Retorno: Cálculo do Patrimônio Financeiro
	funcao real calcular_patrimonio_total() 
	{
		real soma = 0.0
		para (inteiro i = 0; i < totalCadastrados; i++) 
		{
			soma += (quantidades[i] * precos[i])
		}
		retorne soma
	}

	// 4 Ponto de Entrada / Orquestrador
	funcao inicio() 
	{
		inteiro opcao

		faca 
		{
			escreva("\n=== FASTLOG WMS - INVENTORY MANAGEMENT ===\n")
			escreva(" [1] Cadastrar Itens do Lote\n")
			escreva(" [2] Listar Tabela de Estoque\n")
			escreva(" [3] Calcular Valor Total do Estoque\n")
			escreva(" [0] Sair do Sistema\n")
			escreva("Escolha uma opção: ")
			leia(opcao)

			escreva("\n")
			escolha (opcao) 
			{
				caso 1:
					cadastrar_itens()
					pare
				caso 2:
					listar_estoque()
					pare
				caso 3:
					escreva("VALOR TOTAL IMOBILIZADO: R$ ", calcular_patrimonio_total(), "\n")
					pare
				caso 0:
					escreva("Encerrando o módulo de almoxarifado...\n")
					pare
				caso contrario:
					escreva("Opção inválida!\n")
			}
		} enquanto (opcao != 0)
	}
}

🛠️ Prática Obrigatória 1: Módulo de Pesquisa por Nome

Passo 1: O Desafio

Adicione ao sistema acima uma função sem retorno chamada funcao vazio buscar_produto():

  1. Solicite o nome do produto a ser pesquisado.
  2. Varra o vetor de nomes e, se encontrar, exiba a quantidade e o preço.
  3. Se não encontrar, emita o aviso de inexistente usando a técnica da flag booleana.
  4. Adicione a opção [4] Pesquisar por Nome ao menu principal.

🛠️ Prática Obrigatória 2: Localizador de Item Mais Valioso

Crie uma função funcao cadeia item_mais_valioso() que percorra o vetor de preços e retorne o nome do produto que possui o maior preço unitário cadastrado. Adicione a opção ao menu.


📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o arquivo como: Atividade_19_SeuNome_SeuSobrenome.por.
  2. Teste todo o fluxo de navegação do menu e validações.
  3. No Microsoft Teams, envie na tarefa “Portugol Cap 19 - Decomposição Algorítmica”.
  4. Clique em Entregar (Turn In).

💡 Checkpoint de Lógica & Engenharia de Software

Você acabou de aplicar o conceito de CRUD (Create, Read, Update, Delete) e SOA (Service-Oriented Architecture). Essa separação clara de responsabilidades é o exato modelo utilizado no desenvolvimento de APIs modernas em Spring Boot, ASP.NET Core e NestJS.


🔥 Desafio de Fixação: Atualização de Saldo de Produto

Crie a função funcao vazio atualizar_quantidade() que receba o nome do produto e permita alterar a quantidade em estoque caso ele exista.


🔑 Gabarito de Código Completo

Prática 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
programa {
	cadeia nomes[3] = {"Palete Madeira", "Fita Stretch", "Caixa Papelão"}
	inteiro quantidades[3] = {150, 400, 800}
	real precos[3] = {45.0, 22.5, 8.9}
	inteiro totalCadastrados = 3

	funcao vazio buscar_produto() {
		cadeia busca
		logico achou = falso
		escreva("Digite o nome do produto: ")
		leia(busca)
		
		para (inteiro i = 0; i < totalCadastrados; i++) {
			se (nomes[i] == busca) {
				escreva(">> [ENCONTRADO]: ", nomes[i], " | Qtd: ", quantidades[i], " un | Preço: R$ ", precos[i], "\n")
				achou = verdadeiro
				pare
			}
		}
		se (nao achou) {
			escreva(">> [NÃO ENCONTRADO]: Produto '", busca, "' não consta no cadastro.\n")
		}
	}

	funcao inicio() {
		buscar_produto()
	}
}

Prática 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
programa {
	cadeia nomes[3] = {"Palete Madeira", "Fita Stretch", "Caixa Papelão"}
	real precos[3] = {45.00, 22.50, 8.90}
	inteiro totalCadastrados = 3

	funcao cadeia item_mais_valioso() {
		real maiorPreco = precos[0]
		inteiro posMaior = 0
		para (inteiro i = 1; i < totalCadastrados; i++) {
			se (precos[i] > maiorPreco) {
				maiorPreco = precos[i]
				posMaior = i
			}
		}
		retorne nomes[posMaior]
	}

	funcao inicio() {
		escreva("=== AUDITORIA PATRIMONIAL ===\n")
		escreva("Item de Maior Valor Unitário: ", item_mais_valioso(), "\n")
	}
}

Desafio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
programa {
	cadeia nomes[3] = {"Palete Madeira", "Fita Stretch", "Caixa Papelão"}
	inteiro quantidades[3] = {150, 400, 800}
	inteiro totalCadastrados = 3

	funcao vazio atualizar_quantidade() {
		cadeia busca
		inteiro novaQtd
		logico achou = falso

		escreva("Produto para atualizar saldo: ")
		leia(busca)

		para (inteiro i = 0; i < totalCadastrados; i++) {
			se (nomes[i] == busca) {
				escreva("Saldo Atual: ", quantidades[i], " un.\n")
				escreva("Digite o Novo Saldo: ")
				leia(novaQtd)
				quantidades[i] = novaQtd
				escreva(">> [SUCESSO] Saldo atualizado para ", novaQtd, " un!\n")
				achou = verdadeiro
				pare
			}
		}

		se (nao achou) {
			escreva(">> [ERRO] Produto inexistente!\n")
		}
	}

	funcao inicio() {
		atualizar_quantidade()
	}
}

📝 Atividade Extra: Questionário de Fixação (Caderno)

Instruções: Responda no caderno, de próprio punho, as 10 perguntas abaixo com base no que foi estudado neste capítulo. Ao concluir, leve o caderno até o professor para correção e visto.

  1. O que é a Decomposição Top-Down, segundo os Fundamentos deste capítulo?
  2. O que estabelece o Princípio da Responsabilidade Única (SRP), segundo o capítulo? Dê um dos exemplos citados no texto.
  3. No Exemplo Guiado (Subsistema Modular de Estoque), quais módulos/funções são criados e qual a responsabilidade de cada um?
  4. O que é Programação Defensiva, segundo o uso feito na função cadastrar_itens() do Exemplo Guiado? Dê um exemplo de validação aplicada.
  5. Na função calcular_patrimonio_total(), qual cálculo é realizado para cada item do estoque dentro do laço, e o que a função retorna ao final?
  6. Na Prática Obrigatória 1 (Módulo de Pesquisa por Nome), quais são os quatro passos que a função buscar_produto() deve realizar?
  7. Na Prática Obrigatória 2 (Localizador de Item Mais Valioso), o que a função item_mais_valioso() deve retornar, e de que tipo é o seu retorno?
  8. Segundo o Checkpoint de Lógica & Engenharia de Software, a que conceitos de arquitetura de software (siglas) a separação de responsabilidades do capítulo é comparada?
  9. No Exemplo Guiado, quantos produtos o sistema de estoque da FastLog gerencia em memória, e quais são as três opções principais oferecidas no menu (além de Sair)?
  10. Segundo o Cenário Prático, quais problemas o almoxarifado da FastLog enfrentava por falta de informatização, antes da criação do sistema?