Quando o código está uma bagunça, desenvolvedores dizem que ele parece espaguete. Mas o que exatamente é espaguete?
No próximo artigo, Code Smell #2, continuamos analisando o pacote a seguir.
Porque é longo? Porque é bagunçado?
Nenhum dos dois. Espaguete se refere ao fluxo de controle.
É o estado em que, ao acompanhar a ordem de execução, o fluxo se enreda como macarrão e você não sabe para onde ele vai saltar.
O processo de separar código com fluxo de controle e responsabilidades misturados em um único arquivo continua em Caso de aplicação da separação de responsabilidades a um componente de 800 linhas.
Seguindo a origem do termo, chegamos a uma carta publicada em 1968.
Uma carta escrita por Dijkstra
Em março de 1968, Edsger Dijkstra publicou um texto curto no periódico da ACM (Association for Computing Machinery, Associação para Máquinas de Computação) (Artigo 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 alterado 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 bastante longe.
O ponto central era este: as pessoas leem código estático e imaginam mentalmente o processo dinâmico de execução.
Mas, em código com muitos goto, saber apenas que “esta linha está sendo executada agora” não explica o estado do programa. Você não sabe de onde veio.
Código que usa apenas execução sequencial, desvios condicionais e loops é diferente.
É possível descrever a posição de execução como coordenadas: “terceira iteração do loop externo, ramo verdadeiro do if interno”.
gotodestró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).
Ficou matematicamente garantido que isso era possível mesmo sem goto.
O desenho criado por goto
Basta ver como era o código naquela é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 com dez linhas, era preciso desenhar o fluxo no papel para compreendê-lo. 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.
Foi assim nos códigos BASIC e Fortran iniciais das décadas de 1970 e 1980, e espaguete foi o nome dado àquela massa emaranhada.
goto desapareceu, mas o espaguete permaneceu
É 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 a expressões idiomáticas como retornar a pontos de limpeza de recursos.
Mesmo assim, o termo código espaguete é usado com ainda mais frequência.
goto era uma causa, não o problema em si.
O problema real é que o leitor não consegue prever o fluxo, e o código moderno tem muitas outras formas de produzir isso.
Inferno de aninhamento. Um if dentro de outro if, um closure dentro dele e outro if dentro do closure.
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 por cada combinação de condições.
Inferno de callbacks. Encadear tarefas assíncronas com callbacks faz a ordem 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, você precisa vasculhar o projeto inteiro para descobrir por que o valor chegou àquele estado.
É 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 no código reativo e, em certo sentido, mais difícil de rastrear que goto, porque o destino do salto não está escrito no código.
É possível medir com um número?
“Este código parece espaguete” é uma afirmação subjetiva. Por isso, em 1976, Thomas McCabe propôs a métrica Complexidade Ciclomática (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 adicionando 1 ao número de pontos de desvio. Cada if, for, while, case, && e ?? adiciona aproximadamente 1.
Uma convenção comum considera que, acima de 10, é hora de dividir a função. O próprio McCabe apresentou esse número como um limite superior razoável, não como um critério absoluto.
Na prática, uma função que enumera 20 casos com um único switch pode ultrapassar a complexidade 20 e ainda ser fácil de ler.
A regra cyclomatic_complexity do SwiftLint mede um valor semelhante.
Porém, 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 contestação de Knuth
Encerrar essa história com “Dijkstra venceu” é conhecer apenas metade dela.
Em 1974, Donald Knuth apresentou uma contestação em um longo artigo intitulado “Structured Programming with go to Statements” (Artigo).
A ideia era que goto em si não é um mal. Em situações como sair de loops aninhados de uma só vez, usar goto pode deixar o fluxo mais claro.
Tentar removê-lo criando uma variável de flag booleana e adicionando condicionais resulta em código pior.
A conclusão das linguagens atuais se aproxima de um meio-termo: elimina saltos ilimitados, mas oferece 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 principal 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á estão resolvidas
return try decode(data)
}
guard se aproxima do padrão goto cleanup da era do C consolidado como recurso da linguagem. O destino do salto é fixado em um único lugar e 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.
- A carta de Dijkstra de 1968 foi o ponto de partida, e seu argumento central era que “a posição de execução deve poder ser descrita 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 próximo de 10 é uma linha de aviso comum.
- Como Knuth argumentou, o objetivo não é a erradicação de
goto, mas a previsibilidade do fluxo.guardeasync/awaitsão mecanismos que fazem a linguagem proteger esse objetivo por você.
No próximo artigo, veremos código quebrado na direção oposta. O fluxo é perfeitamente organizado, mas adicionar um valor exige alterar sete arquivos.
É 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 de 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)