Patrones y Antipatrones: una Introducción - Parte I

Por León Welicki

Artículos relacionados

Patrones y Antipatrones: una Introducción - Parte II

Contenido

 Introducción
     Definición
     Patrones de software
     Características de un buen patrón
     Lenguajes y sistemas de patrones
     Niveles de patrones
     Pattern Happy
     Los patrones y la gestión del conocimiento
 Patrones de Diseño
     Principios de diseño
     Clasificación de patrones de diseño
     Relajación de patrones
     Sistemas flexibles y robustos con patrones de diseño
     Los patrones de diseño no son perfectos
 Referencias

Introducción

“El aprendizaje más importante proviene de la experiencia directa.”

Nonaka & Takehuchi

 

“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

 

Los patrones son una disciplina de resolución de problemas reciente en la ingeniería del software que ha emergido en mayor medida de la comunidad de orientación a objetos, aunque pueden ser aplicados en cualquier ámbito de la informática y las ciencias en general. Los patrones tienen raíces en muchas áreas, incluyendo la literate-programming y más notablemente en el trabajo de Christopher Alexander en Planeamiento Urbanístico y Arquitectura Civil.

A lo largo de este artículo analizaremos brevemente el concepto de patrón y su aplicación al software, deteniéndonos especialmente en los patrones de diseño, arquitectura y en los antipatrones.

Es importante aclarar que este artículo no pretende ser exhaustivo, sino más bien una introducción a un amplio abanico de temas que serán explorados en entregas posteriores.

Definición

Para comenzar, intentaremos establecer una definición básica del concepto de patrón. De la misma forma que sucede con otros conceptos de la informática (y como es el caso de la arquitectura), no es fácil establecer una definición taxativa y definitiva del concepto de patrón. De hecho, en el capítulo 2 del libro “Pattern Hatching” [Vlissides98], John Vlissides (miembro del GoF) hace hincapié en la dificultad de esta tarea. En las diversas obras de referencia podemos encontrar  diferentes definiciones. En esta sección intentaremos reunir a las más influyentes y significativas que nos permitan comprender la idea y establecer las bases para nuestro posterior estudio.

En el libro “The Timeless Way of Building” [Alexander79]  (obra de referencia donde se plantea por primera vez la teoría de los patrones aplicada a la Arquitectura Civil y Urbanismo), el Arquitecto Christopher Alexander define al patrón en la siguiente manera:

“Cada patrón es una regla de 3 partes, que expresa una relación entre un contexto, un problema y una solución. Como un elemento en el mundo, cada patrón es una relación entre un contexto, un sistema de fuerzas que ocurren repetidamente en ese contexto y una configuración espacial que permite que esas fuerzas se resuelvan entre sí.”

 

“Como elemento de un lenguaje, un patrón es una instrucción que muestra como puede ser usada esta configuración espacial una y otra vez para resolver el sistema de fuerzas, siempre que el contexto lo haga relevante.”

Continuando con la definición anterior, podemos agregar otro párrafo de Alexander, citado en la obra de referencia “Design Patterns” [GoF95] en la sección “¿Qué es un patrón de diseño?”:

“Cada patrón describe un problema que ocurre una y otra vez en nuestro entorno, para describir después el núcleo de la solución a ese problema, de tal manera que esa solución pueda ser usada más de un millón de veces sin hacerlo ni siquiera dos veces de la misma forma.”

Para Alexander, estos patrones son ubicuos y permiten alcanzar la “calidad sin nombre” (Quality Without a Name ó QWAN). Para aclarar estas definiciones, podemos utilizar un ejemplo concreto aplicado a la construcción, tomado también de la obra de Alexander:

“Si nos fijamos en las construcciones de una determinada zona rural, observaremos que todas ellas poseen apariencias parejas (tejados de pizarra con gran pendiente, etc.), pese a que los requisitos personales por fuerza han debido ser distintos. De alguna manera la esencia del diseño se ha copiado de una construcción a otra, y a esta esencia se pliegan de forma natural los diversos requisitos. Diríase aquí que existe un patrón que soluciona de forma simple y efectiva los problemas de construcción en tal zona.” [AIX77]

A modo de complemento, considero muy importante e interesante citar 2 principios postulados por Martin Fowler en “Analysis Patterns” [Fowler97] y que debemos tener en mente en todo momento al utilizar patrones:

  • Los patrones son un punto de partida, no un destino.

  • Los modelos no están bien o mal, sino que son más o menos útiles.

Como reflexión final de esta sección, podemos añadir que un patrón de diseño no es una solución en sí misma, sino la documentación de la forma en que construyeron soluciones a problemas similares en el pasado, lo cual permite una mejor gestión de la experiencia y transferencia de conocimientos.

Patrones de software

Si bien la teoría original de los patrones aplica a la construcción de casas y planeamiento urbanístico, también puede ser aplicada al software. Los patrones de software facilitan la reutilización del diseño y de la arquitectura, capturando las estructuras estáticas y dinámicas de colaboración de soluciones exitosas a problemas que surgen al construir aplicaciones.

De la misma forma que hemos buscado una definición para el concepto general de patrones en la literatura existente, haremos lo propio con los patrones de software. Una definición de este tipo de patrones que goza de amplia aceptación en la comunidad del software es la dada por Richard Gabriel en “A Timeles Way of Hacking” [Hillside03]:

style="color: #FF9900"“Cada patrón es una regla de 3 partes, que expresa una relación entre un contexto, un sistema de fuerzas que ocurren repetidamente en ese contexto y una configuración de software que permite que se resuelvan esa fuerzas.”

Como podemos fácilmente observar, esta definición es una adaptación al mundo del software de la definición dada por Christopher Alexander, citada en la sección anterior.

Otra definición complementaria, más enfocada en el ámbito técnico, es la que se da en el libro de Microsoft “Enterprise Development Reference Architecture” [Microsoft04]:

“Una descripción de un problema recurrente que ocurre en un contexto determinado y, basada en un conjunto de fuerzas, recomienda una solución. La solución es usualmente un mecanismo simple: una colaboración entre dos o más clases, objetos, servicios, procesos, threads, componentes o nodos que trabajan juntos para resolver el problema identificado por el patrón.”

Finalmente, no podemos dejar de citar la frase con que comienza el libro “Pattern Oriented Software Architecture , Volume 1” [Buschmann96], que incluimos a continuación:

“Los patrones le ayudan a construir sobre la experiencia colectiva de ingenieros de software experimentados. Estos capturan la experiencia existente y que ha demostrado ser exitosa en el desarrollo de software, y ayudan a promover las buenas prácticas de diseño. Cada patrón aborda un problema específico y recurrente en el diseño o implementación de un sistema de software.”

Características de un buen patrón

Documentar buenos patrones puede ser una tarea muy difícil. Citando a James Coplien en [Hillside03], un buen patrón:

  1. Resuelve un problema: Los patrones capturan soluciones, no principios o estrategias abstractas.

  2. Es un concepto probado: Capturan soluciones, no teorías o especulaciones. En el caso del “Design Patterns”, el criterio para decidir si algo era un patrón o no, era que éste debía tener al menos 3 implementaciones reales.

  3. La solución no es obvia: Muchas técnicas de resolución de problemas (como los paradigmas o métodos de diseño de software) intentan derivar soluciones desde principios básicos. Los mejores patrones generan una solución a un problema indirectamente (un enfoque necesario para los problemas de diseño más difíciles).

  4. Describe una relación: Los patrones no describen módulos sino estructuras y mecanismos.

  5. Tiene un componente humano significante: El software sirve a las personas. Los mejores patrones aplican a la estética y a las utilidades (de hecho,  no es casual que varios de los primeros lenguajes de patrones tengan que ver con temas estéticos y utilidades como Hot Draw ó ET++ ).

Lenguajes y sistemas de patrones

Un lenguaje de patrones contiene un amplio conjunto de patrones, cuyas combinaciones conforman su gramática. Según Alexander, un lenguaje de patrones provee la misma expresividad que un lenguaje natural, pero aplicada a la construcción. En su libro “A Pattern Language” [AIX77], presenta un lenguaje de 253 patrones aplicables a la arquitectura y urbanismo.

Un sistema de patrones mantiene unidos a sus patrones. Describe la forma en que se conectan y cómo se complementan entre ellos. Un sistema de patrones facilita el uso eficaz de los patrones en el desarrollo de software. Por lo tanto, podemos decir que un sistema de patrones es una colección de patrones, junto con las guías para su implementación, combinación y uso práctico en el desarrollo de software. Un sistema de patrones es similar a un lenguaje de patrones, aunque este último tiene fuertemente asociado el concepto de generatividad e implica que cubre todos los aspectos de importancia en un dominio particular. La combinación de sistemas de patrones puede conformar un lenguaje de patrones, donde la gramática se establece a partir de las combinaciones de estos patrones. Un lenguaje de patrones define una colección de patrones y las reglas para combinarlos en un estilo arquitectural. Los lenguajes de patrones describen frameworks de software o familias de sistemas relacionados.

Niveles de patrones

En “Pattern Oriented Software Architecture , Volume 1” [Buschmann96], se define una taxonomía como la que se muestra en la Figura 1. Los patrones en cada grupo varían respecto a su nivel de detalle y abstracción.:

Bb972242.art235-img01-564x252(es-es,MSDN.10).jpg
Figura 1: Patrones según el nivel de detalle , adaptado de POSA. Volver al texto.

Es importante destacar que esta división no es absoluta ni totalmente comprehensiva, dado que no incluye a otros patrones de amplia aceptación y utilización como los de análisis, integración de aplicaciones, pruebas, etc.

Pattern Happy

El término Patterns Happy aparece en el libro “Refactoring to Patterns” [Kerievsky04] y es un calificativo aplicable a los programadores que se refiere al uso indiscriminado de patrones, aún cuando su utilización no agrega ningún valor a la solución que se esta desarrollando. Un programador Pattern Happy aprende un patrón e “inmediatamente encuentra un lugar para abusar de él”. Para clarificar mejor este concepto, incluyo un breve párrafo de “Refactoring to Patterns” donde se define este calificativo de la siguiente forma:

¿Has aprendido alguna vez algún patrón de software y quisiste usarlo en ese mismo momento, porque te gustó? ¿Mucho? Entonces eres un amante de los patrones. Los patrones no son siempre la solución adecuada o mejor para un problema. Si bien añaden flexibilidad, también añaden complejidad. Es por esto que se debe ser cuidadoso al momento de seleccionar patrones. Siempre hay que recordar que los patrones son un punto de partida y que no son dogmas incuestionables. El uso indiscriminado de patrones, aún en situaciones donde no aportan ningún beneficio, puede ser un antipatrón o un claro indicador de ser un Pattern Happy (esto es “alguien que abusa de los patrones sin razón”).

Los patrones y la Gestión del Conocimiento

Los patrones permiten establecer un vocabulario común de diseño, cambiando el nivel de abstracción a colaboraciones entre clases y permitiendo comunicar experiencia sobre dichos problemas y soluciones.

Son también un gran mecanismo de comunicación para transmitir la experiencia de los ingenieros y diseñadores experimentados a los más noveles, convirtiéndose en unas de las vías para la gestión del conocimiento.

Lo que se pretende con un catálogo de patrones no es favorecer al diseñador experto (que quizás no necesite en absoluto los patrones), sino más bien ayudar al diseñador inexperto a adquirir con cierta rapidez las habilidades de aquél, como también comunicar al posible cliente, si es el caso, las decisiones de diseño en forma clara y autosuficiente [Cueva04].

Patrones de Diseño

Un patrón de diseño describe una estructura recurrente de componentes que se comunican para resolver un problema general de diseño en un contexto particular. Nomina, abstrae e identifica los aspectos clave de una estructura de diseño común, lo que los hace útiles para crear un diseño orientado a objetos reutilizable. Identifica las clases e instancias participantes, sus roles y colaboraciones y la distribución de responsabilidades. Tiene, en general, 4 elementos esenciales (los cuales se explican en gran detalle en el libro “Design Patterns” [GoF95]):

  • Nombre: Permite describir, en una o dos palabras, un problema de diseño junto con sus soluciones y consecuencias. Al dar nombres a los patrones estamos incrementando nuestro vocabulario de diseño, lo cual nos permite diseñar y comunicarnos con un mayor nivel de abstracción (en lugar de hablar de clases individuales nos referimos a colaboraciones entre clases).

  • Problema: Describe cuándo aplicar el patrón. Explica el problema y su contexto. A veces incluye condiciones que deben darse para que tenga sentido la aplicación del patrón.

  • Solución: Describe los elementos que constituyen el diseño, sus relaciones, responsabilidades y colaboraciones. La solución no describe un diseño o implementación en concreto, sino que es más bien una plantilla que puede aplicarse en muchas situaciones diferentes.

  • Consecuencias: son los resultados, así como ventajas e inconvenientes de aplicar el patrón.

Los patrones de diseño no son dogmas que deben ser aceptados. Qué es y qué no es un patrón de diseño, es una cuestión que depende del punto de vista de cada uno y del nivel de abstracción en que se trabaje.

La obra con mayor aceptación en esta campo (y podría decirse que en los patrones en general) es el libro “Design Patterns: Elements of Reusable Object Oriented Software” [GoF95]. En este libro se presenta un catálogo de 23 patrones que analizaremos en mayor detalle más adelante. Esta influyente obra ha sido escrita por un grupo de 4 autores a los cuales se conoce como el Gang of Four (GoF). Por tanto, muchas veces se hace referencia a este libro como “el libro del GoF”. Los patrones que se presentan en el libro del GoF han sido tomados de sistemas existentes y productivos. Una de las heurísticas para establecer un patrón, es que existan al menos 3 implementaciones en aplicaciones reales. Por tanto, los patrones de diseño no son abstracciones teóricas, sino que están fundados sobre una fuerte base práctica y pragmática, producto de la experiencia.

Principios de Diseño

En el libro del GoF se propone unos principios fundamentales de diseño subyacentes a los patrones de diseño que permiten crear aplicaciones más flexibles y robustas:

  • Programar para interfaces y no para una implementación.

  • Favorecer la composición de objetos frente a la herencia de clases.

Otros principios de gran importancia que se derivan de los principios anteriores son los que se detallan a continuación:

  • Determinar qué es común y qué es variable (commonality analisys).

    • Común = Estable

  • Permitir el reemplazo de lo variable mediante una interfaz común.

En este aspecto podemos trazar un paralelismo con los sistemas emergentes, dado que estos principios individuales, muy sencillos a nivel local, producen sistemas robustos y flexibles en el nivel macro.

Clasificación de patrones de diseño

Como ya dijimos, en el libro del GoF se presentan 23 patrones de diseño, divididos en 3 categorías, a saber:

  • De Creación: Abstraen el proceso de creación de instancias de objetos. Ayudan a hacer a un sistema independiente de cómo se crean, se componen y se representan sus objetos.

  • Estructurales: Tratan con la composición de clases u objetos. Se ocupan de cómo las clases y objetos son utilizados para componer estructuras de mayor tamaño.

  • De Comportamiento: Caracterizan el modo en que las clases y objetos interactúan y se reparten la responsabilidad. Atañen a los algoritmos y a la asignación de responsabilidades entre objetos.

En la a Tabla 1 se muestra la distribución de los 23 patrones en las categorías comentadas anteriormente:

 

 

De Creación

Estructurales

De Comportamiento

Ambito

Clase

Factory Method

Adapter (de clase)

Interpreter

Template Method

 

Objeto

Abstract Factory

Builder

Prototype

Singleton

Adapter (de objetos)

Bridge

Composite

Decorator

Façade

Flyweight

Proxy

Chain of Responsibility

Command

Iterator

Mediator

Memento

Observer

State

Strategy

Visitor

Tabla 1: Clasificación de patrones de diseño del GoF. Volver al texto .

Relajación de patrones

Muchas veces los patrones son seguidos estrictamente, olvidando que son más bien un punto de partida en lugar de una meta. Es interesante observar como incluso en el libro del GoF se relajan ciertas condiciones al momento de implementar un patrón. Para ver un ejemplo explícito de esto, se recomienda revisar la implementación del patrón Abstract Factory en C++ en este libro (hay también otra en Smalltalk).

Sistemas flexibles y robustos con patrones de diseño

En el capítulo 2 del libro del GoF, se presenta como caso de estudio la construcción de un editor de documentos, el Lexi. Luego de una primera lectura, se puede determinar que sus requisitos no funcionales incluyen la flexibilidad y la robustez (por ejemplo, el editor puede presentarse en múltiples sistemas de ventanas y cuando se crean objetos relacionados, siempre son de la misma familia).

Mediante el uso de patrones de diseño (en este caso concreto, se utilizan 8 de los 23 patrones presentados en el libro) se logra una solución que cumple con los requisitos no funcionales (y los funcionales) propuestos. Para mayor detalle sobre Lexi, ver el capítulo 2 de “Design Patterns” [GoF95].

Los patrones de diseño no son perfectos

Muchas veces se trata a los patrones de diseño como verdades universales. Esto no puede ser más incorrecto. De hecho, los miembros del mentado GoF destacan que los patrones no son un destino sino un punto de partida. En el libro “Patterns Hatching” [Vlissides98] John Vlissides, uno de los miembros del GoF, analiza los patrones de diseño tradicionales desde un punto de vista diferente, intentando quitar el aura de misticismo que los rodea, detallando incluso el proceso de descubrimiento de patrones utilizado por el GoF. En esa obra el autor vuelca el contenido textual de los correos donde se discute si Multicast debía ser un patrón individual o un caso particular del Observer. Finalmente, Multicast no se publicó como patrón en el libro del GoF. En esa misma obra trata temas críticos y muchas veces ignorados, tales como el ciclo de vida de un Singleton (¿Cuándo y cómo muere?), los problemas del Observer y cómo reemplazarlo en algunos casos por un Visitor y pérdidas de memoria en el Visitor, entre otros.

Referencias

[Alexander79]

Alexander, Christopher: A Timeless Way of Building, Oxford University Press, 1979.

[AIX77]

Alexander, Christopher et al.: A Pattern Language, Oxford University Press, 1977.

[BMMM98]

Brown, W., Malveau, R., Mc Cormick III, H., Mowbray, T.: Antipatterns: Refactoring Software, Architectures and Project in Crisis, Wiley and Sons, 1998.

[Buschman96]

Buschmann, Frank et al.: Pattern Oriented Software Architecture, Volume 1: A System of Patterns, Willey & Sons, 1996.

[Cueva04]

Cueva Lovelle, Juan Manuel: Tecnología de Objetos: Patrones de Diseño, 2004.

[Evitts00]

Evitts, Paul: A UML Pattern Language, SAMS Publishing, 2000.

[Fowler03]

Fowler, Martin: Enterprise Application Architecture Patterns, Addison Wesley, 2003.

[Fowler97]

Fowler, Martin: Analysis Patterns: Reusable Object Models, Adisson Wesley, 1997.

[Fowler99]

Fowler, Martin: Refactoring: Improving the Design of Existing Code, Adisson Wesley, 1999.

[Gall75]

Gall, John: Systemantics: How Systems Work and Especially How They Fail, New York, Quadrangle, 1975.

[GoF95]

Gamma E., Helm, R., Johnson, R., Vlissides J.: Design Patterns: Elements of Reusable Object Oriented Software, Addison Wesley, 1995.

[Hillside03]

Hillside Group: Home of the Patterns Library, 2003 <en línea> http://hillside.net/ .

[Hophe03]

Hophe, Gregor, Woolf, Robert: Enterprise Integration Patterns: Designing, Building and Deploying Messaging Solutions, Addisson Wesley, 2003.

[Kerievsky04]

Kerievsky, Joshua: Refactoring to Patterns, Addison-Wesley, 2004.

[McCormick98]

McCormick, Hays: Antipatterns Tutorial, 1998 <en línea> http://www.antipatterns.com/briefing/sld001.htm. .

[Microsoft03]

Microsoft Corp: Enterprise Solution Patterns, Microsoft Press, 2003.

[Microsoft04]

Microsoft Corp: Enterprise Development Reference Architecture, Microsoft Press, 2004.

[PPR04]

C2 WikiWikiWeb: Portland Pattern Repository <en línea> http://c2.com/ppr/ .

[ST01]

Shalloway, Alan; Trott James: Design Patterns Explained: A New perspective on Object Oriented Design, Pearson Education, 2001.

[Vlissides98]

Vlissides, John: Pattern Hatching: Design Patterns Applied, Addison Wesley, 1998.

León Welicki es Profesor Asociado de Ingeniería Web en el Máster en Ingeniería del Software de la Universidad Pontificia de Salamanca, Madrid, España; donde actualmente está realizando el Doctorado en Ingeniería Informática, su tesis doctoral trata sobre las Arquitecturas de Software y Paradigmas No Convencionales para Ingeniería Web. Trabaja como Arquitecto de Software. Cuenta con más de 12 años de experiencia profesional en diversas áreas de la Ingeniería del Software.

Mostrar: