No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Principios de dise帽o

5/24
Recursos

Aportes 22

Preguntas 3

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Principios SOLID

  • S : Principio de 脷nica Responsabilidad.
    Un m贸dulo deber铆a tener una sola raz贸n para cambiar.
  • O : Principio de Abierto Cerrado.
    Un m贸dulo deber铆a estar abierto a extensiones y cerrado a modificaciones.
  • L : Principio de Sustituci贸n de Liskov.
    Las clases derivadas deben poder sustituirse por sus clases base.
  • I : Principio de Segregaci贸n de la Interfaz
    Haz interfaces que sean espec铆ficas para un tipo de cliente
  • D : Principio de Inversi贸n de Dependencias
    Los m贸dulos de alto nivel no deber铆an depender de los m贸dulos de bajo nivel.

Principios SOLID

Libro: Desarrollo 谩gil de software: principios, patrones y pr谩cticas de Robert Martin

Single Responsibility Principle

Principio de responsabilidad 煤nica

Una clase s贸lo debe tener una raz贸n para cambiar.

El principal objetivo de este principio es reducir la complejidad.

si una clase hace demasiadas cosas, tienes que cambiarla cada vez que una de esas cosas cambia. Al hacerlo, te arriesgas a descomponer otras partes de la clase que no pretend铆as cambiar.

Open/Closed Principle

Principio de abierto/cerrado

Las clases deben estar abiertas a la extensi贸n pero cerradas a la modificaci贸n.

La idea fundamental de este principio es evitar que el c贸digo existente se descomponga cuando implementas nuevas funciones.

Este principio no est谩 pensado para aplicarse a todos los cambios de una clase. Si sabes que hay un error en la clase, debes arreglarlo; no crees una subclase para ello. Una clase hija no debe ser responsable de los problemas de la clase padre.

Liskov Substitution Principle

Principio de sustituci贸n de Liskov

Al extender una clase, recuerda que debes tener la capacidad de pasar objetos de las subclases en lugar de objetos de la clase padre, sin descomponer el c贸digo cliente.

Esto significa que la subclase debe permanecer compatible con el comportamiento de la superclase. Al sobrescribir un m茅todo, extiende el comportamiento base en lugar de sustituirlo con algo totalmente distinto.

  • Los tipos de par谩metros en el m茅todo de una subclase deben coincidir o ser m谩s abstractos que los tipos de par谩metros del m茅todo de la superclase.

  • El tipo de retorno en el m茅todo de una subclase debe coincidir o ser un subtipo del tipo de retorno del m茅todo de la superclase.

  • Un m茅todo de una subclase no debe arrojar tipos de excepciones que no se espere que arroje el m茅todo base.

  • Una subclase no debe fortalecer las condiciones previas.

    No debe a帽adir restricciones a los par谩metros al sobrescribir m茅todos de superclases.

  • Una subclase no debe debilitar las condiciones posteriores.

  • Los invariantes de una superclase deben preservarse.

  • Una subclase no debe cambiar los valores de campos privados de la superclase.

Interface Segregation Principle

Principio de segregaci贸n de la interfaz

No se debe forzar a los clientes a depender de m茅todos que no utilizan.

Dependency Inversion Principle

Principio de inversi贸n de la dependencia

Las clases de alto nivel no deben depender de clases de bajo nivel.

Ambas deben depender de abstracciones.

Las abstracciones no deben depender de detalles.

Los detalles deben depender de abstracciones.

Las clases de bajo nivel

Implementan operaciones b谩sicas, como trabajar con un disco, transferir datos por una red, conectar con una base de datos, etc.

Las clases de alto nivel

Contienen la l贸gica de negocio compleja que ordena a las clases de bajo nivel que hagan algo.

Paso a paso

  1. Para empezar, debes describir interfaces para operaciones de bajo nivel en las que se basar谩n las clases de alto nivel, preferiblemente en t茅rminos de negocio.

    Por ejemplo, la l贸gica de negocio debe invocar un m茅todo abrirInforme(archivo) en lugar de una serie de m茅todos abrirArchivo(x) , leerBytes(n) , cerrarArchivo(x) . Estas interfaces cuentan como de alto nivel.

  2. Ahora puedes hacer las clases de alto nivel dependientes de esas interfaces, en lugar de clases concretas de bajo nivel. Esta dependencia ser谩 mucho m谩s d茅bil que la original.

  3. Una vez que las clases de bajo nivel implementan esas interfaces, se vuelven dependientes del nivel de la l贸gica de negocio, invirtiendo la direcci贸n de la dependencia original.

Para el caso del principio 鈥Abierto/Cerrado鈥, la soluci贸n planteada por el profesor Manuel, est谩 basada en el patr贸n de dise帽o 鈥Abstract Factory鈥, el cual pueden consultar en este enlace: https://refactoring.guru/es/design-patterns/abstract-factory

Los principios SOLID son super importantes aplicarlos en el desarrollo de Software ayudan a tener una mejor estructura en el c贸digo, los utilizo mucho.

Los principios SOLID, son aplicables principalmente a POO, ya que a trav茅s de estos principios se habla acerca de las clases, herencia, polimorfismo, sin embargo estos principios tambien pueden ser aplicables a Paradigmas como la Programacion Funcional, entre otros. Sin embargo es importante destacar que estos principios pueden ser usados en distintos paradigmas, ya que con esto lo que se busca es optimizar el codigo escrito de manera que sea mas comprensible, mantenible y comprobable a trav茅s del tiempo y que a su vez permita la integraci贸n de varios desarrolladores

Esta guay saber que lo que estaba haciendo de manera inconciente tiene nombre XD

Principios Solid.
(Para efectos pr谩cticos)
S: Principio de 脷nica responsabilidad: un m贸dulo deber铆a tener una sola raz贸n para que cambie.
O: Principio abierto Cerrado: un m贸dulo deber铆a estar abierto a extensiones y cerrado a modificaciones.
D: Principio de inversi贸n de dependencias: podemos invertir la direcci贸n de las dependencias.

Para aprovechar al m谩ximo las arquitecturas limpias, es bueno conocer algunos principios de dise帽o, en particular los principios SOLID:

Para efectos pr谩cticos, solo nos enfocaremos en S.O.D.

Principio de 脷nica Responsabilidad (S)

Un m贸dulo deber铆a tener una sola raz贸n para cambiar. Un m贸dulo puede significar muchas cosas, pero podemos verlo como un archivo o una clase en la que se trabajar谩.

Veamos el siguiente c贸digo:

app.post("/users", (req, res) => {
  const user = req.body;

  if (!user || !user.name || !user.email) {
    res.status(400).send("Bad Request");
  } else {
    pool.query(
      "INSERT INTO useers (name, email) VALUES (?, ?)",
      [user.name, user.email],
      (error, results) => {
        if (error) {
          console.log(error);
          res.status(500).send("Internal error");
        } else {
          res.status(201).send("User created");
        }
      }
    );
  }
});

Como puedes ver en el c贸digo anterior, se est谩 recibiendo una petici贸n http, se valida la informaci贸n, luego se hace una inserci贸n a la base de datos, luego se manejan los errores para que al final inserte el usuario con 茅xito. Esto rompe el principio de una sola responsabilidad.

En caso de que queramos modificar este c贸digo, tenemos tres razones para cambiar:

  1. La raz贸n en la manera en que nos comunicamos con el cliente cambi贸 (/users), ya que usamos alg煤n m茅todo diferente o usamos otros par谩metros.
  2. Luego podr铆amos querer hacer validaciones distintas, como verificar que el email que se ha enviado realmente sea un email.
  3. O que tambi茅n la base de datos haya cambiado su estructura, como a帽adir alg煤n nuevo campo o un cambio en la tabla.

Entonces al ver esto, podemos empezar a pensar en que podr铆amos separar todo este c贸digo seg煤n su responsabilidad. Una parte que se enfoque en la http, otro en las validaciones, otro al acceso de datos u otro que se encargue de los errores.

Principio de Abierto Cerrado (O)

Un m贸dulo (clase, archivo) deber铆a estar abierto a extensiones y cerrado a modificaciones.

Veamos el siguiente c贸digo:

if (ciudad == "Cali") {
  ejecutarProcesoCali();
} else if (ciudad == "Lima") {
  ejecutarProcesoLima();
} else if (ciudad == "Buenos Aires") {
  ejecutarProcesoBuenosAires();
}

Esto no es bueno para nada, 驴qu茅 ocurre si un d铆a debemos agregar 10 ciudades m谩s o a帽adir m谩s c贸digo dentro de las condiciones? Esto dificulta la navegaci贸n y la mantenebilidad de nuestro c贸digo. Nosotros deber铆amos buscar una forma en que ese c贸digo no se modifique, sino que a帽ada nuevo c贸digo pero lo que funcione se mantenga quieto, con el objetivo de que podamos a帽adir ciudades de una manera m谩s segura sin comprometer el c贸digo que ya est谩.

Algo para que cumpla el principio de abierto cerrado, puede ser lo siguiente:

![[Captura de pantalla 2023-09-18 a la(s) 22.34.38.png|400]]

Esta estructura nos permite tener mucho m谩s encapsulado nuestro c贸digo, as铆 que a la hora de tener que modificar alguna ciudad, vamos a su clase o si debemos a帽adir otra, creamos una nueva. Extiendo y lo que funciona, no lo modifico. Es decir, estoy abierto a extender, pero cerrado a modificar el c贸digo que funciona.

Principio de inversi贸n de dependencias (D)

Los m贸dulos de alto nivel no deber铆an depender de los m贸dulos de bajo nivel.
Si vemos la arquitectura de tres capas:

![[Captura de pantalla 2023-09-18 a la(s) 21.22.10.png|300]]![[Captura de pantalla 2023-09-18 a la(s) 22.37.56.png|300]]

La presentaci贸n y acceso a datos son m贸dulos de bajo nivel, 驴por qu茅? porque son detalles que pueden cambiar en el tiempo y est谩n m谩s cercanos a una implementaci贸n espec铆fica. El dominio es de alto nivel ya que es mucho m谩s perdurable en el tiempo y general, que no debiese verse afectado si en alg煤n momento cambiamos nuestra bd a SQL Server, por ejemplo.

Se puede invertir la direcci贸n de dependencia:

![[Captura de pantalla 2023-09-18 a la(s) 22.40.55.png|300]]

El dominio ya no depende del acceso a datos, sino que el acceso a datos depende del dominio, porque justamente los m贸dulos de alto nivel no debe depender de detalles que cambien con el tiempo.

Nota
Alto nivel -> Dominio
Bajo nivel -> Todos los detalles que cambian con el tiempo

Un ejemplo de el codigo de ciudades y como evitar su modificaci贸n al dar mas datos de entrada, en este caso 鈥渃iudades鈥, en el cual se ver谩n como clases, se agregaran mas, pero no se tocara la l贸gica para ver si existe esa ciudad en tu 鈥渟istema鈥

# Define una interfaz para las estrategias de procesamiento de ciudades.
class CiudadProcessor:
    def procesar_ciudad(self):
        pass

# Implementa una estrategia para procesar Cali.
class ProcesoCali(CiudadProcessor):
    def procesar_ciudad(self):
        print("Ejecutando proceso para Cali")

# Implementa una estrategia para procesar Buenos Aires.
class ProcesoBuenosAires(CiudadProcessor):
    def procesar_ciudad(self):
        print("Ejecutando proceso para Buenos Aires")

# Implementa una estrategia para procesar M茅xico.
class ProcesoMexico(CiudadProcessor):
    def procesar_ciudad(self):
        print("Ejecutando proceso para M茅xico")

# Definir diccionario que asocia ciudades con sus estrategias de procesamiento.
estrategias_por_ciudad = {
    "cali": ProcesoCali(),
    "buenos aires": ProcesoBuenosAires(),
    "Mexico": ProcesoMexico(),
    
}

# Supongamos que 'ciudad' contiene el nombre de la ciudad a procesar.
ciudad = "cali"

#estructura de codigo que no se va a modificar 
if ciudad in estrategias_por_ciudad:
    estrategia = estrategias_por_ciudad[ciudad]
    estrategia.procesar_ciudad()
else:
    print("Ciudad desconocida")

Principio Dependency Inversion. Los m贸dulos de alto nivel no deber铆an depender de los m贸dulos de bajo nivel. Esto se debe a que los m贸dulos de alto nivel deber铆an ser m谩s generales, y no entrar en detalles como los de m谩s bajo nivel, quienes cambian m谩s seguido.

Principio Open Closed. Un m贸dulo deber铆a estar abierto a extensiones y cerrado a modificaciones. Por ejemplo, en lugar de hacer una cadena de condicionales if cada uno ejecutando un m茅todo, podr铆amos hacer una clase abstracta o interfaz y luego el m茅todo a ejecutar depender谩 de su implementaci贸n. De esta forma, liberamos al m贸dulo de la decisi贸n y la dejamos a una capa superior, donde se indique qu茅 clases implementar谩n a cada interfaz.

Principio Single Responsability. Un m贸dulo (archivo o clase) deber铆a tener una sola raz贸n para cambiar. Es decir, cada m贸dulo debe encargarse de una 煤nica tarea, de modo de simplificar futuros cambios/correcciones/tests. Por ejemplo, un controlador de una API no deber铆a conectarse a la base de datos directamente.

Principios de dise帽o

Para sacarle el mayor provecho a las arquitecturas limpias y entenderlas es importante estudiar algunos principios de dise帽o, en particular S.O.L.I.D.

S - Principio de 脷nica Responsabilidad

Un m贸dulo deber铆a tener una sola raz贸n para cambiar, por ejemplo un archivo o una clase.

O - Principio de Abierto Cerrado

Un m贸dulo deber铆a estar abierto a extensiones y cerrado a modificaciones.

D - Principiop de Inversi贸n de Dependencias

Los m贸dulos de alto nivel no deber铆a depender de los m贸dulos de bajo nivel.

  • Presentaci贸n (Bajo nivel).
  • Dominio (Alto nivel).
  • Acceso a datos (Bajo nivel).

Se puede invertir la direcci贸n de la dependencia:

Acceso a datos (Bajo nivel) 鈫 Dominio (Alto nivel)

El Principio de Inversi贸n de Dependencias (煤ltimo de los cinco principios SOLID).

Los m贸dulos de alto nivel no deben depender de los m贸dulos de bajo nivel. Ambos deben depender de abstracciones.
Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.
En la pr谩ctica, esto significa que las implementaciones de bajo nivel (por ejemplo, la l贸gica de acceso a datos BD) deben ser intercambiables sin que eso afecte a los m贸dulos de alto nivel (por ejemplo, la l贸gica de negocio).

La inversi贸n de control es una forma de lograr esto. En lugar de tener un m贸dulo de alto nivel que crea y controla los objetos de bajo nivel, se utiliza un 鈥渃ontenedor IoC鈥 que crea y gestiona estos objetos. El contenedor IoC puede inyectar estas dependencias en los m贸dulos de alto nivel cuando los necesiten, un patr贸n conocido como Inyecci贸n de Dependencias.

Por lo tanto, el Principio de Inversi贸n de Dependencias y la Inversi贸n de Control son mecanismos que nos ayudan a desacoplar el c贸digo y a hacerlo m谩s modular, flexible y f谩cil de probar.

LLevo bastante tiempo involucrado en proyectos de desarrollo donde usaba inyecci贸n de dependencias pero sin entender su raz贸n de ser propiamente; que buena explicaci贸n del princio de inversi贸n de control y por consiguiente como aplicar correctamente la inyecci贸n de dependencias : )

Si, los he aplicado unos mas que otros, los he aplicado en proyectos, dependiendo de lo que necesitemos

Principios de dise帽o

  • SRP (Single responsibility principle): Una sola raz贸n para cambiar

  • OCP (open closed Principle): Abierto a extensiones y cerrado a modificaciones

  • DIP (Dependency inversion Principle): Modulos de alto nivel(ej: logica de negocio o el dominio) no dependen de detalles que cambia con el tiempo (modulos de bajo nivel).

He aplicado estos principios antes. A煤n as铆 notar que no siempre se deben seguir al pie de la letra. Existen varias corrientes contrarias al respecto como lo son CUPID y STUPID.

https://dannorth.net/2022/02/10/cupid-for-joyful-coding/

https://jnjsite.com/los-principios-del-diseno-software-kiss-dry-solid-stupid/

Dejo los t茅rminos en ingl茅s por si llevan curiosidad:

Single Responsibility Principle (SRP)
Open-Closed Principle (OCP)
Liskov Substitution Principle (LSP)
Interface Segregation Principle (ISP)
Dependency Inversion Principle (DIP)

Me parece excelente para utilizar en el desarrollo de una aplicacion