Refactorización de código legacy en Go: guía paso a paso

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
```html

Introducción a la refactorización de código legacy en Go



Trabajar con código heredado (legacy) es una parte inevitable de la vida de cualquier desarrollador Go. Con el tiempo, los proyectos acumulan deuda técnica: aparecen funciones monolíticas, duplicación de código, falta de pruebas y manejo de errores. La refactorización de código legacy en Go no es simplemente reescribir, sino un proceso estratégico de mejora de la arquitectura sin cambiar el comportamiento externo del sistema.



En este artículo, analizaremos los enfoques principales para la refactorización de proyectos Go, proporcionaremos ejemplos concretos de código y mostraremos cómo hacer que una base de código antigua sea más limpia, segura y eficiente.



¿Por qué el código legacy en Go requiere un enfoque especial?



Go es conocido por su simplicidad y rigor, pero incluso en él se acumulan problemas:



  • Falta de interfaces — alto acoplamiento entre componentes;
  • Ignorar errores — return sin verificar err;
  • Variables globales — dependencias implícitas;
  • Duplicación de lógica — copiar y pegar en lugar de composición;
  • Funciones largas — más de 50 líneas con múltiples responsabilidades.


La refactorización sin pruebas es como una cirugía sin anestesia. Por lo tanto, el primer paso es garantizar la cobertura de pruebas en las áreas críticas.



Estrategia de refactorización: del monolito a los módulos



1. Extracción de interfaces e inversión de dependencias



Comencemos con un código legacy típico, donde la lógica de negocio está rígidamente vinculada a la implementación del almacenamiento:



// Antes de la refactorizacióntype UserService struct {    db *sql.DB}

func (s *UserService) GetUser(id int) (*User, error) { row := s.db.QueryRow("SELECT id, name FROM users WHERE id = ?", id) var u User err := row.Scan(&u.ID, &u.Name) return &u, err}


Problema: este código no se puede probar sin una base de datos real. Solución: introducir una interfaz:



// Después de la refactorizacióntype Storage interface {    GetUser(id int) (*User, error)}

type UserService struct { storage Storage}

func NewUserService(storage Storage) *UserService { return &UserService{storage: storage}}

func (s *UserService) GetUser(id int) (*User, error) { return s.storage.GetUser(id)}


Ahora podemos reemplazar fácilmente la implementación por un mock en las pruebas.



2. División de funciones grandes (Single Responsibility)



Código legacy típico: una función que lo hace todo a la vez:



// Antes de la refactorizaciónfunc processOrder(order Order) error {    // Validación    if order.Amount <= 0 {        return errors.New("invalid amount")    }    // Cálculo de descuento    discount := 0.0    if order.CustomerType == "vip" {        discount = 0.1    }    // Guardar en BD    _, err := db.Exec("INSERT INTO orders ...")    if err != nil {        return err    }    // Enviar email    return sendEmail(order.Email, "Order confirmed")}


Después de la refactorización, dividimos en funciones pequeñas y comprobables:



// Después de la refactorizacióntype OrderProcessor struct {    db      Database    notifier Notifier}

func (p *OrderProcessor) Process(order Order) error { if err := validateOrder(order); err != nil { return err } order = applyDiscount(order) if err := p.db.SaveOrder(order); err != nil { return fmt.Errorf("save order: %w", err) } return p.notifier.SendConfirmation(order.Email)}

func validateOrder(order Order) error { if order.Amount <= 0 { return errors.New("amount must be positive") } return nil}

func applyDiscount(order Order) Order { if order.CustomerType == "vip" { order.Amount *= 0.9 } return order}


3. Reemplazo de variables globales por DI (Dependency Injection)



Las variables globales son el mayor enemigo de las pruebas

```

Blogs

Book Recommendations