 Buenas tardes. Mi nombre es Romel Castro. Hoy vengo agradecido con la comunidad, verdad, por darme la oportunidad de estar aquí. Quiero darle gracias a los organizadores también por haberme seleccionado para el día de hoy y para este work in 2022. Quiero también agradecer a los patrocinadores de ese evento, verdad, por su aporte y a la comunidad por compartir aquí conmigo. Mi nombre es Romel Castro. Tengo alrededor de 15 años desarrollando aplicaciones y escribiendo código. Es una de las mayores pasiones. Uno de mis segundos proyectos fue en WordPress. Fue eso por allá del año 2018. Desde ese momento pues me enamoré WordPress, me enamoré de su comunidad y para mí cada año es un privilegio poder compartir con la comunidad. Me encanta ser parte de ella. No me gusta Star Wars ni Star Trek. No soy un poco diferente a otros programadores, verdad. Me gusta el código limpio, me gusta la buena arquitectura y el diseño de software que son temas que a yo ser autodidacta pues me ha tocado aprenderlos y eso es algo que escucho, verdad, o solamente cuando comento que soy una persona autodidacta. Y parte de eso ha sido aprender esas bases de las que se encien a la universidad, pero que muchas veces no aprendemos por nuestro cuenta. Y hoy quiero hablar de uno de ellos. ¿Qué se llama? Patrones de diseño. Y como se pitó la vasta chara, le puse la solución a muchos problemas. Y ya vamos a ver por qué los patrones de diseño son la solución a muchos problemas que no tuvimos en nuestro código. Pero, ¿qué son los patrones de diseño? Los patrones de diseño son soluciones típicas a problemas comunes que tenemos en el diseño de software. ¿Qué sucede? Que con los años vamos notando de que muchas veces nos encontramos en un mismo problema, verdad. Ya sea por la manera en que mis objetos trabajan, la manera en que se comunican o la manera en que siguen en que yo creo esos objetos o creo mis clases. Y cada software, cada nuevo programa que escribimos, si bien tiene sus diferencias y tiene sus propias reglas de negocio, a final de cuentas nos vamos a encontrar con problemas y paradigmas que se repiten una y otra vez, ¿verdad? ¿Y qué sucedía en mi caso? Volver a pensar en una solución. ¿Cómo hago para solucionar este problema? Hasta que un día me tomé el tiempo, verdad, de leer ese libro que salió por el Gung-O-Forn. El Gung-O-Forn son cuatro probadores que ellos decidieron tomar todos esos problemas que ellos habían visto en su carrera y definirlos en cuatro categorías y, entre cada uno de ellos, poner una serie de patrones que nos van a ayudar a diseñar nuestro código y, aún mejor, a obtener una solución a esos problemas comunes que tenemos. Como les comento, ellos separaron eso en tres categorías. ¿Verdad? ¿Cuáles son las ventajas de aprender este los patrones de diseño? Uno, nos vamos a arreglar mucha energía. ¿Por qué? Porque es un problema de que ya se ha resuelto, al cual yo ya no tengo que buscarle una solución, la manera de comunicarlo también. Si tenemos un lenguaje común con nuestros amigos formadores, con los otros personas del equipo, verdad, yo le puedo decir, vamos a utilizar un singleton para resolver este problema. Ya no tenemos que ir, verdad, y ver toda la solución o tratar de buscarla o inclusive explicarla, porque ya es un lenguaje común y ya es una solución que se ha implementado y que se ha aprobado. Entonces eso va a hacer el proceso de desarrollo muchísimo más ágil, más fácil y vamos a poder utilizar esa energía en los problemas del negocio. O sea, hay problemas de los cuales ya no nosotros, no nos vamos a tener que preocupar. Las categorías de esos patrones de diseño son las siguientes. Tenemos los creacionales o creacional que es, estos promueven mecanismos flexibles y reutilizables para la creación de objetos. Que sucede muchas veces que nuestro software, verdad, el software está completo, está, está complementado de una serie de objetos, una serie de partes y esas partes a veces tenemos que crearlas, que es lo que solamente llamamos instancias o clases o objetos. Por ejemplo, tenemos una tienda que tiene órdenes y esa orden también tiene productos. Entonces qué implica eso, que mi orden, yo para crear mi orden también tuve que haber creado productos y tengo que tener estos productos y eso es un problema muy repetitivo. Todo nuestro software va a requerir que creemos instancias, que creemos objetos y eso va a representar problemas cuando el diseño es muy complejo, cuando nuestro código es muy complejo. Entonces los patrones creacionales nos van a traer una solución. Después tenemos los estructurales que nos van a dar flexibilidad a la hora de manejar la organización de nuestros objetos y de nuestras clases y eso también es muy común, verdad, siempre nos preguntamos dónde pongo el código, verdad, cómo se, cómo se paro, verdad, los conceptos de mi negocio, los, la lógica de mi negocio. Y tenemos también comportamiento, porque si bien la verdad de negocio en cada software son diferentes, hay comportamientos que son muy similares, ya sea porque hay responsabilidades que se van a compartir o también porque tenemos responsabilidades que van a ir de manera lineal y esos problemas son muy comunes. Entonces ya tenemos un set de patrones que van enfocados también en el comportamiento. Vamos a ver ejemplos de cada uno de nuestros patrones en cada una de las categorías. Lo primero que vamos a ver y creo que es de los más utilizados y en mi caso de los primeros que aprendí son los creacionales. El primero que vamos a ver es el constructor o en inglés ese se llama builder, que es lo que permite el builder, me permite construir en palabras muy sencillas, objetos, pero objetos que son complejos, verdad, paso a paso y cuál es la, el propósito de este de este patrón es simplificar la construcción de esos objetos, poder separarla. ¿Qué sucede? Que muchas veces, verdad, estamos escribiendo nuestro código y nos damos cuenta de que necesitamos crear una orden y que para crear esa orden también necesitamos crear los productos y que para crear esos productos a su vez también hay que construir otros otros tipos de objetos y llegamos y escribimos todo el código en un solo lugar, verdad, en un solo archivo o inclusive en una sola función y tenemos este código que está totalmente tightly crouple, verdad, es difícil de desearlo, es difícil de extenderlo inclusive, verdad, todo está en una sola función. Entonces este patrón nos va a permitir ver los distintos tipos que se están creando aquí y separar eso. ¿Para qué? Para que se pueda hacer también, fue utilizado y también para tener un orden, verdad, y también tener los requerimientos de negocio dentro de este objeto que es mi constructor. Vamos a ver un ejemplo de un builder en PHP. Entonces yo me voy a mi idea, verdad. Y en este caso, yo lo que voy a crear es una solución en mi código para poder trabajar con diferentes bases de datos, ¿verdad? ¿Por qué? Porque cada una, yo lo voy a usar para diferentes cosas, pero yo necesito que mi software, todo mi software pueda trabajar con todas estas bases de datos sin hacer muchos cambios en mi código. Pero ¿qué sucede? Que todo esto tiene muchas similitudes, verdad. Si nosotros vemos las bases de datos es escribir datos, obtener datos, actualizar datos y eliminar datos. Entonces, yo lo que hice en este caso, verdad, al implementar mi builder es crear un interfaz común. Así yo ya no tengo dependencias en cada uno de los builders o en cada uno de los objetos de la base de datos. Imagínense que yo en una operación hay que escribir a diferentes bases de datos, pero cada una se trabaja de manera diferente, verdad. Aun cuando todas reciben patrones parámetros muy similares. Yo con mi builder, yo me puedo asegurar de crear un interfaz común que va a recibir siempre los mismos métodos, pero lo que me va a devolver siempre va a ser diferente, va a ser adaptado para la base de datos con el que estoy trabajando. Entonces, yo tengo mi interfaz, este es mi SQL builder, verdad, esto nada más es una guía para mi verdadera builder y como podemos ver, todos los que implementen este interfaz, van a utilizar los mismos métodos. Todos van a tener métodos el EdWord y Limit para construir mi query y podemos agregar aquí otros en fin de métodos. ¿Cómo lo utilizo? Resulta que yo necesito crear un query MySQL. Entonces, yo tengo una guía de qué es lo que yo voy a necesitar en todos mis queries, que para eso me va a funcionar mi interfaz y voy a implementar cada uno de los métodos. Y como les comenté, todos van a recibir los mismos parámetros, pero lo que va a devolver el resultado va a ser diferente. ¿Por qué? Porque él me está construyendo un query para MySQL, en este caso. Después vemos la necesidad de que necesitamos también construir exactamente el mismo query, pero para posgres, que si bien tiene algunas diferencias, si lo implementamos dentro de la misma clase que ya teníamos, nuestro código se vuelve spaghetti, porque ahora estamos manejando muchas cosas dentro de la misma clase. Entonces, una vez más, verdad, mi interfazo y yo implemento mis las diferencias que yo vaya a necesitar. Una vez más, estoy recibiendo los mismos parámetros, pero estoy construyendo algo diferente. Entonces, yo en todo mi software, yo puedo asegurarme de que cada vez que yo voy a recibir algo de la interfaz, tipo query builder, verdad, va a recibir esos parámetros y me va a devolver el query haciado específicamente para esa plataforma. A mí el builder me gusta, verdad, para construir objetos muy avanzados y que requieren mucha programación. Imagínense que yo cada vez que necesitas hacer un query, verdad, un query que se repite muchas veces. Yo le escribo y lo escribo, verdad, es un poco tedioso porque después si necesito cambiarlo, el cambiarlo me va a tomar demasiado tiempo. Mientras que si yo creo un interfazo y empiezo a crear este clases, verdad, que comparten esa funcionalidad y comparten esos parámetros, es mucho más sencillo, porque yo estoy separando todo lo que es la construcción de ese objeto en otra clase, algo por aparte. Entonces puedo separar la lógica de negocio de temas meramente técnicos, como en este caso, que es algo meramente técnico, verdad, es algo de la base de datos. Mi lógica negocio vive en otro lugar, lo que define qué parámetros voy a pasarle a eso. El siguiente, patrón, es el método de fábrica. Es un método de creación, son muy similares, ya los vamos a ver. Y este lo que me permite es una interfaz para crear una superclase, verdad. Hay clases que son muy complejas. Por ejemplo, tenemos un tenemos un tenemos las figuras geométricas, verdad. Y todas las figuras geométricas van a compartir ciertos parámetros. Yo puedo crear una y van a recibir ciertos parámetros que son muy similares, verdad, que es lo que me permite a mí la fábrica. Me permite que, basado en esos parámetros, la fábrica va a decidir qué es lo que me ha de volver. Siempre va a ser una figura geométrica, pero los parámetros que van a recibir va a ser lo que a definir qué tipo de figura geométrica yo voy a recibir. Vamos a ver un ejemplo. Voy a colapsar un poco el código. Esto es un poco pequeño, un poco grande, perdón. Lo primero que yo tengo, verdad, es una clase abstracta. Eso para qué? Esto es para encapsular la funcionalidad que van a tener en este caso todos mis posters, verdad. Aquí yo lo que voy a tratar de crear es un poster que es para una red social. Entonces, se conecta también a algo que va a procesar este poster, pero podemos ver aquí esa construcción, verdad. Este es el que va a construir eso. Él va a recibir un contenido y dependiendo de la red social que yo le paso, él va a crear diferentes, va a dar un resultado diferente. Este network puede ser algo diferente, basado en el source network que se le ha pasado y después el post va a tomar las decisiones de lo que va a hacer con ese network. Pero aquí yo estoy separando lo siguiente, estoy separando el acto de enviar algo a esta red social de el crearlo, de la creación de eso. ¿Por qué? Porque muchas veces, y a mí me ha pasado, lo he hecho muchas veces que tenía todo esto en una sola funcionalidad, verdad. Tenía el post, pero la vez ahí tomaba todos los datos y esto de nuevo lo que hace es crear una serie de código spaghetti. Mientras que si yo creó un factor, el factor me permitirá a mí pasar el contenido y el encargarse de la creación del resultado final. Esto, como les comenté, es muy parecido al builder también. Entonces yo tengo acá, podemos ver las diferencias entre cada uno. Ya este utiliza un conector diferente, podemos ver acá cómo el padre utiliza el conector, pero mi conector yo lo estoy decidiendo en otro lugar. Y aquí tenemos algunos otros ejemplos para LinkedIn y también para Facebook. De qué una vez más yo soy separando qué es lo que él va a hacer y cómo va a funcionar eso. Esa es un poco más compleja, verdad, que lo que es el builder ya da más partes. Yo lo que consejo usualmente es empezar con un builder y después si es necesario separar aún más, ya ver la opción de pasar a un factor, porque este es un patrón más complejo. Estos son los que vamos a ver de los metodos de los patrones creacionales, metodos de fábrica y metodos de builder. Son los que en mi cabrera son los que más he utilizado y ahora vamos a parazar a los estructurales. Y el primero que vamos a ver es el decorador. El decorador a mí lo que me permite es agregar funcionalidad extra a un objeto sin modificar la clase de este objeto. Y eso por qué? Porque a veces podemos ser una súper clase y le voy a llamar así porque esta clase posiblemente se encarga de demasiadas cosas en muchos contextos, verdad. Imagínense que yo tenga un publisher, social network de status, verdad. Y este publisher tiene un publish to Facebook, publish to LinkedIn, publish, tuvo un montón de cosas, pero cada uno de ellos necesita recibir una y otra vez sus parámetros o necesita recibir una y otra vez el mensaje que se va a publicar. Muchas veces lo que optamos nosotros es por hacer herencias. Creamos un publisher, verdad. Y después creamos herencias basado en cada uno de los publishers. Lo que sucede con esto es que si yo necesito utilizar ese publisher, muchas veces tengo que crear demasiadas instancias de ese objeto. Cuando yo lo que puedo hacer es crear un objeto base y después utilizar estos decoradores que lo que van a hacer es agregarle funcionalidad a mi objeto base. Vamos a verlo en código para que sea más fácil de entenderlo. Yo aquí, aquí estoy trabajando en algo basado en un formulario de HTML, verdad. Tengo clases para los inputs y esos inputs necesitan tener ciertas opciones, pero yo quiero también que esas opciones sean reutilizables. Entonces, yo lo que hice acá es crear una interfaz, usualmente siempre voy a empezar con una interfaz, verdad. Que lo que me dice es que el bar recibir un texto y tiene una función que se llama format text. Y cada uno de las clases que implemente esa interfaz, necesito implementar ese método, verdad. Y ahora sí, yo creo un componente base que en este caso sería un text input, que es lo más sencillo. Cuando creamos un input por decirlo así en HTML, lo más común es que tengamos un text input. Eso va a ser la funcionalidad por default y es muy sencillo. Nada más me vuelve un texto. Pero ¿qué sucede? Que las requerimientos empiezan a hacer más complejos, verdad. Cada vez de repente se pide de que el texto, verdad, a veces se devuelva ya en un wrapper, verdad, en un elemento HTML o tal vez tenemos que limpiar el contenido de ese texto. Pero estas opciones pueden ser intercambiables. Entonces, tal vez yo lo que haría primero es extender esta clase, verdad, la extiendo y nada más le pongo otra, le cambio la funcionalidad. ¿Qué es lo que sucede con esto? Que esa inerencia me va a crear una serie de objetos que van a estar demasiado ligados a ese objeto padre y como le repito, si yo necesito mezclar esas funcionalidades, ahí las cosas se ponen muy complejas. Porque tendría que seguir demasiadas clases para inclusive mezclar esas funcionalidades. Pero con un decorador, decorador, ese trabajo se convierte muchísimo más sencillo. ¿Por qué? Porque mi decorador lo que hay a recibir es el elemento principal, el elemento base. Como podemos ver acá, tengo este text format, ya este es un decorador, verdad, que yo sé creando. Podemos ver de que todos comparten la misma interfaz y él va a recibir la distancia anterior o la distancia que yo quiero decorar. Ya él lo recibe este text y aquí yo cambio la funcionalidad. Y este format text, en este caso, puede cambiar el formato de este texto. Después agrega un nuevo requerimiento, verdad, y yo una vez más, aquí inclusive strict tags, verdad, es otro requerimiento. ¿Qué es la maravilla de esto? Y aquí yo tengo otros decoradores. La maravilla de esto es que yo con un solo texto lo puedo pasar sobre mis diferentes decoradores, verdad, como en este caso, defino el text input y paso este text input sobre mis diferentes decoradores y él me da a volver una combinación de todas estas funcionalidades. Eso teniendo todas las funcionalidades en diferentes clases, sin necesidad de afectar mi objeto principal. Para mí el decorador es uno de los patrones más maravillosos porque me permite separar muy bien mi código y además es reutilizarlo, verdad. Yo puedo tener un decorador que se utiliza en muchos tipos de objetos y eso es súper poderoso porque no necesito tener este decorador, verdad, totalmente ligado solo a esta clase o a este objeto, sino que puedo utilizarlo en muchos lugares y es mucho más fácil de testear también. El siguiente patrón que vamos a ver es la fachada o el façade. Ese es un patrón que me permite crear una interfaz fácil de utilizar para mi código. ¿Qué quiere decir esto? Yo estoy utilizando WordPress y WordPress tiene sus funciones, tiene su propio IPI, verdad, y yo estoy creando mi desarrollo, estoy creando mi aplicación, pasado mis reglas de negocio. Para la mejor manera que yo pueda hacer para separar estas dos cosas es creando todo el código de la lógica de mi negocio y crear fachadas que permitan que mi código trabaje con WordPress. Vamos a ver un ejemplo. El façade es muy sencillo, verdad. Yo aquí tengo, bueno, un YouTube downloader, ¿verdad? YouTube a mí me va a dar este diferente tipo de formatos y cada uno de esos formatos se trabajan y se descargan de manera diferente. Esto complica las cosas porque imagínese que yo en editos era una descarga en muchos lugares, ¿verdad? Escribir una y otra vez ese código o separar inclusive o escribir varias veces dependiendo del caso. ¿Qué es lo que hago yo? Yo creo algo muy sencillo, creo una clase que se llama YouTube downloader, al cual yo le voy a pasar ciertos parámetros, pero esta clase es la que se va a encargar de toda la complejidad de descargar ese de descargar ese video y manejar el formato de ese video. Entonces yo lo único que voy a necesitar utilizar en mi código es esto de aquí. Y ya mi YouTube downloader se va a encargar de trabajar con los diferentes APIs, con YouTube, con los formatos, transformarlo, ¿verdad? Incluso de la manera en que se va a exportar ese video. Vean lo que es sencillo, cómo se va a ver este en mi código, al final. Claro, yo en otros lugares escribí todo el código, pero para mí va a ser mucho más fácil de utilizarlo en otros lugares, inclusive con otro desarrollador venga y puedo utilizar esta clase. ¿Por qué él dice? Claro, hago esto, paso el like de el video y lo descargo nada más. El facade sirve para esconder complejidad, para hacerlo de una manera más fácil, más entendible y más fácil. Yo escribo mi código, escribo mi API, escribo mi lenguaje, ¿verdad? en mi código y eso tiene más sentido desde la perspectiva de negocio, que ponerse a explicar cosas más técnicas que no son relevantes para la lógica de negocio. Ahora vamos a ver los patrones de comportamiento. La cadena de responsabilidad es un patrón que lo va a permitir encadenar una serie de funcionalidades, de funciones que se tienen que ejecutar en un request y definir si es el request, si sigue ejecutando o si no, tiene que pasar o si no, o si se tiene que cancelarlo. Vamos a ver esto en código, le doy acá collapse, ¿verdad? Yo lo que hago es crear un middleware, ¿verdad? Y me digo es muy sencillo, él define el cual va a ser la siguiente acción, él necesita saber eso, ¿verdad? ¿Qué lo va a ejecutar y qué es lo que va a ejecutar? ¿Verdad? Básicamente el cheque es, es el corte de mi funcionalidad, es el corte de ese eslabón en la cadena. Y después los que implementen ese middleware, pues este change of responsibility, como podemos ver, supongamos que ese es un caso de un usuario que se está logueando. Cuando los usuarios se loguean tienen que suceder muchas cosas, ¿verdad? En este caso, primero hay que verificar que el usuario exista, ¿verdad? Entonces yo aquí hago una serie de chequeos que el usuario existe o no existe y si todo esto sucede, yo paso a siguiente cheque. Después chequeo el rol, después chequeo también que el usuario tenga permiso de poder salir al en este momento, ¿verdad? Pero ¿qué pasa aquí? Como ustedes pueden ver, cada uno de estos chequeos yo lo tengo en una clase diferente. Puedo testearlo y puedo agregar cuántas clases yo quiera, sin necesidad de tener un objeto que se llame supongamos signing, que tiene un montón de funciones, porque eso pueden ser chequeados de los que se pueden hacer o pueden cambiar dependiendo del tipo de usuario. ¿Y qué pasa? Que al final están sencillo como definir los chequeos que yo voy a utilizar y en el orden en que se van a ejecutar. Yo aquí estoy definiendo este middleware y le digo que este middleware va a trabajar también con estos otros middlewares, ya van a trabajar en conjunto. Si uno se rechaza, toda la ejecución va a finalizar y aquí yo nada más ejecutó algo que se llama login. ¿Pero qué va a ser mi login? Va a llamar a cada una, a cada uno de esos middlewares. Uno por uno, hasta que todo devuelva true o que todo está bien y ya la ejecución sucedió correctamente. Esto y eso también me permite a mí agregar cuántos middlewares yo deseo. Yo puedo seguir creando más o puedo eliminar uno de una manera muy sencilla, nada más burbando una línea aquí y yo sé que eso va a seguir funcionando. El otro es el comando. Este me parece muy útil en el escenario de WordPress porque muchas veces sucede en WordPress le vemos acciones o le vemos filtros y cuando esas acciones o filtros se ejecutan, nosotros podemos decidir qué sucede pero qué sucede, que muchas veces ponemos mucha lógica de negocio en estas acciones y ahora tenemos un monolito en donde el desarrollo, la lógica de mi negocio y WordPress conviven mutuamente y dependen mucho uno del otro. A mí el comando lo que me va a permitir es separar esto. Es decir, cuando se ejecuta esta acción, ok, yo voy a ejecutar el código, sí, pero mi comando es el que se va a encargar de toda la parte de negocio. Va a ser totalmente separado de WordPress, ¿Verdad? ¿Por qué? Porque mi aplicación no le importa si está en WordPress, si está en Laravel o si está en algún tipo de framework. Mi lógica de negocio no debe ser dependiente de la parte ísalo de la parte técnica, que en este caso sería WordPress. Entonces vamos a ver un ejemplo del comando. Lo ideal es que todos los comandos tengan algo en común, ¿Verdad? Entonces de nuevo yo voy a definir una interfaz. Usualmente lo que vamos a requerir es un execute, ¿Verdad? Todos mis comandos tienen que poder ejecutarse, o un run. Y aquí yo tengo una serie de comandos. Estos son ese, en un caso en el scraping web, ¿Verdad? ¿Qué sucede? Que cada uno de esos comandos tiene mucho código. Si yo decidiera tomar las decisiones en un action, todo esto tendría que vivir en una sola función. Pero a mí el comando lo que me permite es tomar decisiones basadas y separar el comando en sí. Como en este caso. Yo estoy leyendo un queue, ¿Verdad? Y si el queue estaba así, entonces yo voy a ejecutar este comando. Pero yo también puedo decidir ejecutar otros comandos en otros en diferentes casos. Cuando agregar comandos también, eso es importante que el queue me lo permita. Entonces, dependiendo de mis variables, yo puedo decidir qué tipo de comandos o qué comando es el que voy a correr. Y sí, mi código va a vivir totalmente aparte de toda esa parte técnica. Mi parte de negocio va a ser separada de la parte técnica, que este es para mí uno de los mayores valores que traen los patrones de diseño, que me permiten entender de que mi código, de que la lógica de mi negocio tiene que ir apartada, ¿Verdad? De la parte técnica. Conclusiones, para mí la mayor es, esto me viene a solucionar los problemas, ¿Verdad? Como pudimos ver en algunos ejemplos, son problemas muy comunes que tenemos una y otra vez, crear objetos complejos, ¿Verdad? Definir una línea de comando de cómo se tienen que variar las cosas o cómo se tienen que ejecutar. ¿De qué manera van a vivir mis objetos también? ¿Cómo van a trabajar entre ellos? ¿Cómo vamos a repartir el trabajo en esos objetos? Y esto de una manera que mi código sea limpio y se puede extender muy fácilmente. Y también tener composición, porque en programación o en todos ejemplos tendemos a darle mucha importancia a la herencia, cuando en realidad lo que veríamos de buscar es composiciones. Y mi código, utilizando patrones de diseño, me permite lograr ese resultado de una manera más fácil y que mi proyecto viva a muy, muy largo plazo también. Estamos hablando de décadas. ¿Algunos recursos? Bueno, les recomiendo mucho libro del Gang of War, Design Patterns. Ahí están cada uno de ellos, muy bien definidos. Hay otros recursos para mí muy, muy buenos y mucho más fáciles de ver que libro. It's Arrefactoring Guru, es un sitio, es de pago, pero tiene muchos recursos gratuitos también. Y eso es totalmente gratis, Design Patterns, es aquí está cada uno de los patrones totalmente explicados con charts en UML también. Y hay ejemplos de código y hay ejemplos de la vía real también muy bien explicados. Se los recomiendo mucho. Este de acá el primero, va a estar en los slides y eso sería de mi parte. Muchísimas gracias.