¿Cómo puedes crear un código que sea sostenible y mantenible en el tiempo? Es una gran pregunta, te sorprenderá saber que escribir código es solo el comienzo (y nosotros solo nos enfocamos en ello). Precisamente porque mantenerlo, editarlo, ampliarlo y optimizarlo es lo que realmente define a los proyectos exitosos a largo plazo. Aquí es donde entran en juego dos de los pilares más importantes: Los patrones de diseño y los principios SOLID. En esta publicación, explicaré por qué estas técnicas son clave, cómo han influido en la programación y cómo puedes aplicarlas para mejorar tu propio código y por ende tu nivel profesional.
Ojo que también influye la arquitectura, pero esa es otra historia que abordaré en otra publicación. De momento lee y aprende estos temas de memoria.
¿Por qué son importantes los Patrones de Diseño y los Principios SOLID?
La idea es no inventar, no reinventar la rueda y no sobrepensar... Los patrones de diseño y los principios SOLID ofrecen soluciones probadas a problemas comunes en programación. Estas técnicas nos ayudan a enfrentar desafíos técnicos, grandes y organizativos, resultando en sistemas poderosos, más robustos y adaptables.
Yo he sido empleado en proyectos donde no se usa estándar alguno y adivina que, estos proyectos se terminan abandonando. Esto es importante, veamos algunas razones adicionales por las cuales esto debe aprenderse y aplicarse:
- Testing: Parece mentira, pero un sistema mal construido o desordenado no admite testing alguno, en cambio un proyecto realmente modular y desacoplado es mucho más fácil de testear, tanto a nivel unitario como a nivel de integración. Y esto es vital para asegurar que el código cumpla con sus objetivos pero además esto nos ayuda a reducir la probabilidad de errores en producción.
- Mantenimiento: Esto es lo más importante. Un código bien estructurado es más fácil de leer, comprender y fácil de modificar sin causar problemas. Esto por supuesto le facilita el trabajo del creador del código como a cualquier otro programador que vaya a trabajar en el proyecto en el futuro. Aquí también decimos, piensa en tu YO del futuro.
- Escalabilidad: Cuando el sistema crece, se vuelve clave y esencial que su estructura sea lo suficientemente flexible para adaptarse a distintos cambios sin necesidad de grandes refactorizaciones. La idea es crear proyectos que soporten el crecimiento.
- Rendimiento: Un sistema bien estructurado nos permitiría identificar y resolver cuellos de botella de manera sencilla, ya que el flujo del código es claro y controlado. Esto se logra gracias al buen diseño.
- Experiencia de desarrollo: Así como existe la experiencia del usuario, también podemos hablar de la experiencia de desarrollo que vive el programador. Uno debe sentirse orgulloso de su trabajo, por lo que puedes imaginar que trabajar con un código limpio y bien organizado es una experiencia agradable y productiva. Además, aprender estos principios mejorará nuestra habilidad técnica y por ende seremos mejores profesionales.
¿Sabes qué es feo y molesto? Que el sistema falle en manos del cliente y si no acatas esto, definitivamente sucederá. El cliente llamará molesto una y otra vez.
¿Qué son los Patrones de Diseño?
Según el diccionario, un patrón es un modelo que sirve de muestra para sacar otra cosa igual, un molde, es una guía a seguir. Así que los patrones de diseño son soluciones genéricas a problemas comunes en la programación. Los podemos llamar estrategias de programación que se han perfeccionado a lo largo del tiempo y que se clasifican en varias categorías:
- Creacionales: Se enfocan en la creación de objetos.
- Estructurales: Se ocupan de la composición de clases y objetos.
- Comportamiento: Se centran en la comunicación entre objetos.
Los podemos abordar más adelante en la historia de esta página web, de momento podré decirte que cada patrón tiene su nombre, por ejemplo: Singleton y factory formal parte de los patrones creacionales, adapter y composite serían estructurales y finalmente observer y strategy estarían dentro de la categoría patrones de comportamiento.
Hay muchos patrones y cada patrón tiene su propósito específico y su contexto ideal, como puedes ver aprender a usarlos te permitirá construir soluciones más eficientes y organizadas. En otras palabras, un patrón es el manual para programar mejor.
Principios SOLID
Es lo que representa cinco principios fundamentales para un diseño profesional orientado a objetos. Aquí es donde el gran Robert C. Martin es protagonista, él los definió y son clave para crear un código flexible, reutilizable, fácil de entender y de mantener.
Soy muy fan de Robert C. Martin, pronto tendré sus libros físicos en mi casa.
Sigamos:
- S (Single Responsibility Principle - Principio de Responsabilidad Única): Cada clase debe tener una única responsabilidad, objetivo o propósito, lo que facilitará su comprensión e implementación de testing.
- O (Open/Closed Principle - Principio Abierto/Cerrado): Toda clase debe estar abierta a su extensión, pero cerrada para su modificación, esto permitirá añadir nuevas funcionalidades sin alterar el código existente.
- L (Liskov Substitution Principle - Principio de Sustitución de Liskov): Este concepto es un poco más complejo porque es difícil de imaginar al principio. Pero piensa que los objetos de una clase hija (derivada) deben ser capaces de reemplazar a los objetos de su clase padre o base sin afectar el funcionamiento o comportamiento.
- I (Interface Segregation Principle - Principio de Segregación de Interfaces): Este principio nos dice que es mejor tener varias interfaces pequeñas y específicas que una sola interfaz general, grande o masiva.
- D (Dependency Inversion Principle - Principio de Inversión de Dependencias): Las clases deben depender de abstracciones, no de implementaciones concretas. Esto reduce el acoplamiento y mejora la flexibilidad. En la práctica significa que debemos inyectar una interfaz o clase abstracta y no una clase concreta directamente.
¿Cómo podemos aprender tantas cosas? Bueno, una de las mejores maneras de hacerlo es crear un proyecto real y además hacerlo poco a poco, no todo a la vez. Esto te dará un mayor dominio y una mayor profundidad en cada concepto.
Single Responsibility Principle - Principio de Responsabilidad Única
Hagamos un ejemplo con Single Responsibility Principle en Python, todos saben que soy PHPero pero siempre hago experimentos en otros lenguajes para aprender un poco más, o tratar de hacerlo.
Imagina que estás trabajando en un código que procesa pagos. Al principio, puedes hacer que todo el código esté en una sola clase, pero no lo dejes así porque esto viola dicho principio. Pensar en SOLID (o al menos la S) te hará dividir esta clase en clases más pequeñas y específicas, como PaymentValidator
, PaymentProcessor
y PaymentRegister
, cada una por supuesto con su propia responsabilidad y no en una clase gigante llamada Payment
.
class PaymentValidator:
def validate(self, payment):
# Logic to validate the payment
pass
class PaymentProcessor:
def process(self, payment):
# Logic to process the payment
pass
class PaymentRegister:
def register(self, payment):
# Logic to record the payment
pass
Esto nos ayuda a pensar en resolver el problema y luego en la implementación del principio de responsabilidad única. Dividir las responsabilidades en clases específicas hace que el código sea más fácil de leer, testear, mantener y escalar.
Aprender esto es una gran inversión que debes hacer. Al principio es complejo, pero dedicale el tiempo hasta causar un gran impacto, sobre todo en proyectos grandes y complejos.