domingo, 7 de junio de 2015

Buenas prácticas de programación:

Principios de diseño SOLID - Open/Closed (3/6)
En esta serie de buenas prácticas de programación ya hemos hablado del principio de responsabilidad única.

Aplicar los principios de diseño SOLID hará que podamos tener nuestro código mejor estructurado y que apliquemos Unit Tests de una mejor forma.

El segundo principio dentro de SOLID es el de "Abierto/Cerrado" (Open/Closed Principle). Este principio establece que cualquier entidad de SW (Clases, módulos, funciones) deben estar abiertas para extensión pero cerradas para modificaciones. Aunque suena a alguna contradicción, no lo es, debemos estructurar nuestros diseños para que al agregar funcionalidad modifiquemos lo mínimo nuestro código.  Debemos evitar que al modificar una clase tengamos que expandir esa modificación a las distintas clases de la aplicación.

Una de las formas más sencillas de escribir clases que que no tienen que cambiar es haciendo que cada clase haga únicamente una sola tarea (Aplicando el principio de Single Responsability),

Otra técnica que podemos utilizar es dividir nuestras tareas de acceso a datos y de lógica para mantenerlas en entidades distintas, de esa forma podemos cambiar una sin afectar a la otra.

El ejemplo que trataremos aquí es un caso de la vida real; En una de las empresas a las que llegué a trabajar me encontré con fragmentos de código (regados en la solución de VS) muy parecidos a esto:




La idea del código era rellenar con ceros a la izquierda las claves de empleado ajustando cada clave de empleado a una longitud de 10.

Sin embargo, al tener el código regado por tantas partes y al estar tan sujeto a la regla de negocio, al momento de que la regla de negocio cambie tendremos que modificar cada aparición del código y modificarla, haciendo complicado el mantenimiento.

La forma en que se refactorizó para poder tener código más fácil de mantener fue crear un método estático en una clase "Helper" que nos permitiera tener más dinamismo al momento de rellenar strings:



Ahora contamos dos métodos distintos, cada uno de ellos realiza una acción independiente pero al centralizar la acción esperada en el método CompletarEspaciosDeClaves() podemos establecer un único camino a seguir para rellenar las claves de empleado, logrando hacer mucho más fácil de mantener nuestro código en caso de que la regla de negocio cambie (por ejemplo: rellenar con una longitud de 5 en lugar de 10).

Nota: En el ejemplo, el método RellenarConChar() se puede apreciar que se utliza una característica llamada "Extension Methods", los cuales se escapan al tema tratado en este post.

Para invocar la nueva funcionalidad podemos ver la diferencia entre el antes y el después:

El código comentado era la forma anterior de hacer el proceso, mientras que la nueva implementación se reduce a una sola línea de código.