Migração de dados entre serviços: estratégias, riscos e trade-offs
Source: Dev.to
Contexto
Recentemente precisei migrar dezenas de milhares de registros de auditoria entre dois serviços durante uma task! Era minha primeira vez fazendo uma migração de dados, ainda mais dessa escala, e aprendi bastante coisa, então decidi registrar tudo neste artigo.
Basicamente, uma migração de dados envolve pegar um conjunto de informações que estão armazenadas em uma determinada base (seja um banco de dados, uma planilha ou outro formato) e transformá‑las para que possam ser consumidas corretamente por outro serviço, respeitando o modelo e as regras esperadas no destino.

Motivações para migração
- Dados legados que precisam ser movidos para um novo serviço.
- Sistemas diferentes que passam a compartilhar responsabilidades e precisam de uma interseção consistente de dados.
- Planejamento prévio, que permite mais tempo para análise e execução.
- Demandas urgentes, como solicitações de clientes, de um setor ou necessidades operacionais inesperadas.
A decisão de migrar pode partir tanto do time de produto quanto da engenharia. Ainda assim, é responsabilidade do time de engenharia avaliar e bater o martelo sobre a viabilidade técnica da migração! Essa viabilidade depende diretamente do estudo que fazemos sobre os dados disponíveis.
Por exemplo, quando a demanda vem de produto, normalmente existe um espaço maior para a engenharia investigar complexidade, riscos e custos. Mas nada disso se resolve apenas com um “dá pra migrar, galera! deixa que eu resolvo”. Antes de qualquer compromisso, é muuuuito importante analisar volumetria, estrutura e complexidade dos dados envolvidos.

Um exemplo claro: vale a pena paralisar um ou dois devs por DUAS sprints para migrar 15 registros? Na maioria dos cenários, não. O custo de engenharia pode ser alto demais para um impacto pequeno no produto.
Claro que viabilidade não se resume apenas a números. O contexto do produto também importa. Perguntas que ajudam na decisão:
- Que tipo de dado está sendo migrado?
- São dados simples ou recursivos?
- Existem dependências entre registros?
- Há estados intermediários, históricos ou regras de negócio acopladas a esses dados?
Tudo isso influencia diretamente na decisão.
Etapas da migração
Quando a migração é considerada viável, o conjunto de problemas que precisam ser resolvidos costuma se dividir em três grandes etapas:
- Extração – Como os dados serão puxados?
- Transformação – Como esses dados serão adaptados para o formato esperado?
- Carregamento – Como os dados transformados serão enviados para o serviço de destino?
Foi nesse contexto que eu aprendi sobre ETL, uma abordagem criada justamente para organizar e estruturar esse tipo de processo (Parabéns, você também aprendeu o que é ETL! :))

Ainda assim, é importante reforçar: ETL não é bala de prata. Em muitos casos, criar uma aplicação dedicada para migração pode ser uma complexidade desnecessária. Antes de qualquer implementação, é essencial estudar a viabilidade real da migração, entender o formato dos dados de origem, o esforço de transformação e o custo de manter essa solução.
De forma geral, ETLs fazem mais sentido quando a migração precisa ser executada mais de uma vez ou reaproveitada no futuro. Para migrações pontuais, uma solução mais simples pode ser suficiente e mais segura.
Estratégias
Migrações menores
Quando estou lidando com migrações menores, costumo optar por soluções simples. Em especial, gosto bastante de usar Jupyter Notebook, principalmente quando os dados de origem estão em planilhas ou em bases pequenas. Nesses cenários, não vejo muito sentido em construir uma aplicação inteira só para executar um processo pontual.
Criar um notebook é relativamente simples: basta um arquivo com extensão .ipynb e um kernel configurado localmente. Dependendo do contexto, dá para usar Kotlin, Python, Deno, entre outras opções. A grande vantagem aqui é a rapidez para explorar os dados, testar transformações e iterar sem muitas dificuldades.

Migrações mais complexas
Para migrações mais complexas, minha preferência passa a ser criar uma aplicação local que roda via terminal — uma CLI simples, mas controlada. Esse tipo de abordagem permite:
- Mais previsibilidade e controle de execução;
- Facilidade para lidar com grandes volumes de dados;
- Possibilidade de versionamento e automação (ex.: scripts de CI/CD).
A estrutura típica de uma CLI de migração inclui:
- Parser de argumentos – para receber parâmetros como data de início/fim, filtros, modo “dry‑run”, etc.
- Camada de extração – conectores a bancos, APIs ou arquivos.
- Camada de transformação – funções puras que recebem um registro e retornam o formato desejado.
- Camada de carregamento – inserção em lote, escrita em arquivos, chamadas a APIs de destino.
- Logging & métricas – para auditoria e monitoramento do progresso.
Conclusão (primeira)
- Avaliar a viabilidade da migração antes de iniciar é essencial – considere volume, complexidade, dependências e custo de engenharia.
- ETL é uma ferramenta poderosa, mas só deve ser adotada quando houver necessidade de reutilização ou execução recorrente.
- Para migrações pontuais e de pequeno porte, Jupyter Notebook ou scripts ad‑hoc são mais ágeis.
- Para migrações de grande escala ou que exigem controle fino, CLI ou pequenas aplicações dedicadas são a escolha mais segura.
[](https://media2.dev.to/dynamic/image/width=800,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8w59uslh300rzxxop5e.png)
Aqui, uma preocupação fundamental é ter uma estratégia de rollback. Nunca dá para assumir que a migração vai rodar perfeitamente de primeira. Sempre que possível, vale testar em ambiente de staging antes de executar em produção, além de alinhar muito bem o rollout com o time.
A forma de carregar os dados também faz diferença. Em alguns casos, inserir diretamente no banco pode ser suficiente. Em outros, usar uma API ou até publicar eventos em fila é mais seguro, principalmente quando estamos lidando com grandes volumes e queremos processar tudo de forma assíncrona.
No fim das contas, o formato do ETL importa menos do que o objetivo final. Ele pode ser um notebook, uma CLI ou até um script simples — desde que atenda às necessidades de extração, transformação e carregamento de forma segura e previsível.
Desafios práticos que você vai enfrentar
Dados faltando ou inconsistentes
Em migrações reais, é muito comum encontrar dados incompletos, inconsistentes ou marcados como removidos (ex.: soft delete). Esses cenários precisam ser tratados explicitamente, seja ignorando registros, preenchendo valores padrão ou sinalizando dados desconhecidos.
Enriquecimento de dados
Nem sempre todas as informações necessárias estão em um único lugar. Muitas vezes é preciso “bater” em outros bancos de dados ou serviços/APIs para buscar os dados que faltam. É bom estar de olho nesse ponto desde o início, pois ele aumenta a complexidade da solução.
Trade‑offs técnicos
- Velocidade vs correção – Quando a migração é urgente, você precisa decidir até onde aceitar inconsistências nos dados sem comprometer a entrega.
- Jupyter Notebook vs CLI – Para migrações pequenas, um notebook resolve e acelera muito! Porém, ele pode crescer rapidamente, dificultando a legibilidade e a manutenção. Quando isso acontece, vale mais a pena adotar uma CLI.
- Migrar tudo vs migrar só o essencial – Nem todo dado merece ser migrado. É fundamental alinhar com o time de produto quais dados serão preservados e quais podem ser descartados de forma consciente.
- Processar tudo de uma vez vs em lotes – Recomendo processar os registros em batches e validar o resultado após cada lote. Essa abordagem é muito melhor do que tentar processar tudo de uma vez e precisar refazer tudo por causa de um pequeno erro nos tratamentos de dados.
Conclusão (segunda)
Se ninguém percebeu que a migração de dados aconteceu em produção, provavelmente foi um bom sinal. No fim, tudo se resume a contexto, equilíbrio e trade‑offs — e a manter o time alinhado sobre o que é possível entregar.