Quando o código está uma bagunça, desenvolvedores dizem que ele parece espaguete. Mas o que exatamente é espaguete?
No próximo Code Smell #2, continuamos com o pacote seguinte.
Porque é longo? Porque é bagunçado?
Nenhuma das duas opções. Espaguete se refere ao fluxo de controle.
O significado original era um estado em que a execução fica emaranhada como fios de macarrão, tornando impossível saber para onde ela vai saltar.
O processo de separar um código que mistura fluxo de controle e responsabilidades em um único arquivo continua em Exemplo de aplicação da separação de responsabilidades a um componente de 800 linhas.
Seguindo a origem da expressão, chegamos a uma carta publicada em 1968.
Uma carta escrita por Dijkstra
Em março de 1968, Edsger Dijkstra publicou um texto curto na revista da ACM (Association for Computing Machinery, Associação para Maquinaria de Computação dos Estados Unidos) (Texto original).
O título era “Go To Statement Considered Harmful”. Era uma carta de duas páginas.
O título original dado por Dijkstra era “A Case Against the Go To Statement”. O título provocativo atual foi colocado pelo editor da época, Niklaus Wirth.
Esse formato de título mais tarde se consolidou na expressão “○○ Considered Harmful”, então a mão do editor foi bem longe.
O ponto central é este: as pessoas leem código estático e imaginam mentalmente o processo dinâmico de execução.
Mas, em um código com muitos goto, saber apenas que “esta linha está sendo executada agora” não explica o estado do programa. Não sabemos de onde ele veio.
Código que usa apenas execução sequencial, ramificação condicional e repetição é diferente.
É possível descrever a posição de execução como coordenadas: “terceira iteração do loop externo, ramo verdadeiro do if interno”.
goto destrói esse sistema de coordenadas.
Essa afirmação também tinha respaldo teórico. Dois anos antes, em 1966, Corrado Böhm e Giuseppe Jacopini provaram que qualquer programa pode ser expresso usando apenas sequência, seleção e repetição (Artigo).
A matemática garantiu, assim, que isso é possível mesmo sem goto.
A figura criada por goto
Basta ver como era o código daquela época para entender.
10 IF X > 100 THEN GOTO 70
20 IF X < 0 THEN GOTO 90
30 Y = X * 2
40 IF Y > 50 THEN GOTO 70
50 PRINT Y
60 GOTO 100
70 PRINT "TOO BIG"
80 GOTO 100
90 PRINT "NEGATIVE"
100 END
Mesmo um código de dez linhas exigia desenhar o fluxo no papel para ser compreendido. Cada GOTO era uma linha, e essas linhas se cruzavam para cima e para baixo.
Não é difícil imaginar o que acontece quando chegam a 500 linhas.
Era assim nos códigos BASIC e nos primeiros códigos Fortran das décadas de 1970 e 1980, e o termo espaguete surgiu ao observar aqueles blocos.
goto desapareceu, mas o espaguete ficou
É aqui que acontece algo estranho. O código moderno quase não tem goto.
Swift nem sequer o possui. Nas linguagens que o têm, seu uso se restringiu basicamente a expressões idiomáticas para voltar a pontos de limpeza de recursos.
Ainda assim, a expressão código espaguete é usada cada vez mais.
goto era apenas uma das causas, não o sintoma em si.
O problema real é que o leitor não consegue prever o fluxo, e o código moderno tem muitas outras formas de criar esse problema.
Inferno de aninhamento. Um if dentro de outro if, depois um closure e mais um if.
Como a indentação se aprofunda em forma de seta, isso é chamado de pirâmide da perdição. Não salta como goto, mas é igualmente difícil rastrear a linha alcançada para cada combinação de condições.
Inferno de callbacks. Encadear tarefas assíncronas por callbacks faz o fluxo de execução divergir da ordem do código.
Quando ler de cima para baixo deixa de ser a ordem de execução, o sistema de coordenadas desmorona novamente.
// Não é possível ler a ordem de execução como a ordem do código
loadUser(id) { user in
loadProfile(user) { profile in
loadPosts(profile) { posts in
DispatchQueue.main.async {
self.render(posts) // Em que camada deve ficar o tratamento de erros?
}
}
}
}
Estado global. Se qualquer função pode alterar uma variável a qualquer momento, é preciso vasculhar o projeto inteiro para descobrir por que o valor ficou daquele jeito.
É também por isso que singletons são frequentemente criticados.
Sopa de eventos. A envia uma notificação, B a recebe e altera o estado, e C, que observava esse estado, envia outra notificação.
Cada parte é curta e limpa, mas o fluxo geral não está registrado em lugar algum.
É uma forma comum em código reativo e, em alguns aspectos, mais difícil de rastrear do que goto. O destino do salto não está escrito no código.
Dá para medir com números?
“Este código parece espaguete” é uma afirmação subjetiva. Por isso, em 1976, Thomas McCabe propôs a métrica chamada Complexidade Ciclomática (Cyclomatic Complexity) (Artigo).
O cálculo é simples: desenhe o fluxo de controle do código como um grafo e conte quantos caminhos independentes existem.
Na prática, aproxima-se somando 1 ao número de pontos de ramificação. Cada if, for, while, case, && e ?? acrescenta aproximadamente 1.
É comum considerar que, quando o valor passa de 10, chegou a hora de dividir a função. O próprio McCabe apresentou esse número como um limite superior razoável, não como um padrão absoluto.
Na prática, uma função que lista 20 casos com um único switch ultrapassa a complexidade 20, mas pode ser fácil de ler.
A regra cyclomatic_complexity do SwiftLint mede um valor semelhante.
No entanto, o SwiftLint conta apenas if, guard, for, while, repeat, case e catch; não conta && nem ??. O limite padrão de aviso é 10.
Ative isso no projeto e uma função que crescia silenciosamente será detectada algum dia.
A réplica de Knuth
Encerrar essa história com “Dijkstra venceu” é conhecer apenas metade dela.
Em 1974, Donald Knuth apresentou uma réplica em um longo artigo chamado “Structured Programming with go to Statements” (Artigo).
A ideia era que goto não é mau por si só. Em situações como sair de loops aninhados de uma vez, usar goto pode deixar o fluxo mais claro.
Se você tentar eliminá-lo à força criando uma variável sinalizadora booleana e adicionando condicionais, o resultado será um código pior.
A conclusão das linguagens atuais é um meio-termo: eliminar saltos ilimitados, mas criar sintaxe específica para padrões frequentes.
break, continue, break label com rótulo e defer e guard do Swift são exemplos.
// guard: Remova as exceções no início e mantenha o corpo plano
func process(_ data: Data?) throws -> Packet {
guard let data else { throw ParseError.empty }
guard data.count > headerSize else { throw ParseError.tooShort }
// A partir daqui, todas as condições já foram resolvidas
return try decode(data)
}
guard se aproxima do padrão goto cleanup da época do C que se consolidou como recurso da linguagem. O destino do salto é fixado em um único ponto, que recebe um nome.
Resumo
- Código espaguete não é código bagunçado, mas código cujo fluxo de controle não pode ser previsto.
- O ponto de partida foi a carta de Dijkstra de 1968, cujo argumento central era: “é preciso conseguir descrever a posição de execução como coordenadas”.
gotodesapareceu, mas aninhamento profundo, callbacks aninhados, estado global e cadeias de eventos recriam o mesmo problema.- É possível medi-lo aproximadamente com complexidade ciclomática, e algo perto de 10 é um limite de aviso comum.
- Como Knuth argumentou, o objetivo não é erradicar
goto, mas tornar o fluxo previsível.guardeasync/awaitsão mecanismos que a linguagem oferece para preservar esse objetivo.
No próximo artigo, veremos código quebrado na direção oposta. O fluxo é muito organizado, mas adicionar um valor exige alterar sete arquivos.
É o código lasanha.
Continue lendo
Fontes e verificação
- Go To Statement Considered HarmfulEdsger W. Dijkstra Archive · Fonte original do autor · Consultado 17 de agosto de 2026Evidência: A crítica a goto em 1968 e o problema de inferir o fluxo de controle
- Flow Diagrams, Turing Machines and LanguagesCorrado Böhm·Giuseppe Jacopini · Artigo científico · Consultado 17 de agosto de 2026Evidência: A capacidade de expressão das estruturas sequencial, de seleção e de repetição em 1966
- A Complexity MeasureThomas J. McCabe · Artigo científico · Consultado 17 de agosto de 2026Evidência: A definição de complexidade ciclomática e os grafos de fluxo de controle em 1976
- Structured Programming with go to StatementsDonald E. Knuth · Artigo científico · Consultado 17 de agosto de 2026Evidência: Programação estruturada e o papel limitado de goto em 1974

![Imagem de capa de [Code Smell #1] Por que código espaguete é espaguete?](/assets/images/posts/a1c72f38-347f-4ee2-8e53-9a021038d44f/spaghetti-code-1.jpg)