DNM+ Online
dotnetmania 2.0
Introducción a los Patrones de diseño
¿Para qué inventar una solución si ésta ya existe? Básicamente, esa es la premisa que siguen los patrones de diseño y que tantos arquitectos han adoptado. Seguido os introducimos de lleno en ellos y os proponemos cambiar vuestro punto de vista en el a veces complejo mundo de la arquitectura de software.

En agosto de 1994 se editó un libro que inició un cambio en la forma de entender y trabajar en arquitectura de software, estableciendo unas bases que se han ido asentando durante estos ya más de diez años transcurridos desde su publicación. El título del libro es "Design Patterns: Elements of Reusable Object-Oriented Software" (traducido y publicado en español por la editorial Pearson en 2003), de los autores Erich Gamma, Richard Helm, Ralph Jonson y John Vlissides. Este equipo de autores también es conocido como el "Gang of Four" o GoF, literalmente, "la banda de los cuatro".
Puede afirmarse que este libro, basado en la tesis doctoral de Erich Gamma, ha revolucionado la arquitectura de software y llevado el diseño orientado a objetos a un nivel más alto. Si bien es cierto que, como la gran mayoría de inventores, el creador real del concepto de patrones permaneció relativamente en el olvido. La persona que hay detrás de los patrones de diseño es el arquitecto Christopher Alexander, que durante 1970 escribió dos libros, "A Pattern Language" y "A Timeless Way of Building", que además de ofrecer ejemplos describió sus razonamientos para documentar los patrones. Desde entonces, el movimiento pro-patrones estuvo muy quieto hasta 1987, momento en el que volvieron a resurgir, teniendo como resultado la tesis doctoral de Erich Gamma (1991) y finalmente, la publicación del libro citado inicialmente, que inicio el fenómeno de los patrones de diseño que actualmente conocemos. Para que nos hagamos una idea de la importancia de la labor de Alexander, podemos afirmar que ésta es similar a la de Noam Chomsky en el área de los lenguajes computacionales, pero aplicada a la arquitectura de software (más información en http://es.wikipedia.org/wiki/ Christopher_Alexander). "El lenguaje de patrones brinda a todo el que lo utilice el poder de crear una infinita variedad de construcciones nuevas y únicas, de la misma forma que su lenguaje común le brinda el poder de crear una infinita variedad de oraciones." Christopher Alexander. Patrones de diseño: ¿por qué?, ¿para qué? y ¿cómo? ¿Por qué? Seguramente os estaréis preguntando por qué deberíamos darle a este tema importancia o incluso nuestro tiempo, un bien tan escaso hoy en día, en el que aparecen nuevas tecnologías tan fascinantes como complejas y casi de estudio requerido... en el que los proyectos se nos acumulan, se complican y requieren que dediquemos horas extra, tanto en el trabajo como fuera de él, para auto-formarnos y poder resolver el problema que nos ha dejado "bloqueados" hoy al día siguiente… con el consabido y ya asumido problema de la falta de tiempo (y en algunos casos, de sueño). La respuesta la podríamos resumir en una simple frase: "porque alguien ya ha resuelto tu problema". Así de simple, así de fácil… Además, las soluciones están escritas, catalogadas y clasificadas. Básicamente, los patrones de diseño son el conjunto de experiencias de un gran número de desarrolladores y arquitectos de software, clasificados según los problemas más frecuentes en el diseño de software. Y además, nos encanta la reusabilidad, ¿no? Todos llevamos un gran vago dentro y nos encanta solucionar un problema o proponer una solución con el menor esfuerzo posible. Y si luego de resolverlo vemos que encima es la solución más optima en flexibilidad, adaptabilidad y con el menor acoplamiento posible, mejor aún, ¿no? Como resumen de lo dicho, he aquí otro párrafo de Christopher Alexander, citado en el ya mencionado libro del GoF, en la sección 1.1: "¿Qué es un patrón de diseño? Cada patrón describe un problema que ocurre una y otra vez en nuestro entorno, así como la solución a ese problema, de tal modo que se pueda aplicar esta solución un millón de veces, sin hacer lo mismo dos veces." ¿Para qué? Bueno, si esto no os convence y sois de la opinión "bueno, vale, los patrones pueden ayudarme, pero ¿para qué quiero aprenderlos si no me los van a valorar?". Básicamente, la respuesta vuelve a ser una frase: "para no reinventar la rueda, para aprovechar por una vía menos dura que la experiencia propia la experiencia de los demás…". Para proveer a nuestros clientes de soluciones probadas y consistentes, además de flexibles. Sí, en cierto modo me repito, pero es importante tener esto claro, ya que muchas veces quizás no nos vayan a apreciar el realizar un diseño de software adecuado, excepto cuando tengamos que modificarlo nosotros mismos o algún compañero, en cuyo caso estaremos haciéndonos un favor, así como a nuestros compañeros, dado que no saldrá la tan típica expresión "esto es un bodrio… quien haya hecho esto...", cosa que, profesionalmente, nos conviene… También pueden decir "esto es realmente complejo, no lo entiendo", lo cual también nos compensará, dado que solo con hacer la pregunta "¿te suena el concepto de patrones de diseño?" nos habremos posicionado como arquitectos de software.
Con la aplicación de los patrones, estaremos proveyendo a nuestros diseños de software de un lenguaje común que otros arquitectos podrán comprender y mediante el cual podremos dialogar con ellos. También nos mejorará como desarrolladores, o mejor dicho, como los arquitectos de software que pretendemos ser. Podría citar muchas otras razones de porqué utilizar patrones de diseño, pero todas se reducen a una muy clara y simple, que nos sonará si hemos trabajado algún tiempo con diseño orientado a objetos: evitar los errores (o dudas) más comunes de la POO (Programación Orientada a Objetos); la programación orientada a objetos está aún en pañales, y mi experiencia con otros profesionales me indica que no se le da la importancia que merece, tanto en centros de formación como en universidades, de las cuales la gente sale sin un conocimiento de la programación "real", con mucha confusión sobre el desarrollo orientado a objetos, quedando éste muy borroso, y con la sensación -muy real- de que solo es aprendido mediante la experiencia; algo costoso y doloroso, en muchos casos. Para verlo algo más claro, ¿qué mejor que un ejemplo? Un error muy común, por ejemplo, es la "muerte por herencia". Si tenemos una aplicación que debe acceder a un objeto de un determinado tipo (el tipo es de una "clase base"), teniendo la arquitectura que se muestra en la figura 1, entonces el desarrollador tiene (si no ha declarado la clase base como privada en la clase derivada) acceso completo a los métodos de la clase base, y la clase derivada debe asegurarse de implementar todas las funcionalidades de la clase base. Lo cual, plasmado en código, queda según se muestra en la figura 2 y el fuente 1. Esto nos parece realmente correcto, pero en la realidad Murphy existe y sus leyes se cumplen… Podemos perder el control de la clase base, quedando ésta bajo el control de otro desarrollador quizás menos comunicativo que nosotros y que "protege su trabajo", con lo que no tenemos opción o elección sobre la implementación de la clase base, pudiendo tener destructores no virtuales, o métodos que no han sido declarados como virtuales, y miembros privados... Todo ello nos determina de una forma drástica y nos hace imposible especializar un objeto vía derivación. Otra preocupación sobre la programación "por herencia" es el crecimiento de una estructura de herencia rígida, pudiendo aparecer problemas en lo que al principio parecía la solución ideal. Básicamente, las clases base pueden destrozar una aplicación con tan solo cambiar ligeramente su implementación (figura 3). Para solucionar este problema, tenemos el patrón de diseño Façade (fachada), que nos "proporciona una interfaz unificada para un conjunto de interfaces de un subsistema", según el libro "Patrones de diseño". Diciéndolo de una forma más comprensible, nos indica que utilicemos la encapsulación para implementar un wrapper (envoltorio) alrededor de otros objetos, algo que con la simple herencia no podemos hacer. Con ello tendríamos lo siguiente (figura 4). Esto, expresado en código, quedaría como se muestra en el fuente 2. Es decir, no deberemos modificar la aplicación para que continúe funcionando; solamente deberíamos adaptar la clase externa que hace las veces de fachada, con lo que tendríamos una mejor solución que simplemente aplicando la  herencia, obteniendo a la vez con ello un mantenimiento mucho menos costoso. Como hemos podido ver, las ventajas de aplicar los patrones de diseño son claramente evidentes, no solo en lo que respecta a la calidad del código o a su implícita reducción de costes, sino también en cuanto a acceso, soporte, diseño, extensibilidad y flexibilidad. Conceptos de los patrones de diseño Es importante, antes de ver los diferentes patrones existentes y su clasificación, analizar las características comunes entre ellos y los conceptos que comparten.
El más importante de todos es que los patrones no son implementaciones de código para un problema concreto. No es de código de lo que tratan los patrones, sino de conceptos e interacción entre ellos, proponiendo soluciones conceptuales que pueden tener muy diversas formas de implementación; cada cual deberá adaptarlos a su problema y arquitectura concretos. Los patrones de diseño básicamente, soluciones conceptuales que tratan sobre el diseño e interacción entre objetos y proporcionan soluciones reutilizables para resolver los problemas más comunes. Se representan normalmente mediante la ayuda de un diagrama UML. Existen unos principios fundamentales de diseño, que son subyacentes a los patrones de diseño, siendo el principio para la creación de soluciones flexibles: •    Programar para interfaces y no para una implementación (objetos). •    Potenciar la composición de objetos frente la herencia de clases.

Derivados de éstos, tenemos otros dos principios no menos importantes: •    Determinar qué es común y qué es variable. •    Encapsular las secciones identificadas como variables mediante una interfaz común. Por ejemplo, si definimos la interfaz IPerro y una clase cPastorAleman que la implemente (figura 5 y fuente 3). Esto sería programar para una implementación:

Dim Carla As cPastorAleman =
New  cPastorAleman Carla.Ladra()

Declarar la variable Carla del tipo cPastorAleman, una implementación concreta de IPerro, nos fuerza a codificar sobre una implementación concreta. Pero programar para una interfaz o supertipo, por ejemplo:

Dim Carla As IPerro =
New cPastorAleman Carla.Ladra()

Es mucho mejor, ya que sabemos que Carla es un pastor animal, pero podemos utilizar la referencia a IPerro polimórficamente, con lo cual en lugar de "fijar" en el código la instanciación de un subtipo, podríamos asignar la implementación concreta en tiempo de ejecución, haciendo aún más flexible nuestro código. Es más, podemos añadir diferentes tipos de perro a nuestra aplicación y ésta seguirá trabajando con ellos sin ningún cambio, mientras que de la otra forma, deberíamos programar código para cada nueva raza. Cabe destacar que los conceptos o principios que hemos visto, además de ser las bases de los patrones de diseño, son las bases de un correcto diseño orientado a objetos. Los patrones de diseño se consideran como la evolución de estos mismos conceptos, por lo que es muy importante entenderlos bien y tenerlos en mente. Clasificación de los patrones de diseño Hay tres tipos de patrones de diseño: •    Creacionales: abstraen el proceso de creación de instancias de objetos, ayudando a hacer un sistema que sea independiente de los procesos de creación, composición y representación de los mismos. •    Estructurales: enfocan los problemas de composición, estructuración y herencia de clases y objetos, así como su uso para componer estructuras de mayor tamaño. •    De comportamiento: son aquellos patrones que se centran en mejorar el modo en que las clases y objetos interactúan y se comunican entre ellos, repartiendo su responsabilidad.

Actualmente hay identificados 23 patrones de diseño, que se listan en la tabla 1. No entraremos en detalles aquí, ya que citarlos sin entrar en su "salsa" es como insultarlos; cada uno de ellos se merece un artículo entero para él, así son de importantes y potentes… ¿Cómo y cuándo utilizarlos? (y cuándo no) Aquí no se trata de reutilizar código, sino experiencia. Los patrones de diseño son conceptos y organización de los mismos que se transfieren fácilmente a código; pero lo que nos tiene que quedar claro son los conceptos y no el código (ojo: también ayuda, pero uno sin lo otro no tiene sentido). Si sólo aprendemos el código estaremos aprendiendo solamente el truco y no la técnica subyacente, que es lo que realmente importa. Si aprendemos los conceptos subyacentes, evolucionamos como arquitectos de software y aumentamos realmente nuestras armas de comprensión y solventación de problemas. Para saber usar los patrones de diseño hay que conocerlos, saber reconocerlos, entenderlos y comprender sus ventajas y beneficios, para luego aprender a implementarlos. Un ejercicio muy bueno consiste en identificar los patrones de diseño en nuestro día a día, tanto en .NET Framework como en la "vida real". Por ejemplo, un patrón de diseño de tipo façade lo podemos hallar en nuestro reproductor MP3, en el cual hay un wrapper que encapsula la complejidad interna y nos proporciona los métodos play, stop, pause, etc. Otro muy buen ejercicio es tratar de encontrar estos patrones dentro de nuestro código; esto nos desvinculará de la complejidad de abstraer estos conceptos en un entorno ya abstracto de por sí como son las líneas de código. Por último, también hay que tener en cuenta que pese a ser unas estupendas herramientas, no son "la técnica" definitiva ni la solución a todo. No hay que caer en la definición de desarrollador pattern happy, que a todo lo que toca intenta aplicarle cuanto más patrones, mejor. Hay momentos en los que aplicar patrones y también los hay para no hacerlo. Referencias Recomiendo sinceramente el libro de referencia que inició este cambio en el campo de la arquitectura de software: "Patrones de diseño: elementos de software orientado a objetos reutilizable", de Erich Gamma, Richard Helm, Ralph Jonson y John Vlissides (Pearson/Addison Wesley). Igualmente recomiendo el libro "Head First Design Patterns", de Elisabeth Freeman y Eric Freeman (editorial O'Reilly), que recientemente descubrí mientras me documentaba para este artículo y cuya exposición de los patrones de diseño es realmente magnífica.

blog comments powered by Disqus
autor
referencias