S.O.L.I.D
Última actualización
¿Te fue útil?
Última actualización
¿Te fue útil?
SOLID es un acrónimo introducido por Robert C. Martin en su libro "Agile Software Development, Principles, Patterns and Practices" y hace referencia a los siguientes cinco principios:
S: (SRP - Single responsibility principle) Principio de responsabilidad única.
O: (OCP - Open closed principle) Principio abierto cerrado.
L: (LSP - Liskov substitution principle) Principio de substitución de Liskov.
I: (ISP - Interface segregation principle) Principio de segregación de la interfaz.
D: (DIP - Dependency inversion principle) Principio de inversión de la dependencia.
El objetivo de aplicar estos principios es obtener sistemas orientados a objetos con código de mayor calidad, facilidad de mantenimiento y mejores oportunidades de reuso de código.
Una clase debe tener una, y sólo una, razón para cambiar, lo que significa que una clase debe tener un solo trabajo.
La primera observación respecto de este principio es que en Go no existen clases. Sin embargo, como vimos mediante la incorporación de comportamientos a tipos de datos, podemos llegar a un concepto equivalente.
Este principio hace foco en que un objeto debe tener únicamente una responsabilidad encapsulada por la clase. Cuando se hace referencia a una responsabilidad es para referirse a una razón para cambiar. Mantener una clase que tiene múltiples objetivos o responsabilidades es mucho más complejo que una clase enfocada en una única responsabilidad.
El siguiente ejemplo no cumple con este principio porque otorga a una estructura dos responsabilidades bien diferenciadas: guardar en un archivo local y guardar en una base de datos.
Un Documento debería saber cómo acceder al sistema de archivos local y a la vez como conectarse y operar contra una base de datos. Implementar ambas acciones en una misma estructura genera un alto acoplamiento.
Creando estructuras con responsabilidades bien definidas se puede mejorar el código de la siguiente manera:
¿Qué pasa en Go: Gracias a la organización en paquetes que permite Go es posible crear estructuras, tipos, funciones y métodos empaquetados con propósitos claros y bien definidos.
Los objetos o entidades deberían estar abiertos para la extensión, pero cerrados para su modificación.
Este principio propone que una entidad esté cerrada, lista para ser usada y estable en su calidad e interfaces, y al mismo tiempo abierta, es decir, que permita extender su comportamiento (pero sin modificar su código fuente).
Imaginemos que se requiere cambiar el comportamiento de la siguiente estructura únicamente en uno de sus métodos:
Podemos hacerlo de la siguiente forma:
¿Qué pasa en Go: Gracias a la composición que permite Go es posible componer tipos simples en más complejos manteniendo la interfaz del tipo original.
Cada clase que herede de otra debe poder utilizarse como su clase padre sin necesidad de conocer las diferencias que pudieran existir entre ellas.
Este principio propone que el contrato de una clase base debe ser honrado por sus clases derivadas para que instancias de las clases derivadas puedan reemplazar a instancias de la clase base.
Veamos el siguiente código:
La estructura Emision debe implementar dos comportamientos, ya que debe poder gestionar impresiones en HTML y JSON. Si a futuro se requiriera de otro tipo de impresión - xml por ejemplo - se debería modificar su código fuente.
La siguiente modificación permite intercambiar cualquier tipo de respuesta para su impresión:
¿Qué pasa en Go: Al definir firmas de métodos a través de interfaces, y no mediante tipos concretos, es posible utilizar cualquier tipo que respete implícitamente la interfaz.
Nunca se debe obligar a un cliente a implementar una interfaz que no utilice, o no se debe forzar a los clientes a depender de métodos que no usan.
Este principio hace foco en como deben definirse las interfaces. Las mismas deben ser pequeñas y específicas. Grandes y complejas interfaces obligan al cliente a implementar métodos que no necesita.
Veamos la siguiente interface:
Como puede verse la interface Boton obliga a implementar ambos comportamientos en sus clientes cuando es muy factible que no todos ellos deban implementar ambas opciones.
Una solución podría ser la siguiente:
¿Qué pasa en Go: En Go puede aplicarse este concepto aislando el comportamiento requerido utilizando interfaces más pequeñas.
Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deberían depender de abstracciones. Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
Este principio esta basado en reducir las dependencias entre los módulos del código para atacar el alto acoplamiento.
Veamos la siguiente ejemplo:
Como puede verse el tipo A depende del tipo B por lo que si el tipo B es modificado afectará al tipo A.
Una solución podría ser la siguiente:
¿Qué pasa en Go: Componer tipos mediante interfaces, y no mediante tipos concretos, permite evitar una fuerte dependencia entre tipos.
Como se vio en el apartado anterior, el poder de la composición y de las interfaces implícitas le permiten a Go implementar buenas prácticas y conceptos propios de la programación orientada a objetos.
Si bien el libro de Robert C. Martin tiene más de una década y media y hace referencia a lenguajes propiamente orientados a objetos, vimos como también pueden aplicarse esos principios en Go.
Atención: Esta publicación se encuentra abandonada. Puede acceder a la versión vigente en