design patterns - estructurales - ¿Cuándo son los patrones de diseño el problema en lugar de la solución?
patrones de diseño web (26)
La forma de un programa debe reflejar solo el problema que necesita resolver.
¿Y qué sucede cuando los requisitos cambian y su módulo no se abstraía usando una Fachada o potencialmente un Mediador, lo que hacía que fuera demasiado difícil de intercambiar?
los patrones de diseño son un signo de no suficiente abstracción
Lo más probable es que si ha abstraído todo correctamente, entonces tenga un patrón de diseño en alguna parte.
¿Qué ocurre si hay un objeto extremadamente pesado que no tiene que cargarse? El patrón de Proxy le ahorra al usuario esperar para siempre.
Podría continuar, pero creo que ya dije lo suficiente. Los patrones de diseño son excelentes herramientas cuando se usan correctamente. El problema surge cuando se usan incorrectamente, pero supongo que es por eso que los patrones mal utilizados se llaman antipatrones.
Nunca he trabajado en software donde necesitaba usar patrones de diseño. Según el ensayo de La venganza de los nerds de Paul Graham, los patrones de diseño son un signo de que no hay suficiente abstracción.
Para citarlo directamente, "Por ejemplo, en el mundo OO escuchas un buen trato sobre" patrones ". Me pregunto si estos patrones no son a veces evidencia del caso (c), el compilador humano, en el trabajo. Cuando veo patrones en mis programas, lo considero una señal de problemas. La forma de un programa debe reflejar solo el problema que necesita resolver. Cualquier otra regularidad en el código es una señal, al menos para mí, de que estoy usando abstracciones que no son lo suficientemente poderosas, a menudo porque estoy generando a mano las expansiones de algunas macro que necesito escribir ".
Me preguntaba si todos pensaban que los patrones de diseño se usan en exceso y son síntomas de no tener suficiente abstracción en el código.
Creo que Paul Graham se está perdiendo la marca a lo grande en esta. El uso de patrones no se trata de elegir un libro que los liste y aplicar algunos de ellos a su código. Estoy de acuerdo en que sería una mala elección, pero de eso no se tratan los patrones.
Los patrones de diseño son simplemente una forma de reconocer "Oye, reconozco que esto es similar a otro problema que he resuelto antes" y aprender a crear una buena abstracción de la solución para que sea aplicable en situaciones apropiadas.
De hecho, lo más probable es que, si ha programado algo de cualquier tamaño razonable, haya utilizado patrones de diseño conocidos y simplemente no sabía que había un nombre para él. Por ejemplo, estaba usando el patrón de "fábrica" durante mucho tiempo antes de tener idea de que era una "fábrica". Saber cómo se llama oficialmente solo me impide reinventar la rueda otra vez.
Seguro que algunos patrones bien conocidos son un poco asquerosos; Singleton es definitivamente sospechoso. Pero ese era un caso claro de una solución demasiado inteligente que buscaba un problema para resolver y no lo hacía muy bien. Pero es por eso que puedes encontrar mucha literatura tanto a favor como en contra, porque las personas reconocen que puede no ser una buena solución.
Pero los patrones como un todo son algo muy bueno, si acaso alientan la abstracción.
Creo que a veces, cuando aprendes un patrón, no solo aprendes el patrón. Pero adquiere una nueva vista en el dominio del problema que quizás no haya tenido antes. Y tal vez es exactamente lo que querías.
Sin contexto para el "problema", no podemos decir si los patrones de diseño son la solución o no.
Creo que esta parte de la cita de Paul Graham es importante:
[...] Estoy usando abstracciones que no son lo suficientemente poderosas, a menudo estoy generando a mano las expansiones de algunas macro que tengo que escribir [...]
Muestra que si puedes construir estas abstracciones en tu idioma (y puedes hacer casi cualquier cosa con Lisp, que es lo que probablemente tiene en mente diciendo lo anterior), no necesitas modelarlas con patrones.
Pero no todos usan Lisp, por lo que solo podrás crear abstracciones donde puedas y usar patrones donde no puedas. Como ejemplo, en idiomas sin funciones de orden superior , estos a menudo se modelan utilizando el patrón de estrategia .
Parece ser una cuestión de cómo se mire: el patrón se puede ver como un síntoma de un problema (por ejemplo, la falta de funciones de orden superior), o como una solución del problema (por ejemplo, hacer algo así como un orden superior funciones posibles a través del patrón de estrategia).
Creo que la afirmación de Paul Graham es que los patrones de diseño deberían expresarse en el lenguaje. Si hay un patrón X, significa que las personas se ven obligadas a reescribir secuencias de código para hacerlo, y debe haber una forma específica de lenguaje para expresarlo. Esto podría integrarse en el lenguaje (aunque es incómodo y puede crear nuevos patrones de diseño), o podría ser automatizable dentro del lenguaje (como las macros de Common Lisp; las plantillas de C ++, particularmente cuando se usan de forma extraña, pueden hacer lo mismo a veces).
Por ejemplo, consideremos un patrón mucho más simple: el ciclo de incremento. Tener que hacer algo en cada elemento de una secuencia es bastante común, y si no tuviéramos algo que corresponda a una declaración for, sin duda adoptaríamos alguna convención de codificación común para expresarlo, y alguien (o un cuarteto) empacarían eso juntos. con otras construcciones similares elementales y escribe un libro sobre eso.
De forma similar, si usa un patrón de fábrica, un idioma podría incluir una función de fábrica o podría automatizarse dentro del idioma. Específicamente, Paul quiere poder escribir una macro Lisp para implementarla, en lugar de escribir Factories él mismo una y otra vez.
El peligro de utilizar un patrón de diseño es que es un marco de código familiar que seguimos escribiendo y, por lo tanto, tenemos trozos de código que tendemos a no leer ni escribir con toda la atención. El inconveniente es que son códigos que tenemos que escribir una y otra vez, y la sensación de que la reescritura realmente debe ser automática.
Si los patrones son una parte esencial del uso de los lenguajes, como dice el GoF, o pueden abstraerse, como dice PG, es fundamentalmente una pregunta empírica, probablemente mejor resuelta buscando idiomas donde los patrones en sí mismos son innecesarios y observando para ver si Realmente necesito nuevos patrones.
Cuando programé en LISP, no usé patrones de diseño GoF, simplemente no era aplicable para los programas que estaba escribiendo. Ahora estoy programando en C # y me encuentro con situaciones todo el tiempo donde un patrón de diseño realmente simplifica el programa que se está escribiendo.
Durante la fase de diseño de mis programas, a menudo analizo primero el problema y, una vez que lo descompone, puedo comenzar a reconocer fácilmente los patrones inherentes al diseño. En ese momento, puedo comenzar a aplicar patrones de diseño bien conocidos para que cuando llegue el momento de comunicar o implementar el diseño, tenga un lenguaje común que pueda usar para la comunicación y, con suerte, pueda reutilizar algunos objetos genéricos que fueron implementado previamente durante la implementación de un patrón similar.
Muchas veces, cuando los patrones de diseño se aplican incorrectamente, es porque el proceso ocurre al revés. El programador Joe (mis disculpas a los que se llaman Joe) lee un libro sobre Patrones de diseño y dice "Ok, entiendo Design Pattern X, ¿cómo puedo aplicarlo a mi aplicación?" Esto está mal.
Los patrones de diseño pueden ser un arma poderosa, pero como cualquier otra cosa, deben usarse de manera apropiada, y el programador siempre debe estar preparado para incorporar algunos pensamientos originales en su diseño.
El término Patrones de diseño está sobrecargado y es confuso.
Hay una manera estrecha de pensarlo: básicamente como un nombre colectivo para los conceptos de OO enumerados en el libro de GoF, por ejemplo, Singleton, Fachada, Estrategia. Probablemente use esta definición si coloca patrones de diseño como competencia en su CV.
Un proyecto puede contener fácilmente docenas de objetos únicos. Este patrón obviamente se beneficia de ser codificado como una abstracción instanciable, por ejemplo, como una clase macro o abstracta. Del mismo modo para muchos de los otros patrones en el libro de GoF.
Me parece que la tesis de Paul Graham es: los patrones de diseño, que son formas estándar de repetirse, deben codificarse como abstracciones instantáneas, y por corolario debe usar un lenguaje que tenga una forma muy flexible de definir la abstracción instantánea.
Pero el concepto es más general: creo que tergiversa los patrones de diseño. Christopher Alexander inventó el concepto para aplicarlo al diseño de países, ciudades, pueblos y casas. Los diseñadores de juegos tienen lenguajes de patrones como Niebla de guerra, Habilidades asimétricas, etc.
En este sentido general, se vuelve mucho menos obvio que los patrones de diseño deberían todos ser codificados como abstracciones instanciables.
Si no ha leído A Pattern Language, consulte el alcance here . Imagina algo así para el mundo del software. Los patrones de GoF estarían muy abajo en la parte inferior del ToC: son detalles de implementación.
¿Qué otros patrones podrías encontrar por encima de ellos?
Supongo que un capítulo tendría patrones relacionados con el juego. Podría incorporar patrones de diseño de juego y técnicas de implementación, y afirmo que esta no es una distinción clara, como Game Loop, World Entity, Spatial Hash, Height Map Map, etc. Estos son todos los patrones de diseño.
Ahora, en el alcance de un proyecto de juego, probablemente solo tendrá una implementación de Entidad Mundial. Cualquiera que trabaje en cualquier idioma tendría el sentido común de hacer de esta Entidad Mundial una abstracción instanciable como una clase base.
Pero lo que el patrón describe es cómo se forma esta abstracción: contiene alguna noción de posición, es renderizable, y así sucesivamente. No es obvio si este patrón de diseño se beneficiaría de ser codificado como una clase macro o abstracta en sí misma: ¡el patrón ya describe una abstracción! ¿Haría una metaclase para implementaciones de entidades mundiales? ¿Una macro para definir las clases de entidades mundiales, con todo tipo de parámetros impíos?
Mirando más arriba en la Tabla de Contenidos imaginaria, vemos que estos patrones están subordinados a un patrón más general, el del Juego. ¿Vale la pena codificar como una clase macro o abstracta? Tal vez. Pero no obviamente Estamos hablando de un marco de juego, donde se define un juego de computadora pasando parámetros, rellenando los espacios en blanco, etc. Eso podría ser productivo y divertido, pero no es la única manera de hacer las cosas.
La plataforma Erlang tiene abstracciones instanciables para patrones tan generales como el Servidor, lo cual es genial. Y creo que un proyecto de Erlang tiene tantos servidores como un proyecto de Java tiene Singletons.
Pero para sus propósitos específicos, si está trabajando en Lisp, o Haskell, o lo que sea, y escribe un servidor, a veces basta con seguir el patrón de Servidor, implementarlo como funciones y objetos antiguos, sin intentar hacer un abstracción de todo el asunto.
Todos los patrones de diseño no son patrones de texto de bajo nivel en su código fuente.
En pocas palabras, los patrones son solo formas formalizadas de resolver tareas comunes en varios idiomas. Como tal, hubo "patrones de diseño" incluso antes de que alguien acuñara el término. Para cada idioma hay "mejores prácticas" y los patrones de diseño son solo eso: un conjunto de mejores prácticas para problemas que ocurren de forma regular.
Uno de los principales beneficios de etiquetar los patrones es que la terminología compartida nos permite hablar de conceptos abstractos.
Obviamente, los patrones de diseño pueden ser mal aplicados o utilizados en cualquier contexto dado, pero realmente no veo cómo los patrones de diseño como un concepto pueden ser un problema.
Esa frase no tiene sentido: los patrones de diseño son un signo de la abstracción no suficiente. ¡Los patrones de diseño son una abstracción! Siguiendo las respuestas aquí, estoy de acuerdo en que los lenguajes de programación deben tener una forma de expresar patrones de diseño. Sin embargo, eso obviamente no es posible para cada situación.
Hay muchas máximas que usamos (y que son comunes en torno a SO) que, si las rastreas de vuelta a la fuente, originalmente se afirmaron con reservas; como en "... cuando estás desarrollando usando ..." Este es uno de esos casos. Los patrones se ajustan bien cuando estás haciendo POO. YMMV cuando estás en otro paradigma.
"Refactorización" es otro caso similar.
Cuando estoy escribiendo SQL, la parte de "patrones" de mi cerebro se apaga.
Tenga en cuenta en su cita: "Estoy generando a mano las expansiones de algunas macro que tengo que escribir". Entonces él reconoce patrones y los abstrae en una macro, no lo vuelve a codificar de otra manera. Solo bueno, viejo. No son los patrones, está fallando en hacer lo correcto con los que encontramos. Yo diría que su comentario podría entrar en cualquier entrada de la wiki expandiendo las virtudes de DRY, y cómo poseerlas. GoF concuerda completamente: reconoce los patrones de desgin, luego usa lo que sabes sobre ellos para implementarlos (o refactorizarlos) apropiadamente.
Hay un momento y lugar para todo. He visto código con demasiados patrones, lo que estaría de acuerdo con su punto, pero también con no suficientes patrones, lo que hace que el código sea difícil de mantener y propenso a errores cuando se realizan cambios.
Generalizar algo como esto va a tener una falla lógica, pero si reformulas tu pregunta a algo como "¿puede haber demasiados patrones en el código que es sintomático de un problema mayor, es decir, niveles insuficientes de abstracción", entonces el la respuesta sería sí. ¿Es siempre el caso? No.
Los lenguajes de programación, como los hablados, le proporcionan el vocabulario para decir lo que quiera. Los patrones solo describen una manera de decir cosas que le permite a la gente saber de lo que está hablando en un nivel superior.
Si me complace en una metáfora: escribir música es un "problema" común y la música a menudo (obviamente no siempre) está flojamente compuesta como algún tipo de variación en lo siguiente:
verso coro verso coro verso coro estribillo
Lo cual, de hecho es un ''patrón''. Sin embargo, todavía necesita escribir la canción y no todas las canciones escritas funcionarán bien con este patrón.
El punto al que trato de llegar es que los patrones no son una solución plug-play-done para programación o música. Son una guía para que comiences y un trampolín desde el que puedes hacer algo que se adapte a tus necesidades.
Los patrones de diseño se definen como los siguientes (de wikipedia, pero también he leído lo mismo en algunos libros)
En ingeniería de software, un patrón de diseño es una solución general reutilizable para un problema común en el diseño de software. Un patrón de diseño no es un diseño terminado que se puede transformar directamente en código. Es una descripción o plantilla de cómo resolver un problema que se puede utilizar en muchas situaciones diferentes.
Si observa la aplicación de patrones directamente desde el desplazamiento sin entrar en el dominio del problema de forma extensa, puede ocasionar problemas. Utilice patrones de diseño como una guía o más, como una sugerencia / sugerencia para resolver un problema. El patrón de diseño aplicado con fuerza seguramente no dará una solución que sea lo suficientemente abstracta. A menudo se ve que en el software de Enterprise se usa una variante o una combinación de algunos patrones de diseño, una especie de híbridos. Si dices que nunca has usado patrones de diseño, te alegrará saber que algo así como un bucle foreach es en realidad un patrón de interacción y puedes buscar implementaciones más obvias cerca de ti.
Los patrones de diseño son soluciones para problemas comunes.
Pero primero, necesita saber qué o dónde está el problema. Y ese es el punto donde las personas no pueden usar los patrones correctamente.
Los patrones son el problema si no son una solución. Con esto quiero decir: si se introduce un patrón por el patrón y no para resolver un problema de diseño real existente en la aplicación, es probable que cause problemas en lugar de resolverlos o prevenirlos.
Sigo diciendo a la gente aquí en el trabajo que el libro La pandilla de los cuatro (Patrones de diseño: elementos del software reutilizable orientado a objetos) es una referencia, no un manual para un buen diseño.
Los patrones son realmente solo una forma de describir cómo funcionan las cosas. Es una forma de clasificarlos. ¿Hay algunos programas que los usan en exceso? Por supuesto. La mayor ventaja de tener patrones es que al clasificar algo como esto o aquello, todos están en la misma página (suponiendo que tengan el nivel de conocimiento para saber de qué se está hablando). Cuando tiene un sistema con 10.000 líneas de código, es necesario poder determinar rápidamente cómo algo va a funcionar.
¿Esto significa que siempre debes usar patrones, no? Eso llevará a problemas para forzar a las cosas a una clasificación, pero tampoco deberías alejarte de ellas.
Mi problema con los patrones es que parece haber una mentira central en el núcleo del concepto: la idea de que si de alguna manera puedes categorizar el código que escriben los expertos, cualquiera puede escribir un código experto simplemente reconociendo y aplicando mecánicamente las categorías. Eso suena genial para los gerentes, ya que los diseñadores de software expertos son relativamente raros.
El problema es que no es verdad. No puede escribir código de calidad experta con solo "patrones de diseño", como tampoco puede diseñar su propia ropa profesional de calidad con solo patrones de costura .
No creo que los patrones en sí sean el problema, sino más bien el hecho de que los desarrolladores pueden aprender patrones y luego aplicarlos de forma exagerada, o aplicarlos de maneras que son extremadamente inapropiadas.
El uso de patrones es algo que los programadores experimentados simplemente aprenden de forma natural. Has resuelto algún problema X muchas veces, sabes qué enfoque funciona, usas ese enfoque porque tu habilidad y experiencia te dicen que es apropiado. Ese es un patrón, y está bien.
Pero también es posible que un programador menos capacitado encuentre una forma de hacer las cosas e intente encauzar todos los problemas que encuentren en ese molde, porque no lo conocen de otra manera. Ese es un patrón también, y es malvado.
Nunca es necesario utilizar patrones de diseño; siempre se puede escribir código que ignora todo lo que se ha aprendido sobre la codificación hasta ahora; incluso puede funcionar. Pero los patrones de diseño pueden facilitar las cosas, dándole un lenguaje compartido para discutir el diseño.
Los patrones de Diesign no representan una abstracción muy pequeña: son un intento de aumentar el nivel de abstracción. Puede decir "este bit es un visitante" en lugar de "aquí hay un código que atraviesa recursivamente un árbol de objetos, actuando sobre su funcionamiento".
Prefiero trabajar con demasiados patrones que ninguno en absoluto. Dicho esto, el equilibrio adecuado es, por supuesto, el objetivo.
Recuerdo una entrevista con uno de los GoF donde alguien preguntó sobre el reclamo común de que los patrones de diseño son herramientas para reemplazar las características que faltan en un idioma. El autor argumentó que A) cualquier lenguaje tiene patrones de diseño (no los mismos) ya que los patrones de diseño son herramientas creadas para trabajar alrededor de idiosincrasia del lenguaje y B) no es posible deshacerse de su necesidad agregando más características a un idioma.
Sí, pg está ahí. Si ve un código similar en su aplicación, significa que le falta una abstracción de ese código. Menos código es mejor.
Aquí hay otro artículo sobre el tema: http://blog.plover.com/prog/design-patterns.html
Todavía no he encontrado un uso para GoF "Design Patterns" en mi código. El coderati parece haberse pegado al libro de GoF, y ahora se espera que en la mayoría de las empresas los conozca y los aplique. Hoy mismo tuve una entrevista y me preguntaron qué patrones conocía y había usado, y cómo los aplicaría a una aplicación empresarial para un banco importante.
La idea genérica de aprender de nuestros proyectos anteriores obviamente tiene sentido. Lo que no tiene sentido es la exageración y el culto en torno a los patrones específicos de GoF, las personas confundiéndolos con buenas prácticas de codificación, y se espera que los amen y los acepten para ser llamados desarrolladores competentes.
Entonces, para responder a su pregunta, diría que la idea del GoF de los patrones de diseño es mal interpretada y usada en exceso por la mayoría. Necesitamos madurar en un uso de alto nivel de los patrones de diseño como una herramienta general de aprendizaje que se aplica a la forma en que aprendemos y refinamos el OO, no solo como 20 ideas para memorizar e imponer en los programas. No hay bala de plata.
Vamos amigos, por favor, lean toda la cita, léanla detenidamente. O mejor aún, lee el ensayo.
Paul Graham critica, entre otras cosas, los lenguajes tipo C por no proporcionar los medios adecuados de abstracción. Dentro del alcance del ensayo, su crítica de los patrones es una idea de último momento, o más bien un caso puntual para su argumento principal. Su razonamiento es así:
Es lógico usar estrategias comunes para resolver problemas recurrentes. En lenguajes realmente abstractos, es posible formalizar esas estrategias y ponerlas en una biblioteca. Siempre que necesite usarlos, simplemente # los incluye, ejemplifíquelos, amplíelos o lo que sea. Los lenguajes tipo C, por el contrario, no proporcionan los medios necesarios para la abstracción. Eso es atestiguado por el hecho de que existe algo así como "patrones". Un patrón es una estrategia tan común que el código de la biblioteca no puede expresar y, por lo tanto, debe escribirse expresivamente cada vez que se aplica.
Paul Graham no cree que los patrones sean malos por sí mismos. Son un síntoma de los idiomas que no proporcionan medios de abstracción. En ese sentido, casi con certeza tiene razón. Si deberíamos usar diferentes idiomas debido a eso, es por supuesto otra discusión.
El cartel original de la pregunta, por otro lado, es incorrecto: los patrones no son "síntomas de no tener suficiente abstracción en tu código", sino que son síntomas de no tener suficientes medios de abstracción en tu idioma.
[suspiro] ¿Cuántas quejas contra las buenas prácticas tenemos que desacreditar antes de que las personas comiencen a usar su propio juicio?
Respuesta corta: si está haciendo un trabajo real en un lenguaje orientado a objetos, hay una gran probabilidad de que haya implementado algunos de los patrones de diseño GoF para hacer el trabajo. Si te das cuenta de que has hecho esto o no es una cuestión de educación, perspectiva e introspección. Negar que alguna vez hayas hecho esto o que los patrones no existan o no sean "necesarios" o se "usen en exceso" es ridículo, a menos que nunca escribas algo más complejo que ''hola mundo'' ;-)
El otro día tuve que implementar una fachada de visitante para un singleton solo para lograr que la estrategia del adaptador funcione :-P