Módulo 14 - Imutabilidade e efeitos: código previsível
Previsibilidade e concorrência: rodar em paralelo
8 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 12/07/2026
O que você vai aprender
- Entender o que é concorrência e por que ela introduz bugs difíceis.
- Identificar a condição de corrida como disputa por dado compartilhado mutável.
- Ligar pureza e imutabilidade à segurança em paralelo.
- Fechar o módulo: previsibilidade é a base do código que dura.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Previsibilidade e concorrência: rodar em paralelo.
Os objetivos desta aula. Entender o que é concorrência e por que ela introduz bugs difíceis. Identificar a condição de corrida como disputa por dado compartilhado mutável. Ligar pureza e imutabilidade à segurança em paralelo. Fechar o módulo: previsibilidade é a base do código que dura.
Veja o essencial, parte por parte.
Várias tarefas ao mesmo tempo. Concorrência é rodar várias tarefas ao mesmo tempo para ir mais rápido.
Pureza e imutabilidade abrem a porta. Aqui as duas ideias do módulo se encontram e mostram para que serviam.
O fio que liga o módulo. Pureza e imutabilidade são ferramentas, não dogmas: use onde o ganho compensa o custo.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Várias tarefas ao mesmo tempo
Computadores modernos têm vários núcleos, e usar todos ao mesmo tempo faz o trabalho render. Isso é concorrência: em vez de uma fila única de passos, várias tarefas avançam em paralelo. O ganho é real, mas vem com um perigo específico. Quando duas tarefas mexem no mesmo dado mutável ao mesmo tempo, o resultado passa a depender de quem chegou primeiro, e essa ordem é imprevisível. É como duas pessoas editando a mesma frase de um caderno na mesma hora: o que sobra na página vira sorte. Esse é o bug conhecido como condição de corrida, e ele é dos mais odiados porque muda a cada execução e some quando você tenta observá-lo.
O exemplo canônico é um simples contador compartilhado. Duas tarefas leem o valor, somam um e escrevem de volta. Se ambas leem o mesmo número antes de qualquer uma escrever, as duas gravam o mesmo resultado, e uma das somas se perde. O contador que deveria ir de dez para doze para em onze. Ninguém escreveu código errado; o erro nasce da ordem em que os acessos ao dado compartilhado se cruzaram. Reproduzir isso é penoso, porque depende de um encontro exato no tempo. Quanto mais dado mutável compartilhado, mais oportunidades para essas colisões.
Pureza e imutabilidade abrem a porta
Aqui as duas ideias do módulo se encontram e mostram para que serviam. A condição de corrida precisa de dois ingredientes: dado compartilhado e mutação. Tire qualquer um dos dois e o bug não tem como nascer. Dado imutável não pode ser alterado no meio da disputa, então várias tarefas podem lê-lo à vontade, ao mesmo tempo, sem risco: ninguém muda o que o outro está lendo. Função pura não mexe em nada por fora, então rodar mil funções puras em paralelo é seguro, porque nenhuma delas pisa no dado da outra. A previsibilidade que parecia só elegância vira uma vantagem concreta: código puro e imutável é fácil de paralelizar porque não há nada compartilhado para disputar.
// Risco: contador MUTÁVEL compartilhado entre tarefas concorrentes
contador <- 10
// tarefa A e tarefa B, ao mesmo tempo:
// leem 10, somam 1, escrevem 11 -> uma soma se perde
// Seguro: cada tarefa trabalha uma CÓPIA IMUTÁVEL e devolve seu resultado
parcialA <- processar(loteA) // não toca em dado de B
parcialB <- processar(loteB) // não toca em dado de A
total <- parcialA + parcialB // combina no fim, sem disputaSem dado mutável compartilhado, as tarefas rodam em paralelo e só juntam os resultados no fim.
🎮 Jogo da aula
Concorrência sem susto
Julgue cada afirmação sobre concorrência, pureza e imutabilidade.
O fio que liga o módulo
Vale amarrar as pontas. Começamos escolhendo entre mudar um dado no lugar ou gerar uma cópia, e vimos que dado imutável evita mudanças por acidente à distância. Depois abrimos a função pura, que só depende dos argumentos e não toca o mundo, o que a torna previsível e trivial de testar. Em seguida, aceitamos que efeitos são necessários e aprendemos a isolá-los na borda, guardando um miolo puro. Agora fechamos mostrando o prêmio maior: essa previsibilidade toda é o que permite rodar em paralelo com segurança. O fio comum é um só, previsibilidade. Código previsível é mais fácil de entender, testar, mudar e paralelizar. Não é enfeite acadêmico; é o que faz um programa durar sem virar um campo minado a cada alteração.
Teste rápido
Por que código puro e dados imutáveis facilitam rodar tarefas em paralelo com segurança?
Perguntas frequentes
- Qual a diferença entre concorrência e paralelismo?
- Concorrência é estruturar o programa em tarefas que avançam de forma independente, mesmo que se intercalem num só núcleo. Paralelismo é executar de fato ao mesmo tempo, usando vários núcleos. Na prática o risco da disputa por dado é parecido nos dois. Para esta aula, o que importa é que várias tarefas mexendo no mesmo dado mutável abre a porta para o bug.
- Como uma condição de corrida some quando tento depurá-la?
- Porque ela depende de um encontro exato no tempo entre as tarefas. Ao rodar o depurador, você muda a velocidade e a ordem dos acessos, e o encontro que causava o bug deixa de acontecer. Por isso esses bugs têm fama de fantasmas: aparecem em produção sob carga e desaparecem quando você olha de perto. Reduzir o dado compartilhado é o remédio mais confiável.
- Imutabilidade elimina a necessidade de travas e sincronização?
- Reduz bastante, mas não sempre elimina. Se as tarefas só leem dado imutável e trabalham cópias próprias, você dispensa travas para esse dado. Quando, no fim, os resultados precisam ser combinados ou algo mutável é de fato compartilhado, ainda pode caber sincronização. A imutabilidade encolhe a área onde travas são necessárias, o que já simplifica muito o problema.
- Se eu não escrevo código concorrente, isso me importa?
- Importa, porque muita concorrência é escondida. Servidores atendem vários usuários ao mesmo tempo, interfaces respondem a eventos enquanto processam, bibliotecas paralelizam por baixo. Escrever lógica pura e evitar dado mutável compartilhado te protege dessas armadilhas mesmo sem você criar tarefas de propósito. É uma rede de segurança para um risco que aparece sozinho conforme o programa cresce.
- Pureza sozinha basta para o paralelo ser seguro?
- Pureza e imutabilidade caminham juntas aqui. Uma função pura não altera estado externo, e dado imutável não pode ser alterado por ninguém. Combinadas, elas garantem que nenhuma tarefa muda o que a outra usa. Se você tem funções puras mas ainda deixa um dado mutável compartilhado no meio, o risco volta. As duas ideias se reforçam para dar a segurança completa.
- Esse foi o último tema teórico do curso?
- Este módulo fecha o bloco sobre organizar código que dura: abstração, invariantes, imutabilidade e efeitos. O que vem a seguir é o projeto final, onde toda a trilha se junta num sistema de verdade. A previsibilidade que você viu aqui volta na prática, porque um projeto bem organizado se apoia justamente em partes puras, dados claros e efeitos isolados.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.