> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/construir/padroes-e-antipadroes/antipadroes-o-que-nao-fazer-e-por-que.md).

# Antipadrões: o que não fazer e por quê

Os erros mais comuns em código skail, agrupados pelo mecanismo que eles quebram. Cada item traz o sintoma, a causa e a correção. Se você chegou aqui por uma `SkailNonDeterministicException`, comece pelo primeiro grupo.

## Quebram o replay

| O que não fazer                                                                                                    | Por que quebra                                                                                                                         | Faça assim                                                                                                                                                                                           |
| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **1.** I/O direto na `[SkailFunction]`: `HttpClient`, `DbContext`, publicar em fila, escrever arquivo              | O corpo da function é reexecutado a cada retomada; o efeito acontece de novo e o resultado pode mudar                                  | Mova para um `[SkailCommand]`. O command roda uma vez e o resultado é gravado                                                                                                                        |
| **2.** `DateTime.Now`, `DateTime.UtcNow`, `DateTimeOffset.Now` na function                                         | O relógio muda entre a execução e o replay; um `if` sobre a hora toma outro caminho e o runtime lança `SkailNonDeterministicException` | `var agora = await ObterDataAtual();` com `[SkailCommand] SkailTask<DateTime> ObterDataAtual()`, ou receba a data como parâmetro                                                                     |
| **3.** `Guid.NewGuid()`, `new Random()`, `Environment.TickCount`, `Environment.GetEnvironmentVariable` na function | Valor diferente a cada execução                                                                                                        | Command, ou parâmetro                                                                                                                                                                                |
| **4.** `Task.Delay`, `Thread.Sleep` na function                                                                    | Não registra passo; no replay o runtime não encontra o passo. `Task.Delay` também não hiberna: segura a thread                         | `SkailTask.Delay`, `DelaySeconds`, `DelayMinutes`                                                                                                                                                    |
| **5.** `Task.WhenAll`, `Task.WhenAny`, `Task.Run`, `Parallel.ForEach`, threads na function                         | Concorrência fora do controle do runtime; ordem não reproduzível                                                                       | `SkailTask.WhenAll` / `SkailTask.WhenAny`                                                                                                                                                            |
| **6.** Mudar ordem, quantidade ou tipo dos `await`s de uma function que tem execuções em andamento, sem versionar  | O histórico da execução não bate mais com o código; as execuções antigas falham na retomada                                            | Novo método com `skailMethodName` ou nova versão do workload; a antiga fica publicada até esvaziar. Ver [Versionamento](/aprender/fundamentos/versionamento-de-codigo-com-execucoes-em-andamento.md) |
| **7.** Renomear function ou command que tem execuções em andamento                                                 | O nome faz parte do endereço da execução ("Target method not found")                                                                   | Mesma correção do item 6                                                                                                                                                                             |
| **8.** Lógica pesada de CPU dentro da function (parsear um arquivo de 200 MB, calcular uma folha inteira)          | Reexecutada integralmente a cada replay                                                                                                | Command; o resultado fica memoizado                                                                                                                                                                  |

## Quebram a garantia do command

| O que não fazer                                                                                          | Por que quebra                                                                                                                                                   | Faça assim                                                                                                                                                                       |
| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **9.** Command que faz várias coisas (cobrar, emitir e enviar e-mail no mesmo método)                    | Se a terceira falha, o retry repete as três; a cobrança e a emissão acontecem de novo                                                                            | Um command por operação de I/O                                                                                                                                                   |
| **10.** Confiar em "exatamente uma vez" no efeito externo                                                | Se o command falha depois do efeito e antes de gravar o resultado, roda de novo                                                                                  | Chave de idempotência (id do pedido, da fatura) na chamada externa. Ver [Como escrever commands idempotentes](/construir/escrever-fluxos/como-escrever-commands-idempotentes.md) |
| **11.** Representar falha de negócio como exceção (`throw new CartaoRecusadoException()`)                | Qualquer exceção em command gera nova tentativa até o `retryCount`; uma recusa definitiva é retentada cinco vezes                                                | Devolva um resultado (`ResultadoCobranca.Recusado`) e decida na function                                                                                                         |
| **12.** Laço de retry manual com `try/catch` a cada tentativa dentro da function                         | O runtime já retentou `retryCount` vezes antes de a exceção chegar à function; o laço duplica. E um `throw` no final faz a function ser reentregue mais 15 vezes | Ajuste `retryCount` no command e trate a exceção final uma vez. Ver [Falhas, retries e idempotência](/aprender/fundamentos/falhas-retries-e-idempotencia.md)                     |
| **13.** Capturar `SkailNonDeterministicException` (ou `SkailException` genérica) para "seguir em frente" | Esconde um erro de infraestrutura ou de código e corrompe o fluxo                                                                                                | Deixe propagar; corrija a causa                                                                                                                                                  |

## Quebram a correlação de eventos e o tempo

| O que não fazer                                                                   | Por que quebra                                                                                                    | Faça assim                                                                                                                                            |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **14.** `WaitForEvent` sem timeout                                                | Se o evento nunca chega (webhook perdido, pessoa que não aprovou), a execução fica parada para sempre, sem alarme | `WhenAny(espera, SkailTask.Delay(prazo))` e decida no timeout. Ver [Como esperar com timeout](/construir/escrever-fluxos/como-esperar-com-timeout.md) |
| **15.** `while (true) { ...; await SkailTask.Delay(...); }` sem condição de saída | O histórico da execução cresce sem limite; cada retomada reexecuta um replay maior                                | Limite de iterações e novo trigger para continuar, ou uma function por ciclo.                                                                         |
| **16.** instanceId de evento gerado na hora, ou derivado de dado que muda         | O disparo nunca encontra a espera; execução presa em "aguardando evento"                                          | Id de negócio estável nos dois lados                                                                                                                  |
| **17.** Nome de evento como string literal repetida em vários arquivos            | Um typo e o evento nunca correlaciona                                                                             | Constantes compartilhadas (`Eventos.PagamentoConfirmado`)                                                                                             |
| **18.** Disparar o evento de dentro da própria function com `HttpClient`          | É I/O na function (item 1). E na maioria dos casos quem tem a informação é um sistema externo                     | Quem dispara é o webhook, a tela, o job. Se precisar disparar de dentro, faça em um command                                                           |
| **19.** Depender da ordem de conclusão em `WhenAll`                               | A ordem de término não é garantida nem reproduzível                                                               | Leia os resultados pela posição de cada tarefa                                                                                                        |
| **20.** Criar uma `SkailTask` e não dar `await` nela                              | Se ela hiberna, a execução fica órfã                                                                              | Sempre `await`, direto ou via `WhenAll`/`WhenAny`                                                                                                     |

## Quebram a assinatura ou o modelo

| O que não fazer                                                                                                         | Por que quebra                                                                                                                                                                         | Faça assim                                                                                                                                                                                                           |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **21.** `Task`/`Task<T>` como retorno de método decorado                                                                | Perde a retomada; o analyzer bloqueia (SKAIL001)                                                                                                                                       | `SkailTask` / `SkailTask<T>`                                                                                                                                                                                         |
| **22.** `.Result`, `.Wait()`, `.GetAwaiter().GetResult()`, `.GetResult()` em `SkailTask`                                | Bloqueia a thread e quebra a hibernação; o analyzer aponta (SKAIL003)                                                                                                                  | `await`                                                                                                                                                                                                              |
| **23.** Método `static` com os atributos                                                                                | Não é o modelo; o analyzer bloqueia (SKAIL001)                                                                                                                                         | Método de instância; a classe é registrada no DI automaticamente                                                                                                                                                     |
| **24.** Método decorado sem `async`                                                                                     | Analyzer bloqueia (SKAIL002)                                                                                                                                                           | `public async SkailTask ...`                                                                                                                                                                                         |
| **25.** Método `private` ou `internal` com os atributos                                                                 | O analyzer recusa (SKAIL001, "The X method must be public.")                                                                                                                           | `public`                                                                                                                                                                                                             |
| **26.** Misturar `Task` e `SkailTask` no mesmo fluxo durável (uma function chamando um helper `async Task` que faz I/O) | O trecho em `Task` não é durável: não registra passo, não retenta, não hiberna                                                                                                         | Tudo o que está no caminho durável é function, command ou `SkailTask.*`                                                                                                                                              |
| **27.** Estado em campos da classe, estáticos ou singletons mutáveis entre `await`s                                     | A instância é descartada na hibernação; o estado some                                                                                                                                  | Tudo em parâmetros e retornos de commands                                                                                                                                                                            |
| **28.** Passar um `SkailTask` como parâmetro de function, ou passar entidades de ORM, streams e listas enormes          | Argumentos são serializados e fazem parte da execução; um `SkailTask` não é serializável, e payload grande deixa o replay lento                                                        | Ids e DTOs pequenos; carregue o resto no command                                                                                                                                                                     |
| **29.** Chamar um `[SkailCommand]` de código comum, fora de uma function                                                | Não há execução durável em volta: o command não tem contexto para rodar                                                                                                                | Commands só de dentro de functions                                                                                                                                                                                   |
| **30.** Chamar um `[SkailCommand]` ou uma `[SkailFunction]` de dentro de um `[SkailCommand]`                            | Quem compõe os passos é sempre a function, e commands são chamados só de dentro de functions; um command que chama outro command ou uma function sai do modelo de programação do skail | Se os dois passos precisam ser duráveis separadamente, a function chama os dois em sequência, seja um command ou uma function filha. Para reaproveitar lógica dentro de um command, use métodos comuns, sem atributo |
| **31.** Esquecer `[assembly: VisibleToSkailPlatform]` ou `builder.UseSkail()`                                           | O runtime não descobre os métodos; "StateMachine not registered." ou "There is not Skail runtime available!"                                                                           | Os dois no `Program.cs` (o template já traz)                                                                                                                                                                         |

## Como usar esta página

No code review, procure os itens 1 a 5 primeiro: são os que passam despercebidos e só aparecem em produção, dias depois, na retomada. Os itens 21 a 24 o compilador pega. Os itens 14 a 17 são os que geram chamado de "a execução travou".

## Próximos passos

[Padrões recomendados](/construir/padroes-e-antipadroes/padroes-recomendados.md) é a versão positiva desta lista. [Checklist de revisão de código skail](/construir/padroes-e-antipadroes/checklist-de-revisao-de-codigo-skail.md) resume os dois em uma página para colar no template de pull request. Para uma configuração que já bloqueia parte disto no seu assistente de IA, veja [Usar o skail com assistentes de IA](/usar-o-skail-com-assistentes-de-ia.md).
