Desenvolvimento

ADVPL vs TLPP: quando usar cada tecnologia

As duas linguagens convivem no mesmo ambiente TOTVS. Escolher a certa evita manutenção cara e código frágil.

ADVPL é a linguagem estrutural clássica do Protheus; TLPP é a extensão orientada a objetos. Elas não competem — se complementam. O problema aparece quando se usa a errada para o problema certo.

ADVPL: rápido, direto e onipresente

Para customizações pontuais, pontos de entrada e rotinas de pequeno porte, ADVPL é imbatível: baixo custo de escrita, execução direta e qualquer desenvolvedor Protheus lê o código.

  • Pontos de entrada (PEs) e validações simples.
  • Jobs e rotinas lineares sem estado.
  • Manutenção de legados existentes — a maioria da base instalada é ADVPL.

TLPP: organização para sistemas que crescem

Quando a regra de negócio ganha volume — validações compartilhadas, integrações com múltiplos canais, regras fiscais complexas — TLPP entrega o que ADVPL estrutural não consegue: encapsulamento, herança simples e organização em camadas.

  • Serviços e APIs com camadas (controle + regra + acesso a dados).
  • Regras reutilizadas em várias rotinas sem copiar código.
  • Equipes maiores, onde o código precisa ser autodocumentado.
Nota sobre herança: TLPP suporta herança simples (single inheritance). Não espere herança múltipla como em Java ou C#. Para compor comportamentos, use interfaces ou composição de classes.

Comparação lado a lado

Veja a mesma regra — cálculo de desconto por faixa de volume — implementada nas duas linguagens:

ADVPL Estrutural — Cálculo de desconto
User Function CalcDesc(nQtd, nPreco)
  Local nDesc := 0

  If nQtd >= 100
    nDesc := nPreco * 0.15
  ElseIf nQtd >= 50
    nDesc := nPreco * 0.10
  ElseIf nQtd >= 20
    nDesc := nPreco * 0.05
  EndIf

Return nDesc
TLPP — Mesma regra com classe
// TLPP — Mesma regra com classe
#Include "totvs.ch"

Class CalculadoraDesconto
  Data nQtd    As Numeric
  Data nPreco  As Numeric

  Public Method New(nQtd, nPreco)
  Public Method Calcula()
EndClass

Method New(nQtd, nPreco) Class CalculadoraDesconto
  ::nQtd   := nQtd
  ::nPreco := nPreco
Return Self

Method Calcula() Class CalculadoraDesconto
  Local nDesc := 0

  If ::nQtd >= 100
    nDesc := ::nPreco * 0.15
  ElseIf ::nQtd >= 50
    nDesc := ::nPreco * 0.10
  ElseIf ::nQtd >= 20
    nDesc := ::nPreco * 0.05
  EndIf

Return nDesc

// Uso:
// ATENÇÃO: instancie com parênteses — CalculadoraDesconto():New(...)
// (no TLPP, a classe é chamada com () antes de :New; sem () não compila)
Local oCalc := CalculadoraDesconto():New(80, 150)
nDesc := oCalc:Calcula()

A versão ADVPL tem 10 linhas. A TLPP tem 25. Para uma regra pontual, ADVPL vence. Mas quando essa regra precisa ser reusada em 15 rotinas diferentes, a classe TLPP se paga em uma semana.

Nota sobre o exemplo: classes reais de produção incluem #Include "totvs.ch" e, quando derivam de outra classe, o construtor chama _Super:New() antes de inicializar os próprios dados. O exemplo acima está simplificado para focar na comparação.

Onde TLPP é obrigatório

No Protheus moderno, existem contextos onde TLPP não é opcional — é obrigatório:

  • MVC (Model-View-Controller): telas de cadastro usam classes Model e Grid. O framework exige TLPP.
  • Integrações fiscais via TSS (TOTVS Sped Service): o serviço que gerencia NF-e/CT-e/MDF-e trabalha com classes.
  • PO-UI Backend: APIs REST que alimentam o PO-UI são mais organizadas com classes de serviço.
  • Regras fiscais complexas: cálculo de impostos com múltiplas exceções se beneficia de herança e polimorfismo.

Performance: TLPP é mais lento?

Não. O overhead de TLPP vs ADVPL é desprezível em operações normais. A diferença aparece apenas em:

  • Milhares de objetos instanciados em loop: criar 10k objetos TLPP em um loop tem overhead vs vetores ADVPL.
  • Introspecção pesada: usar ClassDataArr() em loop pode ser lento.

Na prática: a maioria dos cenários de negócio não nota diferença. Meça o seu caso antes de atribuir lentidão à linguagem — normalmente o gargalo está em query, índice ou E/S, não em TLPP.

Critérios objetivos de escolha

Um bom exercício é responder: a regra será reutilizada? Vai crescer? Precisa de teste isolado?

Se regra é pontual e sem reuso  -> ADVPL (PE / rotina curta)
Se regra é compartilhada e cresce -> TLPP (classe + serviço)
Se é legado e estável            -> manter ADVPL, extrair só o que muda
Se é API/integração              -> TLPP para o contrato, ADVPL no ponto de entrada
Se é MVC ou PO-UI                -> TLPP obrigatório

Armadilhas comuns

  • TLPP por moda: transformar um PE de 20 linhas numa árvore de classes é desperdício.
  • ADVPL gigante: uma rotina de 2.000 linhas estruturais é impossível de manter — nesse ponto, TLPP.
  • Mistura sem critério: o ambiente aceita as duas, mas a decisão precisa ser documentada no código.
  • Esperar herança múltipla: TLPP não suporta. Use composição ou interfaces.

Na prática, a regra que usamos: ADVPL para intervenções cirúrgicas, TLPP para engenharia de software. O resultado é código que o próximo desenvolvedor entende sem susto.

Quer revisar a arquitetura do seu desenvolvimento Protheus?

Falar com a ELP