SOLID: Principios de diseño de software.

7 minute read

Published:

Posteo sobre principios del diseño de software con SOLID.

SOLID: Principios de diseño de software.

El desarrollo de software es una actividad que requiere una excelente planeación para que el producto sea capaz de resolver las necesidades para las que fue creado; además, debe tener características importantes como escalabilidad, robustez y debe ser fácil de mantener y probar.

Existen principios de diseño establecidos para lograr que un programa sea lo más ágil posible, tales como SOLID. Acrónimo formado por las oraciones en inglés: Single Responsability Principle, Open/Closed Principle, Liskov’s Principle of Substitution, Dependency-Inversion Principle e Interface-Segregation Principle. Estos principios fueron recabados por Robert C. Martin en su libro Agile Software Development: Principles Patterns and Practices; a continuación, se discuten cada uno de ellos.

El principio de responsabilidad única (Single Responsability Principle, SRP) establece que una clase debe ser responsable de una sola funcionalidad, es decir, dicha clase solo tendría una razón para ser modificada.

Otros autores, para referirse al mismo caso, utilizan la definición de cohesión, y la describen como la relación funcional de los elementos de un módulo o clase. En esta relación, fijar la responsabilidad en cada clase permite cualquier modificación sobre la funcionalidad de clase, para así disminuir los errores. Entonces, existe una razón para modificar cada una de las clases porque son de responsabilidad única[Rober, Martin. 2014. p. 95].

Un ejemplo de este principio, podría ser considerando un programa de una calculadora simple. Este consiste básicamente en dos partes: la primera es la interacción con el usuario a través de una entrada y salida de símbolos; y la segunda es la parte lógica que se encarga de computar todos las operaciones que el usuario le indique. Utilizando el SRP, este programa debe contener al menos dos clases o módulos que realicen estas tareas, cada una con una responsabilidad fija, interacción o cómputo.

El segundo principio, llamado de responsabilidad abierta-cerrada (Open-Closed Responsibility, OCP), está pensado en los cambios de las entidades de software a lo largo de su ciclo de vida y cómo afrontará dichas modificaciones. “Las entidades deberían estar abiertas para extensiones, pero cerradas para modificaciones”. Este principio intenta disminuir la rigidez del código, es decir, que cuando haya un cambio no ocurra una cascada de alteraciones que complique el cambio principal. De tal forma que los cambios futuros solo sean adiciones de nuevo código y no cambios de código que funcionen y sean utilizables.

Considerando las clases en oop, éstas deberían ser abiertas para nuevos comportamientos o métodos y cerradas para modificaciones de los métodos ya establecidos dentro del código fuente fundamentales para su desempeño [Rober, Martin. 2014. p. 99].

Un ejemplo para este principio podría construirse a partir de la abstracción de algo práctico. Si una empresa de autos usados comienza un proyecto de desarrollo de software que relaciona los atributos y métodos de los autos, el OCP sugiere que el código se desarrolle de tal forma que cuando haya modificaciones (como agregar un auto nuevo con un comportamiento diferente, por ejemplo, estacionarse por sí solo), no se altere el código fuente que define la clase de autos con sus atributos y métodos, sino aprovechando la abstracción, así ese nuevo auto solo será una adición al código. El siguiente principio es el de sustitución de Liskov (Liskov’s Principle of Substitution, LSR), establece que los subtipos podrían ser sustituidos por tipos de su base. Este principio está relacionado con las reglas diseñadas para la herencia en oop, sus características y problemas. La premisa es sencilla, si se sustituye un objeto de una clase madre, con la clase hija, este debería ser capaz de ejecutar los mismos métodos sin ningún problema porque una clase deriva de otra, de lo contrario se ha fallado en el LSR [Rober, Martin. 2014. p. 111].

Este principio se puede ilustrar con el ejemplo de la empresa de autos usados, dado que cualquier subclase que añada comportamiento a la clase madre, seguirá teniendo un comportamiento similar a la clase que hereda y el principio estipula que cualquier instancia de subclase deberá ser capaz de llamar a los mismos métodos que la clase madre, es decir, compartir el mismo comportamiento.

El principio de inversión de dependencia (Dependency-Inversion Principle, DIP) está relacionado directamente con el diseño del framework. Este establece que los módulos de alto nivel no deben depender de los módulos de bajo nivel y las abstracciones no deberían depender de los detalles. Dicho principio estipula una premisa que beneficia la reutilización o modificación de módulos de alto nivel sin afectar módulos de bajo nivel porque no hay una dependencia.

Por otra parte, la dependencia en las abstracciones beneficia que las relaciones en el programa sean flexibles y no dependan de una clase en específico[Rober, Martin. 2014. p. 127].

Un ejemplo de este principio es el diseño de código de un equipo de audio. Si se diseña un programa a partir de un tipo definido de sonido, con intervalo de frecuencias, decibeles, número de bocinas y el ruido, se estaría dependiendo del detalle de un caso en particular para realizar toda una serie de métodos. Cuando se intente modificar dicho programa, será necesario adaptarlo al siguiente caso específico, lo cual es impráctico. Lo mejor es pensar en la abstracción del equipo y considerar todo los posibles casos, para que cualquier cambio de alto nivel sea independiente de las características de bajo nivel.

El último principio es el de segregación de interfaz (Interface-Segregation Principle, ISP) establece que un módulo no debería estar forzado a depender de métodos que no se usan y sugiere la creación de interfaces o clases específicas para determinados módulos. Es una manera de afrontar las desventajas de interfaces enormes, es decir interfaces no cohesivas y basadas en abstracción en lugar de instancias [Rober, Martin. 2014. p. 135].

Un ejemplo del uso del principio ISP es el diseño de una aplicación multitask, como un visualizador de imágenes médicas. Dentro de esta app, la interacción será entre entes de distintos módulos, tales como la clase paciente con las características y métodos del paciente y la clase scheduler con las características y métodos del manejo de citas y resultados de estudios.

La app tendrá un interfaz que será manipulada por el médico, dicha interfaz debe lograr operar algunos atributos y comportamientos de la clase paciente y scheduler; sin embargo, este principio sugiere que la interfaz que es utilizada por el usuario médico, únicamente contenga los métodos que sí utiliza de las clases y no todo su contenido. Es decir, puede ver edad, peso y altura pero no puede utilizar alguna función que modifique dichos valores; o bien, puede realizar algunas operaciones sobre la imagen del estudio del paciente, pero no puede modificar el procesamiento de la imagen.

En conclusión, los principios SOLID, son una referencia muy importante al momento del diseño del software. El objetivo es lograr un código de programación orientado a objetos con la capacidad de ser escalable, estable, flexible y mantenible.

Así mismo, los principios están basados en los conceptos más importantes de la programación orientada a objetos, tales como modificadores, herencia, encapsulación, polimorfismo, atributos y métodos. Entonces, llevar buenas prácticas con base en la metodología SOLID, es sinónimo de comprender de forma lógica y eficiente la programación orientada a objetos.

Referencias

1) Martin Robert C. 2014. Agile Software Development : Principles Patterns and Practices 1St ed. Pearson new international ed. Essex (U. K.): Pearson