Migración técnica · Strangler pattern

Migración de
Python a Go.

Tu Django o Flask no aguanta el crecimiento. Latencia subiendo, factura de Cloud disparada, GIL bloqueando lo que debería ser concurrente. Migramos a Go con strangler pattern, sin big-bang, manteniendo el negocio en pie cada sprint.

No es una reescritura ciega ni un purismo de lenguaje. Es una migración por dominio, con métricas antes y después, y compatibilidad de API mientras dura el cambio.

−40%

Coste de Cloud Run típico tras migrar el path crítico

10×

Throughput por instancia con goroutines vs uvicorn workers

<100 ms

Cold-start típico, vs 1–3 s de un proceso Python con dependencias pesadas

0

Big-bang. Migración progresiva con strangler pattern

Cuándo migrar

Síntomas que indican que tu backend Python ha dejado de escalar.

No todo backend Python necesita migrarse. Estos son los síntomas concretos donde Go aporta más de lo que cuesta.

🥵

Latencia p99 que sube con el tráfico

El GIL serializa la concurrencia real. Cuando subes RPS, p99 se dispara aunque la CPU esté al 30%. Añadir uvicorn workers compra tiempo, no resuelve el problema.

💸

Factura de Cloud creciendo rápido

Para servir el mismo throughput, Python necesita 3–10× más instancias que Go. En Cloud Run con autoscaling, eso es factura directa. Migrar el path caliente reduce coste sin cambiar la lógica.

🐢

Cold-start de varios segundos

Python + Django/FastAPI + dependencias ML carga 1–3 s al arrancar. En Cloud Run con scale-to-zero, eso son request fallidas o timeouts. Un binario Go arranca en <100 ms.

🧱

Concurrencia pesada con asyncio o Celery

asyncio es funcional pero el modelo mental es complejo y rompe en librerías sync. Celery + Redis para tareas async es operativamente caro. En Go, una goroutine + canal cubre el 90% de los casos.

🔒

Tipos en runtime, bugs en producción

mypy ayuda pero no es vinculante. En Go, el compilador rechaza tipos incompatibles antes de que lleguen a CI. La curva de bugs por lanzamiento se aplana visiblemente.

📦

Despliegue dependiente de imagen base pesada

Imágenes Docker Python con NumPy, PyTorch, etc. pasan de 1 GB. En Go, un binario estático en una imagen scratch o distroless ronda los 30 MB. Deploys más rápidos, superficie de ataque menor.

Cuándo NO migrar

  • ·Tu carga es moderada (<100 RPS) y el SLA actual se cumple sin sufrir.
  • ·El servicio es pesado en lógica numérica/ML (NumPy, pandas, PyTorch). Mejor mantener Python en ese path y migrar solo la parte de servicio HTTP.
  • ·El equipo es 100% Python sin apetito de aprender Go. Una migración fallida es peor que un Python lento.
  • ·El servicio va a deprecarse en <12 meses. No tiene sentido invertir en migrar lo que se va a apagar.

Comparativa honesta

Python vs Go en producción.

Cada lenguaje gana en lo suyo. Esta es la comparativa que damos a CTOs en duda — sin sectarismo de stack.

DimensiónPythonGoVeredicto
Latencia p99 a alta concurrenciaLimitada por el GIL · workarounds con uvicorn workersEstable bajo carga · goroutines nativasGo
Cold-start (Cloud Run / Lambda)1–3 s típico con dependencias<100 ms con binario optimizadoGo
Footprint de imagen300 MB – 2 GB<30 MB con multi-stageGo
Velocidad de prototipadoInmejorable · notebook → script → serviceMás boilerplate · compila siemprePython
Ecosistema ML / data scienceEl estándar de facto · NumPy, PyTorch, scikitLimitado · ONNX runtime para inferenciaPython
Tipado y captura de errores en compilaciónmypy / pyright son opcionales · runtime errorsCompilador estricto · errores explícitosGo
Concurrenciaasyncio funciona pero rompe en libs sync · GILGoroutines + canales · idioma de primer nivelGo
Talento disponibleAbundante a todos los nivelesMás nicho · pero alto nivel medioEmpate
Deployment a Cloud RunRazonable · ajustes de Dockerfile constantesIdiomático · imagen scratch/distrolessGo
Coste mensual a igual throughputLínea baseTípicamente −40% al −60%Go

Cómo migramos

Strangler pattern. Sin big-bang, sin downtime.

El servicio Go nuevo recibe progresivamente porcentajes del tráfico vía proxy o feature flags. La API mantiene compatibilidad. El monolito Python sigue vivo hasta que el último endpoint se ha migrado.

01

Discovery + audit

Auditoría del monolito actual: endpoints, latencia por endpoint, cobertura de tests, dependencias críticas, observabilidad existente. Identificamos los 3–5 endpoints calientes que justifican empezar la migración. Definimos el SLO objetivo.

1–2 sem

02

Diseño de API y contratos

El servicio Go nuevo expone exactamente las mismas APIs que el monolito Python. OpenAPI / Protobuf como contrato firmado, contract testing en CI. Sin cambios de cliente — el frontend o las apps móviles no tocan código.

1 sem

03

Implementación del primer dominio

Reescribimos el endpoint o conjunto de endpoints más caliente en Go. Misma DB, mismo Redis, misma cola. Tests de integración contra fixtures reales. Despliegue inicial al 0% de tráfico — sombra completa para validar paridad de comportamiento.

3–6 sem

04

Rollout progresivo con proxy/flags

Routing del 1% → 5% → 25% → 100% del tráfico al servicio Go via proxy (Envoy, Cloud Load Balancer) o feature flags por usuario. Métricas comparadas en cada salto: latencia, error rate, paridad de respuesta. Rollback en segundos si algo se desvía.

2–3 sem por dominio

05

Migración del resto + apagado del monolito

Repetimos el ciclo por dominio. Cuando el último endpoint Python ha migrado, apagamos el monolito. Documentación operacional, runbooks, dashboards Grafana / Cloud Monitoring entregados al equipo del cliente.

Variable según alcance

Qué migramos

Casos típicos de migración Python → Go.

No siempre se migra todo. A veces solo el path caliente. Estos son los patrones más frecuentes que vemos en producción.

🚪

API gateway o BFF

El Django/Flask que sirve a la app móvil o al SPA. Suele ser el path con más tráfico y el más fácil de migrar — aprovecha al máximo las goroutines y reduce coste de Cloud inmediatamente.

🔁

Workers de procesamiento async

Lo que hoy hace Celery + Redis lo asume un servicio Go con Pub/Sub o NATS. Pool de goroutines acotado, dead-letter queue, backpressure controlada. 10× throughput por instancia sin tocar la lógica de negocio.

🤖

Servicios que orquestan LLMs

La parte de orquestación (function calling, retries, streaming) en Go; la parte ML pura (entrenamiento, fine-tuning) sigue en Python. Patrón híbrido común — lo aplicamos en CityXerpa.

🔌

Microservicios extraídos del monolito

Trocear un Django monolítico por dominio (auth, billing, catalogue, notifications). Cada dominio se vuelve un microservicio Go independiente con su DB. Strangler pattern por dominio, sin tocar el resto.

💳

Pricing engines y servicios fintech

Donde p99 < 100 ms es contractual. Python no llega; Java/JVM funciona pero pesa más. Go encaja exacto: latencia y footprint correctos, talento más barato que Java.

📡

Webhooks y handlers de eventos

Endpoints que reciben webhooks (Stripe, Twilio, GitHub) y disparan procesamiento. Go hace estos endpoints irrompibles a saturación con goroutines + Pub/Sub para decoupling del path crítico.

FAQ técnica

Las preguntas que nos hace cualquier CTO la primera reunión.

Depende del tamaño y la fragmentación del monolito. Un servicio Python mediano con 8–15 endpoints calientes se migra en 3–5 meses con el strangler pattern, sin downtime y manteniendo el negocio operativo. Monolitos grandes con cientos de endpoints son proyectos de 9–18 meses, pero el ROI suele aparecer en el mes 3 con la migración del primer dominio caliente.

Los tests unitarios sí — son específicos del lenguaje. Los tests de integración y end-to-end (que llaman a la API) NO: precisamente esos validan que el Go nuevo entrega la misma respuesta que el Python viejo. Mantenerlos durante toda la migración es la red de seguridad principal.

Caso típico. Tres opciones: (1) Dribba implementa la migración y entrega + handover con documentación + sesiones de pairing 2 semanas; (2) modelo híbrido — nuestros engineers Go integrados con vuestro equipo Python para transferir conocimiento mientras migran; (3) formación previa intensiva (1–2 semanas) para el equipo, después acompañamiento. Los engineers Python con experiencia aprenden Go en 4–8 semanas — la curva es corta.

Total. La API expuesta no cambia mientras dura la migración. Mismos endpoints, mismos schemas, mismos códigos de error. El frontend o las apps móviles no se enteran. Si después de la migración queréis evolucionar la API a v2, lo hacemos como proyecto separado.

Por defecto, solo la capa de aplicación. La DB se mantiene (Postgres normalmente). El servicio Go usa pgx o sqlc para acceder a las mismas tablas. Si la DB es parte del problema (modelo mal diseñado, queries pesadas, índices incorrectos), lo flagamos en el discovery y proponemos mejoras como track separado.

No las migramos. PyTorch, TensorFlow, scikit-learn, NumPy/pandas se quedan en Python — Go no compite ahí. La separación es: capa de servicio HTTP en Go, capa ML en Python (FastAPI minimal o gRPC server). El servicio Go llama al Python por gRPC interno. Patrón común y eficaz.

Cuatro métricas en cada salto de tráfico: (1) latencia p50/p95/p99 del nuevo servicio Go vs el viejo Python; (2) error rate por endpoint; (3) paridad de respuesta — comparación byte-a-byte de respuesta para 1000 requests aleatorios; (4) coste de Cloud Run por request. Dashboards Grafana o Cloud Monitoring con alertas automáticas si cualquier métrica se desvía >5%.

Migración del path caliente (3–5 endpoints en un servicio Python mediano) entre 60.000 y 120.000 € en 3–5 meses. Migración completa de un monolito a una arquitectura de microservicios Go entre 150.000 y 400.000 € en 9–18 meses. Precio fijo por dominio tras Discovery. La factura suele amortizarse en 6–12 meses por el ahorro en Cloud.

¿Tu monolito Python ha dejado de escalar?

Auditoría técnica en 2 semanas.
Plan de migración concreto.

Te entregamos un informe con: endpoints calientes, paridad de tests, plan de strangler por dominio, estimación de coste y de ROI. Aunque el plan no nos contrate.

Equipo 100% senior in-house en Barcelona y Andorra · Respuesta en 24 h