DNATech :: 🚀 Otimizando Código ADVPL: Boas Práticas de Performance, Caching, Escopo e **Loops Claros** – Guia Prático e Leve

_Créditos das imagens: ChatGPT

Em 2025 ainda existe muito código Legado AdvPL que pode ser otimizado.

Como tornar o código **ADVPL mais rápido, limpo e profissional** — com **exemplos fictícios**, dicas práticas e **boas práticas que todo mundo pode (e deveria!) adotar**.

Vamos aos 5 pilares de hoje:

1. 🔁 **Evite chamadas repetidas em loops**  
2. 🧠 **Cacheie o que for constante (Cache preditivo: + static/local)**  
3. 🛡️ **Use `local` ao invés de `private`**  
4. 🔁 **Escreva `while` que você entende de primeira**  
5. 🎯 **Resolve o campo dinâmico uma vez só***
6. 🧠 **Pense como o interpretador pensa**

---

## 1. O Vilão dos Loops: "Ei, função, posso entrar?"

```advpl
// Exemplo fictício: 1000 pedidos
For nI := 1 To 1000
    if SC5->C5_FILIAL==xFilial("SC5")  // 1000 chamadas Empilhando e Desempilhando!
        ...
    endif
Next
```

O que acontece?

A cada iteração, o ADVPL:

Empilha o estado
Chama xFilial()
Desempilha

1000 vezes = 1000 viagens de elevador

para que, para obter um valor constante que não mudará durante o laço.

**Solução:**
```advpl
local cSC5Filial := xFilial("SC5")  // 1 vez só!
For nI := 1 To 1000
    if SC5->C5_FILIAL==cSC5Filial  // 1000 chamadas Lendo uma constante!
        ...
    endif
Next
```

> **Ganho**: até **15% mais rápido**.

---

## 2. Cache com `static` – "Já sei disso!"

```advpl
static lIsUnix := IsSrvUnix()
```

> `static` = **post-it na geladeira**: cola uma vez, usa sempre.

---

## 3. `private` vs `local`: Escopo Seguro

```advpl
// Ruim: vaza e pode ser alterado
private cCliente := "ACME"

// Bom: isolado e rápido
local cCliente := "ACME"
```

> `local` = **caixa-forte**: só você abre.

---

## 4. O Monstro do `while !(alias)->(Eof())` – Herança dos Padrões

### Versão herdada (confusa e lenta):
```advpl
while !(cAlias)->(Eof()) .and. (cAlias)->FILIAL==xFilial(cAlias) .AND. (cAlias)->FIELD1 == "X" .AND. (cAlias)->FIELD2 == "Y"
    // o que eu estou negando mesmo?
    (cAlias)->(DbSkip())
enddo
```

### Problemas:
- **`!(alias)->(Eof())`** → "não não é fim" → **dupla negação**
- **`(cAlias)->`** repetido **3x por linha**
- **Não se vê o alias principal de cara**
- **Mais lento**: o interpretador precisa avaliar o alias toda vez

---

### Versão clara, rápida e profissional:
```advpl
cAliasFilial:=xFilial(cAlias)
while (cAlias)->(!Eof() .and. FILIAL==cAliasFilial .AND. FIELD1 == "X" .and. FIELD2 == "Y")
    (cAlias)->(DbSkip())
enddo
```

### Melhorias:
| Antes                               | Depois                                     | Ganho                                                |
|-------------------------------------|--------------------------------------------|------------------------------------------------------|
| `!(cAlias)->(Eof())`                | `(cAlias)->(!Eof())`                       | **Clareza + velocidade**                             |
| `(cAlias)->FIELD1+(cAlias)->FIELD2` | `(cAlias)->(FIELD1+FIELD2)`                | **Menos digitação + menos avaliação + legibilidade** |

> **Regras de ouro**:  
>> **Use o Operador ! junto ao que você quer negar. Torna o código mais legível. Ex. !Eof() e não !(cAlias)->(Eof()) Tem um caminhão de distância aqui.**

>> **Se o alias já está posicionado, use `->` só no `while`. Dentro do bloco, use campos diretos. Ex.: (cAlias)->(FIELD1,FIELD2,FIELDN)**

---

### Exemplo completo (fictício):
```advpl
// Posiciona no alias
(cAlias)->(DbSetOrder(1))
(cAlias)->(DbSeek(cChave))

// Loop limpo e rápido
while (cAlias)->(!Eof() .and. PEDIDO == cPedido .and. STATUS $ "AB")
    ProcessaItem()
    (cAlias)->(DbSkip())
enddo
```

--- 

## 5. Campo Dinâmico: FieldPos() + FieldGet()
```advpl// Exemplo: volumes em campos F2_VOLUME1, F2_VOLUME2...

cScan := "1"
While ( !Empty(cScan) )
    cEspecie := Upper(FieldGet(FieldPos("F2_ESPECI"+cScan)))
    If !Empty(cEspecie)
        nScan := aScan(aEspVol,{|x| x[1] == cEspecie})
        If ( nScan==0 )
            aadd(aEspVol,{ cEspecie, FieldGet(FieldPos("F2_VOLUME"+cScan)) , SF2->F2_PLIQUI , SF2->F2_PBRUTO})
        Else
            aEspVol[nScan][2] += FieldGet(FieldPos("F2_VOLUME"+cScan))
        EndIf
    EndIf
    cScan := Soma1(cScan,1)
    If ( FieldPos("F2_ESPECI"+cScan) == 0 )
        cScan := ""
    EndIf
EndDo
```
Otimizado:

```advpl
cScan:="1"
while ((nF2Scan:=SF2->(FieldPos("F2_ESPECI"+cScan)))>0)
    cEspecie:=SF2->(FieldGet(nF2Scan))
    If !Empty(cEspecie)
        nScan:=aScan(aEspVol,{|x| x[1] == cEspecie})
        If (nScan==0)
            SF2->(aadd(aEspVol,{cEspecie,FieldGet(FieldPos("F2_VOLUME"+cScan)),F2_PLIQUI,F2_PBRUTO}))
        Else
            aEspVol[nScan][2] += SF2->(FieldGet(FieldPos("F2_VOLUME"+cScan)))
        EndIf
    EndIf
    cScan:=__Soma1(cScan)
EndDo
```

### Melhorias:
Menos código, menos chamadas, mais velocidade.

> **Regras de ouro**:  
>> **Resolva o campo Dinâmico apenas uma vez**

---

## 6. Checklist Rápido (Cole na sua mesa!)

```advpl
[ ] xFilial() está FORA de loops?
[ ] Usei LOCAL ao invés de PRIVATE?
[ ] Cacheei com STATIC o que é constante?
[ ] FieldPos() está em variável (nPos)?
[ ] Usei __Soma1() em vez de Soma1()?
[ ] Evitei funções "leves" e que retornam constantes dentro de loops?
[ ] while usa (alias)->(!Eof()) e não !(alias)->(Eof())?
[ ] Dentro do while, uso campos diretos (sem (alias)->)?
[ ] Testei com 100+ registros?
```

---

## Exemplos Práticos para Copiar e Colar

```advpl
// 1. Cache de filial
local cSC5Filial := xFilial("SC5")

// 2. Cache de ambiente
static lWindows := !IsSrvUnix()

// 3. Loop limpo e rápido
while (cAlias)->(!Eof() .and. STATUS == "P")
    (cAlias)->(DbSkip())
enddo

// 4. Campo dinâmico otimizado
local cSeq := "1"
while ((nPos := FieldPos("F2_VOLUME"+cSeq))) > 0
    nTotal += FieldGet(nPos)
    cSeq := __Soma1(cSeq)
enddo
```

---

## Dica Final: Seja o Exemplo

> Muitos códigos "padrão" (de qualquer origem) têm **hábitos antigos**.  
> Mas **você não precisa herdar o que não presta**.

**Escreva como se alguém fosse ler amanhã.**  
**Escreva como se fosse rodar em 10.000 registros.**

> **Um bom código não é só funcional — é rápido, claro e fácil de entender.**

---

## Conclusão

Pequenas mudanças = **grandes resultados**:

- **Menos chamadas** → mais velocidade  
- **Menos `private`** → menos bugs  
- **Menos `(alias)->`** → mais clareza  
- **Mais `local`, `static` e `!Eof()`** → mais profissionalismo

> **Você não precisa reescrever tudo. Só precisa melhorar uma linha por vez.**

---

**Quer mais?**  
> **Mande um `while` confuso do seu código** (pode ser fictício!) e eu mostro **como deixar cristalino**.

---

Fique ligado!  
*Naldo DJ – Seu parceiro em código limpo, rápido e eficaz.*

Torne-se um Sponsor: 🥊(дави)={0.5x[(Налдо)+(Алине)]}🥊

Comentários

Postagens mais visitadas