Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

5
respostas

[Projeto] Desafio: Calculadora de despesas - Proposta de Solução em Linguagem Natural e Pseudocódigo MODULARIZADO

Controle Financeiro Pessoal

Desenvolvimento criativo de algoritmo — linguagem natural, pseudocódigo modular e demonstrativo


1. Enunciado e requisitos funcionais

Desenvolver um sistema simples de controle financeiro pessoal que permita ao usuário informar diversas despesas do mês (mercado, transporte, lazer etc.) e, ao final, apresentar um demonstrativo consolidado.

Requisitos funcionais

#Requisito
RF01Somar automaticamente todos os valores informados, por tipo, sem que o usuário precise informar quantas despesas fez
RF02Contar as despesas realizadas por tipo
RF03O processo continua em laço até que o valor digitado seja zero ou o usuário digite FIM
RF04Exibir o título CONTROLE FINANCEIRO no topo do demonstrativo
RF05Listar os tipos de despesa ordenados crescentemente por nome
RF06Para cada tipo: nome, total gasto, menor valor, maior valor, valor médio, % sobre o total geral e contagem de lançamentos
RF07Linha final de resumo geral: total geral, tipo de maior gasto (nome + valor total), tipo de menor gasto (nome + valor total), contagem total geral e valor médio geral
RF08Indicar também o tipo de maior valor médio com o valor correspondente

2. Algoritmo em linguagem natural

Objetivo: registrar despesas do mês sem saber antecipadamente quantas serão, acumulando estatísticas por tipo, e ao final exibir um demonstrativo ordenado por nome do tipo, mais uma linha de resumo geral.

Fase 1 — Preparação

  1. Criar cinco listas paralelas, todas alinhadas pelo mesmo índice, que representam cada tipo distinto de despesa encontrado:

    • nomeTipo — o nome do tipo (ex.: MERCADO, TRANSPORTE, LAZER);
    • totalTipo — soma acumulada dos valores daquele tipo;
    • qtdTipo — quantas despesas já foram lançadas naquele tipo;
    • menorTipo — menor valor individual já lançado naquele tipo;
    • maiorTipo — maior valor individual já lançado naquele tipo
  2. Zerar o contador de tipos distintos (qtdTipos), o total geral gasto (totalGeral) e a contagem geral de lançamentos (qtdGeral).

Fase 2 — Entrada de dados (laço de repetição, sem quantidade prévia)

  1. Repetir indefinidamente:
    1. Pedir ao usuário o tipo da despesa (ou a palavra FIM para encerrar).
    2. Converter o texto digitado para letras maiúsculas e remover espaços em excesso, para que "mercado", "Mercado" e "MERCADO" sejam tratados como o mesmo tipo.
    3. Se o texto for FIM, encerrar o laço.
    4. Pedir o valor da despesa.
    5. Se o valor for zero, encerrar o laço (o lançamento em andamento é descartado).
    6. Se o valor for negativo, avisar que é inválido e voltar ao início do laço, sem gravar nada.
    7. Procurar nomeTipo nas listas para descobrir se aquele tipo já existe:
      • Se não existe: abrir uma nova posição — incrementar qtdTipos, gravar o nome, iniciar o total com o valor informado, iniciar a contagem em 1, e iniciar tanto o menor quanto o maior com o próprio valor informado (é o único valor conhecido até agora).
      • Se já existe: somar o valor ao totalTipo daquela posição, somar 1 ao qtdTipo; se o valor for menor que menorTipo, substituir o menor; se for maior que maiorTipo, substituir o maior.
    8. Somar o valor ao totalGeral e somar 1 ao qtdGeral.
    9. Voltar ao passo 3.1.

Fase 3 — Ordenação

  1. Se nenhum lançamento foi feito (qtdTipos = 0), exibir a mensagem "Nenhuma despesa registrada." e terminar o programa.
  2. Ordenar as listas em ordem crescente pelo nome do tipo (método da bolha ou equivalente). Sempre que dois nomes forem trocados de posição, trocar também os valores correspondentes de totalTipo, qtdTipo, menorTipo e maiorTipo, para não quebrar o alinhamento entre as listas.

Fase 4 — Apuração dos extremos globais

  1. Percorrer as listas guardando:
    • a posição do tipo com maior total acumulado (posMaiorTotal);
    • a posição do tipo com menor total acumulado (posMenorTotal);
    • a posição do tipo com maior valor médio (posMaiorMedia), onde a média de um tipo é totalTipo ÷ qtdTipo.
  2. Calcular a média geral como totalGeral ÷ qtdGeral.
5 respostas

Fase 5 — Saída

  1. Exibir o título CONTROLE FINANCEIRO e o cabeçalho das colunas.
  2. Para cada tipo, do primeiro ao último (já em ordem alfabética), exibir em uma linha: nome do tipo, total gasto, quantidade de lançamentos, menor valor, maior valor, valor médio (total ÷ quantidade) e o percentual sobre o total geral (total ÷ totalGeral × 100).
  3. Exibir a linha de RESUMO GERAL contendo:
    • total geral gasto;
    • contagem total de despesas realizadas;
    • valor médio geral;
    • maior gasto: nome do tipo de maior total acumulado seguido do seu valor total;
    • menor gasto: nome do tipo de menor total acumulado seguido do seu valor total;
    • maior média: nome do tipo de maior valor médio seguido da média correspondente.
  4. Encerrar.

3. Arquitetura modular

Hierarquia de chamadas

PROGRAMA PRINCIPAL
│
├── Inicializar()
│
├── LerLancamentos()
│   └── RegistrarDespesa(tipo, valor)
│       ├── Normalizar(tipo)
│       ├── BuscarTipo(tipo)         -> posicao ou 0
│       ├── CriarTipo(tipo, valor)   [se posicao = 0]
│       └── AtualizarTipo(pos, valor)[se posicao > 0]
│
├── OrdenarPorNome()
│   └── Trocar(i, j)
│
└── EmitirDemonstrativo()
    ├── EscreverCabecalho()
    ├── EscreverLinhaTipo(i)          [para cada tipo]
    │   ├── MediaDoTipo(i)
    │   └── PercentualDoTipo(i)
    └── EscreverResumoGeral()
        ├── MediaGeral()
        ├── PosMaiorTotal()
        ├── PosMenorTotal()
        └── PosMaiorMedia()
              └── MediaDoTipo(i)

Catálogo de módulos

MóduloTipoParâmetrosRetornoResponsabilidade
InicializarProcedimentoZera acumuladores globais
NormalizarFunçãot: caracterecaracterePadroniza o nome do tipo (maiúsculas, sem espaços nas pontas)
ValorValidoFunçãov: reallogicoRejeita valores negativos
BuscarTipoFunçãot: caractereinteiroÍndice do tipo, ou 0 se ainda não existe
CriarTipoProcedimentot: caractere, v: realAbre nova posição nas listas paralelas
AtualizarTipoProcedimentop: inteiro, v: realAcumula total/qtde e ajusta menor/maior
RegistrarDespesaProcedimentot: caractere, v: realDecide entre criar e atualizar; soma nos totais gerais
LerLancamentosProcedimentoLaço de entrada com sentinela dupla (FIM ou 0)
TrocarProcedimentoa, b: inteiroPermuta as 5 listas paralelas simultaneamente
OrdenarPorNomeProcedimentoOrdenação crescente por nome (bolha)
MediaDoTipoFunçãop: inteirorealtotal ÷ quantidade do tipo
PercentualDoTipoFunçãop: inteirorealtotal do tipo ÷ total geral × 100
MediaGeralFunçãorealtotal geral ÷ qtde geral
PosMaiorTotalFunçãointeiroÍndice do tipo de maior total acumulado
PosMenorTotalFunçãointeiroÍndice do tipo de menor total acumulado
PosMaiorMediaFunçãointeiroÍndice do tipo de maior valor médio
EscreverCabecalhoProcedimentoTítulo e cabeçalho da tabela
EscreverLinhaTipoProcedimentop: inteiroFormata uma linha do demonstrativo
EscreverResumoGeralProcedimentoLinha final consolidada
EmitirDemonstrativoProcedimentoOrquestra toda a saída

4. Pseudocódigo modularizado

Algoritmo "CONTROLE_FINANCEIRO_PESSOAL_MODULAR"

// ============================================================
// AREA DE DADOS GLOBAIS (compartilhada pelos modulos)
// ============================================================
Var
   // listas paralelas: uma posicao por TIPO distinto de despesa
   nomeTipo  : vetor[1..100] de caractere
   totalTipo : vetor[1..100] de real
   qtdTipo   : vetor[1..100] de inteiro
   menorTipo : vetor[1..100] de real
   maiorTipo : vetor[1..100] de real

   // acumuladores globais
   qtdTipos   : inteiro     // quantidade de tipos distintos
   totalGeral : real        // soma de todas as despesas
   qtdGeral   : inteiro     // quantidade total de lancamentos

   // variaveis do programa principal
   i : inteiro


// ============================================================
// MODULO 1 - INICIALIZACAO
// ============================================================
Procedimento Inicializar()
Inicio
   qtdTipos   <- 0
   totalGeral <- 0
   qtdGeral   <- 0
FimProcedimento

// ============================================================
// MODULO 2 - NORMALIZACAO DO NOME DO TIPO
// Garante que "mercado", "Mercado" e " MERCADO " sejam
// tratados como um unico tipo.
// ============================================================
Funcao Normalizar(t : caractere) : caractere
Var
   texto : caractere
Inicio
   texto <- MAIUSC(t)
   Enquanto (Compr(texto) > 0) E (Copia(texto, 1, 1) = " ") Faca
      texto <- Copia(texto, 2, Compr(texto) - 1)          // remove espacos a esquerda
   FimEnquanto
   Enquanto (Compr(texto) > 0) E (Copia(texto, Compr(texto), 1) = " ") Faca
      texto <- Copia(texto, 1, Compr(texto) - 1)          // remove espacos a direita
   FimEnquanto
   Retorne texto
FimFuncao


// ============================================================
// MODULO 3 - VALIDACAO DO VALOR
// ============================================================
Funcao ValorValido(v : real) : logico
Inicio
   Retorne (v > 0)
FimFuncao


// ============================================================
// MODULO 4 - BUSCA DE TIPO JA CADASTRADO
// Retorna o indice do tipo, ou 0 se ainda nao existir.
// ============================================================
Funcao BuscarTipo(t : caractere) : inteiro
Var
   k : inteiro
Inicio
   Para k de 1 ate qtdTipos Faca
      Se (nomeTipo[k] = t) Entao
         Retorne k
      FimSe
   FimPara
   Retorne 0
FimFuncao


// ============================================================
// MODULO 5 - CRIACAO DE UM NOVO TIPO
// menor e maior nascem com o proprio valor: e o unico
// valor conhecido do tipo neste momento.
// ============================================================
Procedimento CriarTipo(t : caractere ; v : real)
Inicio
   qtdTipos <- qtdTipos + 1
   nomeTipo[qtdTipos]  <- t
   totalTipo[qtdTipos] <- v
   qtdTipo[qtdTipos]   <- 1
   menorTipo[qtdTipos] <- v
   maiorTipo[qtdTipos] <- v
FimProcedimento


// ============================================================
// MODULO 6 - ACUMULO EM TIPO EXISTENTE
// ============================================================
Procedimento AtualizarTipo(p : inteiro ; v : real)
Inicio
   totalTipo[p] <- totalTipo[p] + v
   qtdTipo[p]   <- qtdTipo[p] + 1

   Se (v < menorTipo[p]) Entao
      menorTipo[p] <- v
   FimSe
   Se (v > maiorTipo[p]) Entao
      maiorTipo[p] <- v
   FimSe
FimProcedimento


// ============================================================
// MODULO 7 - REGISTRO DE UMA DESPESA (regra de negocio)
// ============================================================
Procedimento RegistrarDespesa(t : caractere ; v : real)
Var
   pos : inteiro
Inicio
   pos <- BuscarTipo(t)

   Se (pos = 0) Entao
      CriarTipo(t, v)
   Senao
      AtualizarTipo(pos, v)
   FimSe

   totalGeral <- totalGeral + v
   qtdGeral   <- qtdGeral + 1
FimProcedimento


// ============================================================
// MODULO 8 - ENTRADA DE DADOS EM LACO
// Sentinela dupla: tipo = "FIM" ou valor = 0.
// A quantidade de despesas nunca e perguntada ao usuario.
// ============================================================
Procedimento LerLancamentos()
Var
   tipo     : caractere
   valor    : real
   encerrar : logico
Inicio
   encerrar <- FALSO

   Escreval("=== LANCAMENTO DE DESPESAS ===")
   Escreval("Digite FIM no tipo, ou 0 no valor, para encerrar.")
   Escreval("")

   Enquanto (encerrar = FALSO) Faca
      Escreva("Tipo da despesa (ou FIM): ")
      Leia(tipo)
      tipo <- Normalizar(tipo)

      Se (tipo = "FIM") Entao
         encerrar <- VERDADEIRO
      Senao
         Escreva("Valor de ", tipo, ": R$ ")
         Leia(valor)

         Se (valor = 0) Entao
            encerrar <- VERDADEIRO
         Senao
            Se (ValorValido(valor)) Entao
               RegistrarDespesa(tipo, valor)
            Senao
               Escreval(">> Valor invalido. Informe um valor positivo.")
            FimSe
         FimSe
      FimSe
   FimEnquanto
FimProcedimento

// ============================================================
// MODULO 9 - TROCA DE DUAS POSICOES
// As 5 listas sao paralelas: a troca precisa mover todas,
// senao os totais passam a pertencer ao tipo errado.
// ============================================================
Procedimento Trocar(a : inteiro ; b : inteiro)
Var
   auxNome : caractere
   auxReal : real
   auxInt  : inteiro
Inicio
   auxNome     <- nomeTipo[a]
   nomeTipo[a] <- nomeTipo[b]
   nomeTipo[b] <- auxNome

   auxReal      <- totalTipo[a]
   totalTipo[a] <- totalTipo[b]
   totalTipo[b] <- auxReal

   auxInt     <- qtdTipo[a]
   qtdTipo[a] <- qtdTipo[b]
   qtdTipo[b] <- auxInt

   auxReal      <- menorTipo[a]
   menorTipo[a] <- menorTipo[b]
   menorTipo[b] <- auxReal

   auxReal      <- maiorTipo[a]
   maiorTipo[a] <- maiorTipo[b]
   maiorTipo[b] <- auxReal
FimProcedimento


// ============================================================
// MODULO 10 - ORDENACAO CRESCENTE POR NOME DO TIPO
// ============================================================
Procedimento OrdenarPorNome()
Var
   a, b : inteiro
Inicio
   Para a de 1 ate (qtdTipos - 1) Faca
      Para b de 1 ate (qtdTipos - a) Faca
         Se (nomeTipo[b] > nomeTipo[b+1]) Entao
            Trocar(b, b+1)
         FimSe
      FimPara
   FimPara
FimProcedimento


// ============================================================
// MODULO 11 - CALCULOS ESTATISTICOS
// ============================================================
Funcao MediaDoTipo(p : inteiro) : real
Inicio
   Retorne (totalTipo[p] / qtdTipo[p])
FimFuncao

Funcao PercentualDoTipo(p : inteiro) : real
Inicio
   Retorne ((totalTipo[p] / totalGeral) * 100)
FimFuncao

Funcao MediaGeral() : real
Inicio
   Retorne (totalGeral / qtdGeral)
FimFuncao


// ============================================================
// MODULO 12 - APURACAO DOS EXTREMOS GLOBAIS
// ============================================================
Funcao PosMaiorTotal() : inteiro
Var
   k, pos : inteiro
Inicio
   pos <- 1
   Para k de 2 ate qtdTipos Faca
      Se (totalTipo[k] > totalTipo[pos]) Entao
         pos <- k
      FimSe
   FimPara
   Retorne pos
FimFuncao

Funcao PosMenorTotal() : inteiro
Var
   k, pos : inteiro
Inicio
   pos <- 1
   Para k de 2 ate qtdTipos Faca
      Se (totalTipo[k] < totalTipo[pos]) Entao
         pos <- k
      FimSe
   FimPara
   Retorne pos
FimFuncao

Funcao PosMaiorMedia() : inteiro
Var
   k, pos : inteiro
Inicio
   pos <- 1
   Para k de 2 ate qtdTipos Faca
      Se (MediaDoTipo(k) > MediaDoTipo(pos)) Entao
         pos <- k
      FimSe
   FimPara
   Retorne pos
FimFuncao

// ============================================================
// MODULO 13 - SAIDA: CABECALHO (formato Markdown)
// ============================================================
Procedimento EscreverCabecalho()
Inicio
   Escreval("")
   Escreval("# CONTROLE FINANCEIRO")
   Escreval("")
   Escreval("### Demonstrativo por tipo de despesa")
   Escreval("*(ordenado crescentemente por nome do tipo)*")
   Escreval("")
   Escreval("| Tipo da Despesa | Qtde | Total Gasto | Menor Valor | Maior Valor | Valor Medio | % do Total |")
   Escreval("|:----------------|-----:|------------:|------------:|------------:|------------:|-----------:|")
FimProcedimento


// ============================================================
// MODULO 14 - SAIDA: UMA LINHA DO DEMONSTRATIVO
// ============================================================
Procedimento EscreverLinhaTipo(p : inteiro)
Inicio
   Escreval("| ",     nomeTipo[p],
            " | ",    qtdTipo[p],
            " | R$ ", totalTipo[p]:0:2,
            " | R$ ", menorTipo[p]:0:2,
            " | R$ ", maiorTipo[p]:0:2,
            " | R$ ", MediaDoTipo(p):0:2,
            " | ",    PercentualDoTipo(p):0:2, "% |")
FimProcedimento
// ============================================================
// MODULO 15 - SAIDA: RESUMO GERAL
// ============================================================
Procedimento EscreverResumoGeral()
Var
   pMaior, pMenor, pMedia : inteiro
Inicio
   pMaior <- PosMaiorTotal()
   pMenor <- PosMenorTotal()
   pMedia <- PosMaiorMedia()

   Escreval("")
   Escreval("### Resumo geral")
   Escreval("")
   Escreval("| Indicador | Tipo correspondente | Valor |")
   Escreval("|:----------|:--------------------|------:|")
   Escreval("| **Total geral gasto** | - | **R$ ", totalGeral:0:2, "** |")
   Escreval("| **Qtde total de despesas** | - | **", qtdGeral, "** |")
   Escreval("| **Valor medio geral** | - | **R$ ", MediaGeral():0:2, "** |")
   Escreval("| **Despesa de maior gasto** | **", nomeTipo[pMaior],
            "** | **R$ ", totalTipo[pMaior]:0:2, "** |")
   Escreval("| **Despesa de menor gasto** | **", nomeTipo[pMenor],
            "** | **R$ ", totalTipo[pMenor]:0:2, "** |")
   Escreval("| **Despesa de maior valor medio** | **", nomeTipo[pMedia],
            "** | **R$ ", MediaDoTipo(pMedia):0:2, "** |")
FimProcedimento


// ============================================================
// MODULO 16 - ORQUESTRADOR DA SAIDA
// ============================================================
Procedimento EmitirDemonstrativo()
Var
   k : inteiro
Inicio
   EscreverCabecalho()

   Para k de 1 ate qtdTipos Faca
      EscreverLinhaTipo(k)
   FimPara

   EscreverResumoGeral()
FimProcedimento


// ============================================================
// PROGRAMA PRINCIPAL
// Apenas coordena os modulos - nenhuma regra de negocio aqui.
// ============================================================
Inicio
   Inicializar()
   LerLancamentos()

   Se (qtdTipos = 0) Entao
      Escreval("")
      Escreval("Nenhuma despesa registrada.")
   Senao
      OrdenarPorNome()
      EmitirDemonstrativo()
   FimSe

Fimalgoritmo

5. Exemplo de execução — demonstrativo em Markdown

5.1 Entrada digitada pelo usuário

#Tipo informadoValor informado
1MERCADOR$ 250,00
2TRANSPORTER$ 40,00
3LAZERR$ 120,00
4MERCADOR$ 180,50
5TRANSPORTER$ 15,00
6MERCADOR$ 90,00
7LAZERR$ 60,00
8TRANSPORTER$ 25,00
FIM(encerra o laço)

5.2 Saída gerada

CONTROLE FINANCEIRO

Demonstrativo por tipo de despesa

(ordenado crescentemente por nome do tipo)

Tipo da DespesaQtdeTotal GastoMenor ValorMaior ValorValor Médio% do Total
LAZER2R$ 180,00R$ 60,00R$ 120,00R$ 90,0023,06%
MERCADO3R$ 520,50R$ 90,00R$ 250,00R$ 173,5066,69%
TRANSPORTE3R$ 80,00R$ 15,00R$ 40,00R$ 26,6710,25%

Resumo geral

IndicadorTipo correspondenteValor
Total geral gastoR$ 780,50
Qtde total de despesas8
Valor médio geralR$ 97,56
Despesa de maior gastoMERCADOR$ 520,50
Despesa de menor gastoTRANSPORTER$ 80,00
Despesa de maior valor médioMERCADOR$ 173,50

5.3 Conferência dos cálculos

VerificaçãoCálculoResultado
Total geral180,00 + 520,50 + 80,00R$ 780,50
Qtde geral2 + 3 + 38
Média geral780,50 ÷ 8R$ 97,56
% LAZER180,00 ÷ 780,50 × 10023,06%
% MERCADO520,50 ÷ 780,50 × 10066,69%
% TRANSPORTE80,00 ÷ 780,50 × 10010,25%
Soma dos percentuais23,06 + 66,69 + 10,25100,00%

5.4 Código-fonte Markdown do demonstrativo

# CONTROLE FINANCEIRO

### Demonstrativo por tipo de despesa
*(ordenado crescentemente por nome do tipo)*

| Tipo da Despesa | Qtde | Total Gasto | Menor Valor | Maior Valor | Valor Médio | % do Total |
|:----------------|-----:|------------:|------------:|------------:|------------:|-----------:|
| LAZER           |    2 |  R$ 180,00 |   R$ 60,00 |  R$ 120,00 |   R$ 90,00 |  23,06% |
| MERCADO         |    3 |  R$ 520,50 |   R$ 90,00 |  R$ 250,00 |  R$ 173,50 |  66,69% |
| TRANSPORTE      |    3 |   R$ 80,00 |   R$ 15,00 |   R$ 40,00 |   R$ 26,67 |  10,25% |

Resumo geral

IndicadorTipo correspondenteValor
Total geral gastoR$ 780,50
Qtde total de despesas8
Valor médio geralR$ 97,56
Despesa de maior gastoMERCADOR$ 520,50
Despesa de menor gastoTRANSPORTER$ 80,00
Despesa de maior valor médioMERCADOR$ 173,50

Observações sobre a saída em Markdown:

  • A linha de alinhamento (|:---|---:|) deve vir imediatamente após o cabeçalho — é ela que define o alinhamento (:--- à esquerda para textos, ---: à direita para números e valores monetários).
  • A quantidade de colunas do cabeçalho, da linha de alinhamento e de cada linha de dados precisa ser idêntica, senão a tabela não renderiza.
  • O laço Para em EmitirDemonstrativo gera uma linha por tipo distinto, então a tabela cresce automaticamente conforme os tipos que o usuário cadastrar — nada é fixado no código.

6. Justificativas de projeto

6.1 Pontos de lógica do algoritmo

  • Não se pergunta a quantidade de despesas. O laço Enquanto em LerLancamentos é controlado por sentinela dupla (FIM no tipo ou 0 no valor), e os contadores qtdGeral e qtdTipo[] são incrementados a cada lançamento válido.
  • Descoberta dinâmica de tipos. A busca linear de BuscarTipo decide entre criar uma nova posição ou acumular numa existente — por isso o usuário nunca precisa declarar antecipadamente quais tipos vai usar.
  • Menor e maior inicializados com o próprio valor no primeiro lançamento do tipo (CriarTipo). Inicializar menorTipo com 0 seria um erro clássico: nenhum valor positivo posterior ficaria abaixo de 0 e o menor jamais seria atualizado.
  • Troca em bloco na ordenação. As cinco listas são paralelas, então toda troca precisa mover as cinco simultaneamente — daí o módulo Trocar existir isoladamente.
  • Normalização com Normalizar evita que "Mercado" e "MERCADO" virem dois tipos distintos.
  • Proteção contra divisão por zero. MediaGeral e PercentualDoTipo só são alcançadas por dentro do ramo Senao do teste qtdTipos = 0 no programa principal, ou seja, quando existe ao menos um lançamento.

6.2 O que a modularização resolve

Antes (sequencial)Depois (modular)
Um bloco único de ~120 linhas com entrada, regra de negócio, ordenação e saída misturadas16 módulos, cada um com uma responsabilidade
Trocar o formato de saída exigia mexer no meio do algoritmoBasta reescrever EscreverCabecalho, EscreverLinhaTipo e EscreverResumoGeralnenhum outro módulo é tocado
A troca de 5 vetores aparecia inline dentro da bolha, com risco de esquecer um vetorIsolada em Trocar, chamada de um único ponto
Cálculo de média repetido em 3 lugares diferentesCentralizado em MediaDoTipo, reutilizado por EscreverLinhaTipo e PosMaiorMedia
Testar a regra "tipo novo × tipo existente" exigia rodar o programa inteiroBuscarTipo, CriarTipo e AtualizarTipo podem ser verificados isoladamente
Trocar vetores paralelos por registros/matriz quebrava tudoO impacto fica contido em CriarTipo, AtualizarTipo, BuscarTipo e Trocar

6.3 Decisões de projeto

  • Dados globais + módulos sem parâmetros de estado. manter as cinco listas na área global e passar apenas índices e valores como parâmetros é a solução idiomática. Em uma linguagem com estruturas (Python), o passo seguinte natural seria substituir as listas paralelas por um vetor de registros Despesa{nome, total, qtde, menor, maior} — e a interface dos módulos permaneceria a mesma.
  • Funções puras para estatística. MediaDoTipo, PercentualDoTipo e MediaGeral apenas leem e retornam, sem alterar nada. Isso permite chamá-las de qualquer ponto sem efeito colateral — inclusive dentro de comparações, como em PosMaiorMedia.
  • RegistrarDespesa como fronteira da regra de negócio. LerLancamentos cuida só do diálogo com o usuário e da sentinela; toda a decisão sobre como armazenar está abaixo dela. Se amanhã as despesas vierem de um arquivo em vez do teclado, só LerLancamentos muda.
  • Limite de 100 tipos distintos. Valor arbitrário e folgado para uso pessoal. Em uma implementação real, o vetor seria substituído por uma lista dinâmica ou dicionário, eliminando o limite e reduzindo a busca de linear para constante.