Principios SOLID en Go: guía avanzada 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

Principios SOLID en Go: nivel avanzado



SOLID son cinco principios fundamentales del diseño orientado a objetos que ayudan a crear código flexible, mantenible y escalable. En el contexto de Go, un lenguaje con una filosofía única de composición en lugar de herencia, la aplicación de SOLID requiere un enfoque especial. En este artículo, analizaremos cada principio a nivel avanzado, con ejemplos reales y antipatrones característicos de la comunidad Go.



1. Principio de Responsabilidad Única (SRP) en Go



El principio de responsabilidad única establece: una clase (estructura) debe tener solo una razón para cambiar. En Go, esto a menudo se viola en paquetes utilitarios y "objetos divinos".



Antipatrón: estructura con múltiples responsabilidades



type UserService struct {    db *sql.DB    cache *redis.Client    logger *log.Logger}

func (s *UserService) CreateUser(ctx context.Context, u User) error { // 1. Validación // 2. Hash de contraseña // 3. Guardar en BD // 4. Enviar email // 5. Registro en log return nil}


Solución: divida las responsabilidades en servicios separados y use composición.



type UserValidator interface {    Validate(u User) error}

type PasswordHasher interface { Hash(password string) (string, error)}

type UserRepository interface { Save(ctx context.Context, u User) error}

type EmailSender interface { SendWelcomeEmail(ctx context.Context, email string) error}

type UserService struct { validator UserValidator hasher PasswordHasher repo UserRepository emailSender EmailSender logger Logger}


Cada componente ahora tiene una sola razón para cambiar, lo que simplifica las pruebas y el mantenimiento.



2. Principio Abierto-Cerrado (OCP) mediante interfaces



El principio abierto/cerrado: las entidades deben estar abiertas para extensión, pero cerradas para modificación. En Go, esto se logra mediante interfaces e inyección de dependencias.



Ejemplo incorrecto: acoplamiento rígido



type PaymentProcessor struct {    paypalAPI *PayPalAPI}

func (p *PaymentProcessor) Process(amount float64) error { return p.paypalAPI.Charge(amount)}


Si necesita agregar Stripe, tendrá que modificar el código.



Enfoque correcto: interfaz + estrategia



type PaymentGateway interface {    Charge(amount float64) error    Refund(transactionID string) error}

type PayPalGateway struct{ /* ... */ }type StripeGateway struct{ /* ... */ }

func (p *PayPalGateway) Charge(amount float64) error { /* ... */ }func (s *StripeGateway) Charge(amount float64) error { /* ... */ }

type PaymentService struct { gateway PaymentGateway}

func NewPaymentService(gw PaymentGateway) *PaymentService { return &PaymentService{gateway: gw}}


Ahora puede agregar nuevas pasarelas de pago sin modificar PaymentService.



3. Principio de Sustitución de Liskov (LSP) en el contexto de Go



El principio de sustitución de Barbara Liskov: los objetos en un programa deben ser reemplazables por instancias de sus subtipos sin alterar la corrección del programa. En Go, donde no hay herencia clásica, LSP se manifiesta a través de contratos de interfaces.



Violación típica: interfaz con métodos redundantes



type Bird interface {    Fly() error    Swim() error}

type Penguin struct{}

func (p *Penguin) Fly() error { return errors.New("los pingüinos no pueden volar")}

func (p *Penguin) Swim() error { return nil}


Aquí, Penguin no puede implementar correctamente Fly(), lo que viola LSP.



Solución: separación de interfaces



type Flyer interface {    Fly() error}

type Swimmer interface { S

Blogs

Book Recommendations