TheCodeNaked

A Redenção do Procedural (Copy)

Como deixamos o Procedural ser expulso da sala sem defesa.


Durante décadas, o paradigma procedural foi o alicerce sobre o qual a computação moderna cresceu. De COBOL a C, de Turbo Pascal a Clipper, escrevíamos código com clareza: passo a passo, de cima pra baixo, de causa pra consequência. Era possível ver o fluxo, entender o porquê de cada linha, e corrigir o que precisava ser corrigido. Lógico, racional, matemático.

Ai vieram as buzzwords, os evangelistas de paradigmas, e de repente, programar proceduralmente virou sinônimo de "ultrapassado". Diziam: "É difícil dar manutenção", "Fica tudo acoplado", "Sem coesão", "Sem escalabilidade". Só esqueceram de mostrar provas concretas — porque o que existia de software procedural era sólido, funcional e durável.

O procedural não morreu. Ele foi silenciado. Mas nem tanto.

🤔 Somente como um primeiro exemplo da importância do paradigma procedural, convido à você ver o nosso artigo sobre a linguagem Go onde afirmamos que Go é tanto orievamos fazer alguns comentários sobre a linguagem de programação Go.

🤔 Go é Orientada a Objetos?

A resposta curta é: sim e não.
A resposta longa é: Go oferece recursos orientados a objetos, mas recusa deliberadamente o formalismo do paradigma OOP clássico.

Vamos destrinchar:

Conceito Clássico OOPGo tem?Como é?
Classes❌ NãoGo não tem class. Structs e métodos fazem o papel.
Objetos✅ SimStructs com métodos associados.
Encapsulamento✅ ParcialUsa convenção de visibilidade por letras maiúsculas (Nome público, nome privado).
Herança❌ NãoGo rejeita herança. Prefere composição.
Interfaces✅ SimInterfaces são centrais em Go — mas são implícitas.
Polimorfismo✅ SimBaseado em interfaces, mas sem acoplamento.

💡 O que isso significa?

Go adota os aspectos úteis da OOP, mas descarta tudo o que é considerado excesso, acoplamento ou complexidade artificial.

Ela não quer parecer Java, C++ ou C#. Ela quer resolver problemas de forma clara, concisa e previsível — e nisso se aproxima muito do espírito procedural pragmático.


🧠 A filosofia por trás de Go é direta:

“Favor composition over inheritance.”
“Interfaces should be satisfied implicitly.”
“Keep things simple.”

E isso é poderoso.


🧭 Então... Go é o quê?

Go é uma linguagem que:

  • não é OOP clássica
  • não é puramente procedural
  • não força estilos — mas favorece um estilo pragmático, enxuto e direto

Se você vem do mundo OOP, pode estranhar.
Se vem do mundo procedural, vai se sentir em casa — mas com esteroides.


💥

O procedural não morreu. Ele evoluiu.
Linguagens modernas como Go são a prova viva disso.
Elas mostram que herança, construtores, interfaces explícitas e hierarquias formais não são pré-requisitos para escrever software limpo, escalável e de alta performance.

O "problema" do procedural? Ser direto demais.

Programação procedural é o que fazemos naturalmente quando queremos resolver um problema. É a transcrição do raciocínio humano: se isso, então aquilo. Ela não precisa esconder o fluxo dentro de objetos, não precisa forçar herança só pra parecer “bonita”, nem encapsular o que só existe porque não confiamos nos outros programadores. Ela não nega a lógica: a celebra.

No procedural, um if não é um inimigo — é um aliado. Não fingimos que ele não existe. Aceitamos que controle de fluxo é fundamental. Rejeitamos o fetiche de eliminar os desvios condicionais só porque alguém disse que isso é "clean".

O verdadeiro acoplamento está na ignorância do que se acopla

Ironia: muitos sistemas orientados a objetos escondem tanto o fluxo que criam acoplamentos invisíveis, difíceis de detectar. Um procedural bem estruturado, com separação clara de responsabilidades em módulos e funções, frequentemente oferece menos acoplamento e mais legibilidade do que uma arquitetura que precisa de um diagrama UML para ser compreendida.

E não se engane: regras de negócio vivem no procedural. O que move um sistema não é a modelagem elegante das entidades, mas a lógica entre elas. É o que conecta, decide, ramifica. É ali que o valor acontece.

O que perdemos ao trocar clareza por abstração?

A obsessão por padrões e arquitetura nos afastou do código que resolve o problema. Ao invés de escrever um fluxo lógico claro, preferimos criar camadas, interfaces, injeções e proxies que nos afastam da intenção original. Perdemos a rastreabilidade.

E ainda tem o preço da performance. Em muitos casos, o procedural é mais leve, direto, e eficiente — especialmente quando lidamos com operações que exigem previsibilidade e rapidez.

Procedural moderno: sim, ele existe

Não estamos falando de voltar ao código espaguete. Estamos falando de resgatar o que o procedural tem de melhor:

  • fluxo claro,
  • desvios condicionais explícitos,
  • raciocínio lógico linear,
  • e estrutura modular sem teatrinho de design patterns onde não são necessários.

Você pode aplicar técnicas modernas, usar modularização, funções puras, até testes automatizados — tudo isso sem precisar se render à OOP como mandamento universal.


O procedural nunca nos deixou. Nós é que o abandonamos.

Está na hora de parar de pedir desculpas por escrever procedural. Está na hora de enxergar que há beleza na lógica direta, que há potência na simplicidade. E que, talvez, a salvação para a complexidade desnecessária que criamos esteja exatamente naquele paradigma que deixamos para trás.

A Redenção do Procedural já começou. E você pode fazer parte dela.


🧾 Sistema: Simulador de Pedido com Cálculo de Imposto e Desconto

🔧 Regras

  • Lista de produtos: nome, preço, quantidade
  • Se total bruto > R$ 500, aplicar 10% de desconto
  • Imposto:
    • SP: 18%
    • RJ: 20%
    • Outros: 15%

Versão Procedural (Delphi - Console Application)

program PedidoProcedural;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  TProduto = record
    Nome: string;
    Preco: Double;
    Quantidade: Integer;
  end;

const
  MAX_PRODUTOS = 5;

var
  Produtos: array[1..MAX_PRODUTOS] of TProduto;
  TotalBruto, TotalComDesconto, TotalFinal: Double;
  Estado: string;

function CalcularTotalBruto: Double;
var
  I: Integer;
begin
  Result := 0;
  for I := 1 to MAX_PRODUTOS do
    Result := Result + (Produtos[I].Preco * Produtos[I].Quantidade);
end;

function AplicarDesconto(ATotal: Double): Double;
begin
  if ATotal > 500 then
    Result := ATotal * 0.9 // 10% de desconto
  else
    Result := ATotal;
end;

function CalcularImposto(ATotal: Double; const AEstado: string): Double;
var
  Taxa: Double;
begin
  if AEstado = 'SP' then
    Taxa := 0.18
  else if AEstado = 'RJ' then
    Taxa := 0.20
  else
    Taxa := 0.15;

  Result := ATotal * Taxa;
end;

procedure ExibirPedido;
var
  I: Integer;
begin
  Writeln('Resumo do Pedido:');
  for I := 1 to MAX_PRODUTOS do
    Writeln(Format('%d x %s @ R$%.2f = R$%.2f',
      [Produtos[I].Quantidade, Produtos[I].Nome,
       Produtos[I].Preco,
       Produtos[I].Preco * Produtos[I].Quantidade]));

  Writeln(Format('Total Bruto: R$%.2f', TotalBruto));
  Writeln(Format('Total com Desconto: R$%.2f', TotalComDesconto));
  Writeln(Format('Imposto (%s): R$%.2f', [Estado, TotalFinal - TotalComDesconto]));
  Writeln(Format('Total Final: R$%.2f', TotalFinal));
end;

begin
  // Mock de dados
  Produtos[1] := TProduto.Create('Notebook', 2500.00, 1);
  Produtos[2] := TProduto.Create('Mouse', 150.00, 2);
  Produtos[3] := TProduto.Create('Teclado', 300.00, 1);
  Produtos[4] := TProduto.Create('Monitor', 900.00, 1);
  Produtos[5] := TProduto.Create('Cabo HDMI', 50.00, 3);

  Write('Informe o estado (UF): ');
  Readln(Estado);
  Estado := UpperCase(Trim(Estado));

  TotalBruto := CalcularTotalBruto;
  TotalComDesconto := AplicarDesconto(TotalBruto);
  TotalFinal := TotalComDesconto + CalcularImposto(TotalComDesconto, Estado);

  ExibirPedido;

  Readln;
end.

O que temos aqui:

  • Simples, legível, direto.
  • Toda lógica concentrada de forma natural.
  • Nenhuma classe, nenhuma abstração desnecessária.

🧱 Versão OOP — Delphi (Console Application)

program PedidoOOP;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Generics.Collections;

type
  TProduto = class
  public
    Nome: string;
    Preco: Double;
    Quantidade: Integer;
    constructor Create(const ANome: string; APreco: Double; AQuantidade: Integer);
    function Subtotal: Double;
  end;

  TImposto = class
  public
    class function Calcular(AEstado: string; AValor: Double): Double;
  end;

  TDesconto = class
  public
    class function Aplicar(AValor: Double): Double;
  end;

  TPedido = class
  private
    FProdutos: TObjectList<TProduto>;
    FEstado: string;
  public
    constructor Create(const AEstado: string);
    destructor Destroy; override;
    procedure AdicionarProduto(AProduto: TProduto);
    function TotalBruto: Double;
    function TotalComDesconto: Double;
    function Imposto: Double;
    function TotalFinal: Double;
    procedure ExibirResumo;
  end;

{ TProduto }

constructor TProduto.Create(const ANome: string; APreco: Double; AQuantidade: Integer);
begin
  Nome := ANome;
  Preco := APreco;
  Quantidade := AQuantidade;
end;

function TProduto.Subtotal: Double;
begin
  Result := Preco * Quantidade;
end;

{ TImposto }

class function TImposto.Calcular(AEstado: string; AValor: Double): Double;
var
  Taxa: Double;
begin
  AEstado := UpperCase(AEstado);
  if AEstado = 'SP' then
    Taxa := 0.18
  else if AEstado = 'RJ' then
    Taxa := 0.20
  else
    Taxa := 0.15;

  Result := AValor * Taxa;
end;

{ TDesconto }

class function TDesconto.Aplicar(AValor: Double): Double;
begin
  if AValor > 500 then
    Result := AValor * 0.9
  else
    Result := AValor;
end;

{ TPedido }

constructor TPedido.Create(const AEstado: string);
begin
  FProdutos := TObjectList<TProduto>.Create(True);
  FEstado := AEstado;
end;

destructor TPedido.Destroy;
begin
  FProdutos.Free;
  inherited;
end;

procedure TPedido.AdicionarProduto(AProduto: TProduto);
begin
  FProdutos.Add(AProduto);
end;

function TPedido.TotalBruto: Double;
var
  Produto: TProduto;
begin
  Result := 0;
  for Produto in FProdutos do
    Result := Result + Produto.Subtotal;
end;

function TPedido.TotalComDesconto: Double;
begin
  Result := TDesconto.Aplicar(TotalBruto);
end;

function TPedido.Imposto: Double;
begin
  Result := TImposto.Calcular(FEstado, TotalComDesconto);
end;

function TPedido.TotalFinal: Double;
begin
  Result := TotalComDesconto + Imposto;
end;

procedure TPedido.ExibirResumo;
var
  Produto: TProduto;
begin
  Writeln('Resumo do Pedido:');
  for Produto in FProdutos do
    Writeln(Format('%d x %s @ R$%.2f = R$%.2f',
      [Produto.Quantidade, Produto.Nome, Produto.Preco, Produto.Subtotal]));

  Writeln(Format('Total Bruto: R$%.2f', TotalBruto));
  Writeln(Format('Total com Desconto: R$%.2f', TotalComDesconto));
  Writeln(Format('Imposto (%s): R$%.2f', [FEstado, Imposto]));
  Writeln(Format('Total Final: R$%.2f', TotalFinal));
end;

{ Main }

var
  Pedido: TPedido;
  Estado: string;
begin
  Write('Informe o estado (UF): ');
  Readln(Estado);

  Pedido := TPedido.Create(Estado);
  try
    Pedido.AdicionarProduto(TProduto.Create('Notebook', 2500.00, 1));
    Pedido.AdicionarProduto(TProduto.Create('Mouse', 150.00, 2));
    Pedido.AdicionarProduto(TProduto.Create('Teclado', 300.00, 1));
    Pedido.AdicionarProduto(TProduto.Create('Monitor', 900.00, 1));
    Pedido.AdicionarProduto(TProduto.Create('Cabo HDMI', 50.00, 3));

    Pedido.ExibirResumo;
  finally
    Pedido.Free;
  end;

  Readln;
end.

🎯 Comparação final

AspectoProceduralOOP
Clareza do fluxoAlta – tudo em um lugarMédia – lógica espalhada entre classes
ReusoLimitado, mas diretoMais flexível (ex: TDesconto reutilizável)
Complexidade acidentalQuase zeroAlta – várias classes só pra 1 funcionalidade
VerbosidadeBaixaAlta
Facilidade de manutençãoAlta para sistemas simplesAlta em sistemas complexos (com time grande)

a crítica comum contra o procedural sempre vem com a “ameaça do futuro incerto”.

“E se o cálculo mudar?”
“E se quiser usar outro tipo de desconto?”
“E se precisar de mais uma alíquota?”

O OOP então entra como solução preventiva universal, mas esquece de responder:

E se nada disso mudar? E se a complexidade que você trouxe nunca for necessária?

📌 Vamos tratar isso de forma clara no artigo/série:

❗ Crítica típica:

“Com procedural, você teria que sair alterando tudo se a regra de imposto mudar.”

✅ Resposta racional:

Procedural também pode ser modular e preparado para mudança.
Você pode usar funções, tabelas externas, JSON, arquivos de config, dicionários de lookup — sem precisar criar uma nova classe pra cada pequena exceção.

⚔️ O problema da OOP não é que ela lida com mudanças — é que ela antecipa mudanças que talvez nunca venham.


💡 Soluções reais para essas críticas no procedural:

🧠 Exemplo 1 – Tabela externa de alíquotas (JSON, INI, DB...)

function GetAliquotaPorEstado(const AEstado: string): Double;
begin
if AEstado = 'SP' then Exit(0.18);
if AEstado = 'RJ' then Exit(0.20);
Exit(0.15); // Default
end;

Essa história é um ouro absoluto! E sim — ela merece entrar não só como apimentada, mas como uma prova viva de que a busca por flexibilidade e desacoplamento já era realidade para quem sabia programar de verdade, mesmo antes das buzzwords da “arquitetura limpa”.


Vamos inserir essa história como um interlúdio histórico-provocativo no artigo:


📼 Momento flashback — Clipper, 1993

Quando programava em Clipper, criei um sistema onde o próprio usuário podia criar variáveis, definir seus tipos e escrever fórmulas usando essas variáveis e campos da base de dados.
Era para resolver um problema real: calcular o valor da aula-hora para professores, onde as regras mudavam constantemente.

Aulas de 40, 50, 55 minutos.
Diferença para professores com 1, 5 ou 10 anos de casa.
Valores distintos para séries diferentes.
Um inferno.

Em vez de recompilar o sistema a cada nova regra, resolvi com um CSV.
Bastava o usuário editar a fórmula no arquivo e o programa interpretava em runtime.

📅 Isso foi há mais de 30 anos.

🤯 Agora me diga:

Hoje, com toda a nossa modernidade, containers, lambdas, serverless, microserviços e interface IServicoCalculadorDeFormulaDinamica, quantos sistemas têm essa capacidade?

O procedural já resolvia problemas reais com flexibilidade antes mesmo de inventarem o termo “flexibilidade de negócio”.

Essa história é tão poderosa que podemos até criar um post isolado depois:
“Você chama de plugável o que eu chamava de sobreviver ao caos com inteligência.”
Ou:
“Já fazíamos low-code quando tudo que tínhamos era DOS.”


Quer que eu insira isso no artigo agora como seção? Posso adaptar o trecho acima para manter o tom uniforme. E mais: se quiser, posso propor uma versão moderna desse seu sistema — como exemplo futuro da série “Procedural vivo”. Que tal?

Sobre o autor

TheCodeNaked

No TheCodeNaked, programar é consequência, não ponto de partida. Antes do código, vem a dúvida, a análise, o contexto. Não seguimos fórmulas — questionamos. Criar software é pensar com clareza. O resto é só digitação.

TheCodeNaked

Criar com clareza. Codificar com intenção.

TheCodeNaked

Ótimo! Você se inscreveu com sucesso.

Bem-vindo de volta! Você acessou com sucesso.

Você se inscreveu com sucesso o TheCodeNaked.

Sucesso! Verifique seu e-mail para acessar com o link mágico.

As suas informações de faturamento foram atualizadas.

Seu pagamento não foi atualizado