Patrones de diseño en Go a nivel avanzado con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Patrones de diseño en Go: nivel avanzado para desarrolladores profesionales

\n\n

Go (Golang) es un lenguaje creado para trabajar eficientemente con concurrencia y arquitectura de microservicios. Los patrones de diseño básicos, como Singleton o Factory, son bien conocidos, pero para crear sistemas de alta carga y tolerantes a fallos se requiere un nivel avanzado de dominio de los patrones. En este artículo analizaremos cuatro patrones clave: Fan-Out/Fan-In, Pipeline, Worker Pool y Circuit Breaker. Cada uno resuelve problemas prácticos de escalado, procesamiento paralelo y protección del sistema contra fallos en cascada.

\n\n

1. Patrón Fan-Out / Fan-In: procesamiento paralelo de datos

\n\n

Este patrón es la base de los cálculos paralelos en Go. Fan-Out (salida en abanico) distribuye la carga entre varias gorutinas, mientras que Fan-In (entrada en abanico) recoge los resultados de vuelta en un solo canal.

\n\n

Implementación de Fan-Out

\n

Imaginemos una tarea: hay que procesar 100 direcciones URL. En lugar de un procesamiento secuencial, lanzamos 10 gorutinas, cada una de las cuales toma una tarea del canal común.

\n\n
package main\n\nimport (\n    "fmt"\n    "sync"\n)\n\nfunc worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {\n    defer wg.Done()\n    for job := range jobs {\n        // Simulación de procesamiento\n        results <- job * 2\n        fmt.Printf("Worker %d processed job %d\\n", id, job)\n    }\n}\n\nfunc main() {\n    const numJobs = 20\n    const numWorkers = 5\n\n    jobs := make(chan int, numJobs)\n    results := make(chan int, numJobs)\n    var wg sync.WaitGroup\n\n    // Fan-Out: lanzamos los workers\n    for w := 1; w <= numWorkers; w++ {\n        wg.Add(1)\n        go worker(w, jobs, results, &wg)\n    }\n\n    // Enviamos las tareas\n    for j := 1; j <= numJobs; j++ {\n        jobs <- j\n    }\n    close(jobs)\n\n    // Fan-In: esperamos a que terminen y cerramos results\n    go func() {\n        wg.Wait()\n        close(results)\n    }()\n\n    // Recogemos los resultados\n    for result := range results {\n        fmt.Println("Result:", result)\n    }\n}\n
\n\n

Puntos clave:

\n
    \n
  • El canal jobs sirve como punto de Fan-Out: todos los workers leen de él.
  • \n
  • El canal results es el punto de Fan-In: todos los workers escriben en él.
  • \n
  • El uso de sync.WaitGroup garantiza que cerremos results solo después de que todas las gorutinas hayan terminado.
  • \n
\n\n

2. Patrón Pipeline: procesamiento de datos en cadena

\n\n

Pipeline es una cadena de etapas, donde cada etapa procesa los datos y los pasa a la siguiente. En Go esto se implementa mediante una secuencia de canales. El patrón es ideal para procesos ETL, procesamiento de logs o transformación de datos.

\n\n

Ejemplo: cadena de procesamiento de texto

\n\n
package main\n\nimport "fmt"\n\n// Etapa 1: generación de números\nfunc generate(nums ...int) <-chan int {\n    out := make(chan int)\n    go func() {\n        for _, n := range nums {\n            out <- n\n        }\n        close(out)\n    }()\n    return out\n}\n\n// Etapa 2: elevar al cuadrado\nfunc square(in <-chan int) <-chan int {\n    out := make(chan int)\n    go func() {\n        for n := range in {\n            out <- n * n\n        }\n        close(out)\n    }()\n    return out\n}\n\n// Etapa 3: multiplicar por 2\nfunc multiply(in <-chan int, factor int) <-chan int {\n    out := make(chan int)\n    go func() {\n        for n := range in {\n            out <- n * factor\n        }\n        close(out)\n    }()\n    return out\n}\n\nfunc main() {\n    // Construcción del pipeline\n    pipeline := multiply(square(generate(1, 2, 3, 4)), 10)\n\n    // Consumo de resultados\n    for result := range pipeline {\n        fmt.Println(result) // 10, 40, 90, 160\n    }\n}\n
\n\n

Ventajas:

\n
    \n
  • Cada etapa es una unidad independiente
  • \n

Blogs

Book Recommendations