Transcripciones
1. Introducción: Oye, ahí. Bienvenido al curso de Fundamentos de
Arquitectura limpia Mi nombre es Kayo Susa, y seré tu
instructor para este módulo Ahora, repasemos el material que se cubrirá
en este curso. En primer lugar, voy a hablar
de los principios sólidos, que contiene el principio de
responsabilidad única,
el principio abierto y cerrado, el principio de sustitución de Liskov, el
principio de
segregación de
la interfaz, y el principio de inversión de dependencia Luego revisaremos
algunos conceptos relacionados con la arquitectura de software. Revisaremos el modelo C four, que se divide en cuatro
niveles de abstracción, el contexto del sistema,
el contenedor, el componente y
el diagrama de código. También revisaremos la
idea entre capas y
las responsabilidades
entre estas capas a la
hora de diseñar la arquitectura de
software. Luego cubriremos los conceptos de
arquitectura limpia, que es básicamente un enfoque centrado en el
dominio. Revisaremos las
responsabilidades de cada una de estas capas. Rápidamente configuraremos nuestro entorno para que las
cosas funcionen. Entonces voy a presentar un problema
sencillo a resolver. Lo resolveremos de manera rápida, luego refaccionaremos e
implementaremos una arquitectura limpia Cubriremos capas que
representen una arquitectura limpia. Estas capas las implementarás
al final del curso, que es básicamente
la presentación, infraestructura,
aplicación y core. Este es el diagrama de
arquitectura de la solución final que
implementarás al
final de este curso. Te invito a unirte a mí en esta oportunidad de aprendizaje
para entender, implementar y aplicar conceptos de
arquitectura limpia.
2. Principio de responsabilidad única: Entonces hablemos de
algunos principios de diseño. Entonces veamos sólido. Tan sólido es un acrónimo, lo que significa que cada una de estas letras
representa un significado. Entonces tenemos S para el principio de
responsabilidad única. Tenemos O para el principio abierto
y cerrado, L,
para el principio de lista de
sustitución,
I para el principio de segregación NFA Por último, tenemos D para principio de inversión de
dependencia. Por lo que el principio de
responsabilidad única establece que un módulo debe tener una y sólo una
razón para cambiar. Diferentes usuarios tienen
diferentes objetivos a la
hora de
usar un software. Los usuarios distantes pueden implicar diferentes razones para que
un módulo cambie Veamos un ejemplo. Aquí tenemos una plataforma de
comercio electrónico. También tenemos una clase llamada CRT. La clase de tarjeta es
responsable de calcular los artículos en una tarjeta y actuar
sobre la orden de compra. Molly es miembro de la plataforma
de comercio electrónico. Aquí tenemos a Josh, quien es miembro premium de la plataforma de
comercio electrónico. En este ejemplo, los miembros premium son parte de la nueva
funcionalidad del software. Los miembros Premium pueden tener
descuentos que varían del 10% al 50%
dependiendo del artículo comprado. Ahora tenemos a Molly
y Josh que pueden comprar artículos pero con diferentes cálculos
o algoritmos ¿Dónde debemos poner el descuento
en los artículos calculados? Recuerde, el principio establece un módulo debe tener una y
sólo una razón para cambiar. Para separar la
responsabilidad y aplicar el principio de
responsabilidad única, creamos un par de clases. Tenemos la fachada del automóvil, que calcula el artículo, aplica los descuentos y órdenes de
compra en
forma de orquestaciones Entonces tenemos la calculadora de
descuentos que aplica el descuento. Tenemos la calculadora total responsable de
calcular los artículos, y luego tenemos el envío responsable de
efectuar su compra
3. Principio de apertura y cierre: Entonces, continuemos con
los principios de diseño. Ahora veamos el principio abierto
y cerrado. Por lo que el
principio abierto y cerrado establece que un más blando debe ser abierto para extensión pero
cerrado para modificación. En otras palabras, un artefacto
más suave. El comportamiento debe
permitir que se extienda sin modificar
el artefacto real Como ejemplo,
digamos que tienes o digamos que estás usando una
aplicación web con un
par de páginas. Esta página está envuelta alrededor del modelo en el patrón
del controlador de vista. Entonces tienes una vista que
solicita datos a un responsable del tratamiento. En este ejemplo, el controlador tiene múltiples responsabilidades. Se conecta a la base de datos, recupera los datos y también implementa reglas de
negocio Ahora, veamos esta imagen. Tiene dos controladores que se conectan a la misma base de datos. Recuperar son los mismos datos, pero tienen reglas diferentes. Recuerde, el principio de abrir y
cerrar establece que un artefacto más suave
debe estar abierto para extensión pero cerrado
para su modificación Cuando los componentes no están bien definidos, puede ocurrir redundancia Aquí, no estás extendiendo comportamiento
similar en
diferentes controladores. Bueno, para resolver este problema, como puedes ver, se incluyó la
capa de negocio. Encargado de
aplicar las reglas. También hay una capa de acceso a datos responsable de conectar y recuperar datos
de la base de En este caso, se dividen
responsabilidades. Cuando el software se
divide en capas, puede definir
responsabilidades únicas. Eso permite que las clases
estén abiertas para extensión y cerradas para su modificación con un impacto mínimo en otras
partes de la aplicación.
4. Principio de substitución de Liskov: Oigan, chicos, así que
continuemos y
hablemos del principio de
sustitución de Liskov El
principio de sustitución de Liskov establece que los objetos de una superclase deben
ser reemplazables por objetos de sus subclases sin Aquí tenemos un ejemplo. Si un objeto parece un pato, charlatanes como un pato,
pero necesita baterías, es posible que tengas la abstracción
equivocada En este caso, tienes
la extracción equivocada. Comprender
la herencia y aplicar la herencia pueden ser
dos mundos separados. Veamos este ejemplo, que es una especie de ejemplo
clásico. Un cuadrado tiene igual
anchura y altura. Un rectángulo no tiene
igual anchura y altura. Entonces un cuadrado no puede ser un
subtipo de un rectángulo. Cuadrados y rectángulos tienen ambos son de tipo cuadrilátero Ambos tienen cuatro ángulos
interiores iguales a 90 grados y lados opuestos
paralelos entre sí. Los rectángulos y cuadrados son
subtipos de cuadriláteros.
5. Principio de segregación de la interfaz: Oigan, chicos,
hablemos del principio de
segregación de la interfaz Por lo que este principio
establece que
se debe depender sólo de lo depender sólo de lo necesario o
de parte de un alcance determinado. Una interfaz debe tener responsabilidades
definidas. Por ejemplo, una
interfaz humana no debe implementar métodos
con respecto al comportamiento animal. Entonces imaginemos que estás desarrollando un sistema de educación
secundaria. Este sistema necesita tener información sobre
el alumno, la clase a
la que asiste y información de
sus padres o
tutores Aquí tenemos un ejemplo de
una interfaz de repositorio. Un repositorio en este ejemplo se encarga de guardar
los datos en la base de datos. Como puedes ver, el usuario
interactúa con la aplicación, y eventualmente llamará repositorio
del estudiante
para guardar el estudiante, la clase y
la información de los
padres Considerando que el alumno, la clase y el
padre de familia se almacenan en diferentes tablas en
una base de datos común, este ejemplo viola el principio de
segregación de la interfaz, como afirma el principal, depende únicamente de lo necesario o parte
de un alcance determinado Para resolver esto,
implementamos o tenemos diferentes repositorios para
diferentes responsabilidades Como puedes ver en una imagen, tenemos un
repositorio de estudiantes que contiene los métodos
para guardar al alumno, el repositorio de clases que
contiene los métodos para guardar la clase del alumno y
el repositorio padre que contiene el método
para guardar el padre.
6. Arquitectura de software: Entonces hablemos de arquitectura
de software. La arquitectura más suave
abstrae un sistema y los elementos consistieron en un más suave que define
su estructura Aquí en la imagen, tenemos la representación
del modelo C four que
visualiza una arquitectura más suave, en este caso, a nivel
de contexto Entonces el modelo C four es un conjunto de diagramas
jerárquicos que
se compone de cuatro niveles El contexto del sistema,
los contenedores, los componentes y el código. Dentro de este diagrama que
representa el nivel de contexto, podemos evaluar un alto
nivel de abstracciones de cómo interactúa el usuario
con el sistema de software Aquí tenemos un
cliente bancario que interactúa con
un externo con un sistema interno
llamado sistema bancario por Internet El sistema interno interactúa
con sistemas externos, como el sistema de correo electrónico
y el sistema bancario mainframe En el diagrama, podemos ver una breve descripción
de estos sistemas. Al analizar este diagrama, también
podemos ver algunas
abstracciones de los elementos, y podemos entender
una
estructura de alto nivel de la arquitectura El punto focal de las relaciones es definir cómo los elementos
del software
interactúan entre sí evitando demasiados detalles de
implementación. Entonces ahora, con el diagrama
contenedor, que es el segundo nivel
del modelo C four, podemos ver cómo algunas de estas capas interactúan entre sí y sus
relaciones. Aquí vemos al mismo
usuario del software, pero con más detalles. Ahora podemos evaluar el tipo de aplicación con la que el
usuario puede interactuar. En este caso, se trata de una aplicación de una sola página
en la aplicación móvil. También podemos ver que
existe una API que lee y escribe
datos en la base de datos. En algunos casos, podemos ver los detalles de
la comunicación, como cómo interactúa la
aplicación móvil con la API a través de llamadas JSON ATTP Ahora, veamos el tercer
nivel del modelo C four, que es el nivel de componente. Dentro de este diagrama,
se pueden identificar los principales
bloques de construcción estructurales en sus interacciones. El diagrama de componentes
muestra cómo un contenedor se compone de una
serie de componentes. Y cuáles son las responsabilidades
de estos componentes, tecnología y los detalles de
implementación. Aquí, podemos ver que la aplicación
single bage y la aplicación móvil, y podemos ver cómo
interactúan con los controladores hasta el componente que baja a la base de datos y los sistemas
externos. Por último, tenemos
el diagrama de código, que es el último nivel
del modelo C four. Este diagrama muestra clases
UML, relación de
entidad o
de estructura similar La representación
baja a la realidad de cómo se está
implementando el código. Este diagrama se considera o
puede considerarse opcional, ya que muchos IDE pueden generar una estructura
similar
automáticamente
basada en el software desarrollado. Los arquitectos de software
deben facilitar el desarrollo de nuevas características. Un software que es difícil de
mantener puede ser difícil de
enviar y evolucionar. Entonces el
arquitecto de software debe tener en cuenta términos como
¿necesito probar? ¿Qué tan reutilizable es mi código? ¿Necesito integrar esto con algún otro sistema existente?
¿Qué pasa con la seguridad? ¿Cómo puedo
implementar fácilmente el código M y otros atributos de calidad mientras desarrollo
la arquitectura La arquitectura de software ideal
cumple con el propósito
del negocio para facilitar
el trabajo de desarrollo real. Una cosa a tener en cuenta es
mantener abiertas tus opciones. Entonces, el comportamiento y
la estructura de un software es quizás lo que aporta más valor a
los sistemas de
software. Muchas
organizaciones de software no tienen un alcance claro de lo que
están tratando de lograr. Por lo tanto, mantener abiertas
sus opciones es clave para
tomar decisiones importantes en el futuro. Tener cierta flexibilidad por adelantado, como no tener que
preocuparse por la base de datos, los marcos, tal vez las bibliotecas de bus de servicio pueden dar a los arquitectos
opciones para experimentar, probar y esperar a que
el proyecto madure para tomar la
decisión correcta en el momento adecuado Ahora, veamos las capas. A medida que aumenta la complejidad de la
aplicación, una forma de
administrarla es
dividirlas de acuerdo a
responsabilidades o preocupaciones. Cuando el código se organiza en
capas con responsabilidades, funcionalidad de
bajo nivel
se puede reutilizar en toda
la aplicación El beneficio de la reutilización es
que ya que el código necesita ser escrito y permite estándares de
implementación únicos, siguiendo el principio DRI, que es no repita usted mismo En este ejemplo, tenemos
un diagrama de tres capas. La interfaz de usuario representa
la interfaz de usuario. La capa de negocios es donde se implementan
las reglas, y la
capa de acceso a datos es donde se realiza
la conexión con la base de datos y cómo
define cómo interactúa la
base Comprender la arquitectura de
software subyacente y la responsabilidad y los límites de cada capa
es crucial para que los ingenieros de
software
mantengan y desarrollen los sistemas.
7. Arquitecto de software limpio: Oigan, chicos, así que por fin hablemos de arquitectura
limpia. Entonces, para empezar, veamos algunas de las variaciones
de la arquitectura limpia. Primero, vamos a
mirar la arquitectura onion,
luego la arquitectura hexagonal, luego los puertos y adaptadores Entonces cuando miramos la arquitectura
cebolla, podemos ver que en más centro de esta arquitectura,
tenemos nuestras entidades. Entonces tenemos nuestros casos de uso, lo que representa las reglas de negocio. Después de eso, podemos ver
controladores, puertas de enlace
y presentadores, que
representan adaptadores de interfaz Por último, podemos ver nuestros
frameworks y drivers. Todo esto tiene
cierto tipo de propósito, y lo veremos además. Cuando miramos la arquitectura
hexagonal en el centro de
esta arquitectura, podemos ver nuestras reglas de negocio. Por lo que es muy similar a la
primera arquitectura de cebolla. Después de eso, puedes ver que
hay repositorios y servicios que implementa o utiliza hace
uso de los modelos de negocio, y luego tenemos nuestra interfaz de
infraestructura con, ya
sabes, nuestras fuentes de datos, nuestros adaptadores de interfaz
y fuentes de datos También puedes ver que hay una
flecha apuntando al centro, lo que significa que el centro de esta aplicación no puede
depender de las capas externas, pero las capas externas pueden
depender de las capas más centrales. Entonces ahora veamos la arquitectura de puertos
y adaptadores. Aquí en el centro,
podemos ver que tenemos una capa de dominio con un modelo de dominio y
nuestros servicios de dominio. Todos estos
representan componentes, y están en el dominio. Entonces tenemos nuestra capa
de aplicación. Bueno, mirando
al centro de esto, podemos ver que esto
probablemente esté usando algún
tipo de patrón DDD Mirando la capa de
aplicación, podemos ver comandos,
consultas, servicios, que también podemos
identificar el patrón CCR CQRS Después, podemos ver
la interfaz de usuario la izquierda con AttprstrQuest, interfaz
gráfica de usuario,
y luego podemos ver nuestra infraestructura a la
derecha con nuestros adaptadores de correo electrónico, adaptadores
SMS, adaptadores de bus de eventos Entonces cuando miramos
esta arquitectura, también
es muy similar a las otras arquitecturas
donde tenemos nuestro dominio en el centro y nuestra presentación
e infraestructura en las capas más externas Entonces, ¿cuándo se debe usar una arquitectura
limpia? Cuando pensamos en diseños
centrados en dominios, ¿verdad? Entonces, diseños centrados en el dominio donde tienes reglas de
negocio complejas y quieres
proteger esas reglas. Entonces esto va muy bien
con el patrón DDD. Es importante afirmar
que DDD no
es una arquitectura limpia
y viceversa. Se puede implementar una
sin la otra. Con abstracciones bien definidas, es mucho más sencillo
implementar pruebas unitarias Entonces, si tienes un alto
nivel de pruebas, si necesitas una buena
parte de la cobertura del código, arquitectura
limpia podría ser una buena arquitectura porque separa las abstracciones y simplifica las pruebas unitarias Finalmente, ayuda a hacer cumplir las políticas y separar capas, preocupaciones y responsabilidades. Con responsabilidades definidas
en cada capa, se puede tener separación de preocupaciones e independencia
de infraestructura. Entonces, ¿cuándo no debes
usar Arquitectura limpia? Bueno, si estás escribiendo una aplicación realmente pequeña
con un par de puntos finales, arquitectura
limpia
puede ser una exageración Porque la arquitectura limpia es, ya
sabes, una
arquitectura en capas. Tienes un par de
capas, tienes reglas. Es necesario entender
algunos conceptos. Por lo que las solicitudes muy pequeñas
podrían no ser un buen candidato. Si tienes
tiempo y conocimiento limitados, así que si estás, no sé, aprendiendo objeto o en el diseño,
aprendiendo los marcos, aprendiendo la inyección de dependencia, pruebas unitarias de
aprendizaje, etcétera,
recomendaría bajar primero
los fundamentos Cuando la inyección de dependencia y las pruebas
unitarias no son aplicables. Entonces tal vez podrías estar trabajando en una aplicación heredada donde no
hay ninguna
inyección de dependencia implementada. No hay
pruebas unitarias en tu código. Y para estas aplicaciones donde no es muy aplicable, arquitectura
limpia podría
no ser una buena solución. Entonces veamos qué
es la arquitectura limpia. Entonces, básicamente, es un enfoque centrado en el dominio
para organizar las dependencias. Te ayuda a seguir algunos
de los principios sólidos, y lo veremos una vez que
empecemos a implementar. Tiene
separaciones de preocupaciones bien definidas. Entonces cada capa tiene su
propia responsabilidad, y es un
modelo centrado en el negocio donde el negocio está en el medio o centro
de la aplicación. Debería tener dependencias mínimas
o nulas. Entonces, en cierto sentido, está protegido
de las capas externas, que es la
infraestructura en la interfaz de usuario. Lo que eso significa es que la infraestructura no puede
influir en tus reglas de negocio. Se minimizan las dependencias de
la infraestructura. Entonces la infra, que
representa base de datos, correos electrónicos ,
colas, almacenamiento, etcétera, básicamente se
minimizan Cambiar la
infraestructura
no debería tener un impacto importante
en la aplicación. Al ser un poco redundante, pero mirando
las características, la arquitectura
limpia ayuda a implementar
las
independencias del marco Ayuda a uno a tener un nivel
alto o ser capaz implementar un alto nivel de comprobabilidad para aplicaciones de
software Es
independiente de la interfaz de usuario. Es independiente de la base de datos
y aísla tus reglas en el centro
de la aplicación Entonces veamos esta imagen
aquí para una arquitectura limpia. Entonces en el centro, podemos ver las entidades, que contiene básicamente las
reglas de negocio cruciales del sistema. También tenemos la capa de
aplicación que contiene las reglas de negocio
específicas de la aplicación. También puede orquestar
el flujo de datos de las entidades para cumplir con el objetivo de la
aplicación Después de eso, tenemos
nuestros controladores, gateways y presentadores, que convierten los datos de las capas externas
a las capas internas,
como las capas de casos de uso y
entidades Por último, tenemos nuestro
servicio de interfaz de usuario
web móvil Above storage, que es la capa más externa Y estas capas son básicamente, tu interfaz de usuario, tu base y los marcos alrededor que
rodean tu aplicación. Ya que los frameworks
y drivers están en la capa más externa
de la arquitectura, convirtiéndolos en un detalle que podría
ser reemplazado si fuera necesario. Aquí tenemos otra
visión del mismo diseño. Y como puedes ver aquí,
como máximo centro,
tenemos las reglas de
negocio de la empresa,
luego tenemos las reglas de negocio de la
aplicación. Entonces tenemos los
adaptadores y la interfaz, y finalmente, los
Fredericks y los drivers Entonces, ¿cuáles son las reglas de
dependencia? Las dependencias
del código fuente deben apuntar únicamente a
los círculos internos Los elementos del interior
del círculo interno no pueden acceder a los elementos externos
desde los círculos exteriores. Por ejemplo, la capa de entidades no puede hacer referencia a la capa de
aplicación. Entonces, si volvemos a la diapositiva, podemos ver que las entidades
están en el centro más, y no pueden acceder a la capa de aplicación
externa. Sin embargo, la capa de aplicación puede acceder a la capa de entidades. Esto, en cierto sentido, protege a
sus entidades o protege reglas
de negocio de
su empresa de dependencias externas,
marcos, etcétera Entonces, ¿qué pertenece a la interfaz de usuario? Básicamente API endpoints,
controladores, vistas, modelos de vista. Por lo general en este
nivel, también tienes tu raíz principal o de composición donde implementas tu expulsión de
dependencia Lo que pertenece a la
infraestructura. Para que pueda tener repositorios, contactos de acceso a
datos, correo electrónico, almacenamiento e
implementación de mensajería, y lo que pertenece al
núcleo de la aplicación Entonces esto puedes tener
tus interfaces,
tus entidades, tus validadores de
servicio de dominio, o partes de la aplicación que definen el dominio o las
reglas de la aplicación Y aquí es donde
queremos hacer o
queremos tener protegidos.
8. Primeros pasos con Visual Studio: Hola, ahí. Entonces, sigamos
adelante y repasemos algunas de las herramientas que
se utilizarán en este curso. Así que tenemos Viso Studio 2022. Esta versión tiene un
par de adiciones. Tenemos la edición comunitaria, la edición profesional
y la empresa. La comunidad es
de descarga gratuita. Está disponible para Windows, y debería ser suficiente para hacer fácilmente cualquier cosa
que necesitemos hacer. Si estás en la máquina Linux, podrías usar
Visual Studio Code. Si estás en una Mac, ahí está
Visual Studio para Mac. Para acceder a
estas descargas, puedes seguir adelante y visitar
visualstudio.miicrosoft.com Además, otra
cosa importante es el control de versiones. Por lo que el control de fuentes
es la práctica de rastrear y administrar
los cambios en el código de software. Y recomiendo encarecidamente usar algún tipo de
control de versiones como Git, y tengo el enlace
disponible aquí. Y también hay otros tipos
o plataformas para el versionado.
9. Configuración de la solución: Hola, ahí. Ahora, una vez que descargues Visual Studio
2022 o cualquier ID, te sientes más cómodo,
vamos a seguir adelante y
crear una nueva solución. Entonces una solución es
algo que sostiene proyectos dentro de un proyecto.NET. Puedo llevar a cabo diversos
tipos de proyectos, y lo veremos a lo
largo del curso. Así que una vez que abras
Visual Studio 2022, puedes dar click en
Continuar sin Código. A continuación, puede hacer
clic en Archivo Nuevo Proyecto. Aquí en la parte superior,
hay una barra de búsqueda si buscas en blanco. Hay una solución en blanco. Sigamos adelante y
haga clic en
Solución en blanco y haga clic en siguiente. Elija la ubicación en la que
desee almacenar su solución, y luego podrá
nombrar su solución. En mi caso, voy a
llamarlo Clean Arc Solution. Haga clic en Crear. Y ahora
puedes ver una solución vacía de arco
limpio.
10. Capa de presentación: Entonces ahora que tenemos
nuestra solución vacía,
sigamos adelante y creemos
un proyecto net Web API. Si da la derecha, haga clic en
la solución, haga clic en Agregar Nuevo Proyecto. Si buscas API
aquí en la barra de búsqueda, deberías ver la API web principal de
asp.net Voy a elegir el
de C Sharp. Haga clic en Siguiente. La ubicación predeterminada es donde se encuentra
mi solución, así que solo la voy a
dejar ahí. Y para el nombre del proyecto, voy a nombrar esta API web. Voy a dar click en siguiente. Voy a dejar todos
los ajustes predeterminados. El marco realmente
no importa. Voy a mantener la
última versión que es la última
versión actual, que es 70. Como puedes ver aquí,
hay un par de versiones. Voy a dejar lo último
y configurarlo para HTPS, usar controladores y
habilitar el soporte de API abierta Entonces esta es importante porque podemos ver a
Swagger a través de esto, lo que
nos será útil en un futuro cercano Entonces voy a
seguir adelante y hacer clic en Crear con ajustes predeterminados. Y ahora debería
ver un proyecto
API web predeterminado dentro de mi solución.
11. Ejecución de la API: Entonces ahora que tenemos
nuestra solución configurada, tenemos nuestro proyecto de API web. Se puede ver que hay ajustes
predeterminados
para este proyecto. Entonces, si haces clic en el archivo de
programa punto cs, puedes ver que
swagger está habilitado Aquí hay un par de
middlewares preconfigurados. Y si vas adelante y haces clic
en esta pestaña de reproducción o ejecución, esta debería ejecutar un proyecto de API
web con estos ajustes predeterminados. Entonces aquí, como pueden ver, se habilita la
swagger. Hay un controlador de
pronóstico del tiempo predeterminado. Si hago clic aquí,
puedo probarlo, y debería
poder ejecutar esto, y me devolvería algunos pronósticos
meteorológicos aleatorios.
12. Creación de una clase de extensión: Oigan, chicos. Bienvenida de nuevo. Ahora que tenemos nuestra
web BPI funcionando,
sigamos adelante y veamos
el archivo del programa dot cs Entonces en este archivo, podemos
ver un par de servicios siendo inyectados como los Ad Controllers,
los endpoints Explorer, y
el Swagger Gen.
Así que el SpaggerGn generará Swagger para nosotros. Así que el SpaggerGn generará Swagger Y lo que queremos hacer ahora
es extender esto a través métodos de
extensión
porque podemos hacer crecer esta clase o hacer crecer este método, y no queremos contaminar
nuestro programa punto Cs haciéndolo demasiado grande y a veces difícil
o difícil de entender Así que vamos a seguir adelante y
hacer clic en el proyecto, hacer clic en Agregar nueva carpeta, y vamos a nombrar
estas extensiones. Vamos a hacer clic derecho en las carpetas de
extensión, hacer clic en Agregar, y luego clase. Y sigamos adelante y nombremos a
estos dos Swagger Config. Entonces ahora tenemos nuestra nueva clase de confit
swagger, y queremos hacer de
esta una extensión Bien extensión,
permite agregar
métodos a tipos existentes sin crear un
nuevo tipo derivado, recompilar o
modificar de otra manera el tipo original Los métodos de extensión son estáticos. Así que vamos a seguir adelante y crear esta clase como una clase estática. Y sigamos adelante
y creamos un método. Así que vamos a nombrar esto añadir Swagger. Y sigamos adelante y abramos
y cerremos los soportes. Si venimos aquí
al programa punto TS
y pongo el cursor sobre los servicios, podemos ver que
la gen Ag Swagger es una extensión de los Por lo que un servicio es una colección
de servicios oculares. Así que queremos
replicar este comportamiento para que
podamos agregar nuestra propia
extensión a Swagger Así que sigamos adelante y tengamos el parámetro como una colección de servicios
oculares. Entonces esta colección de servicios oculares Y entonces sólo
puedo seguir adelante y cortar a este tipo y pegarlo aquí. No necesitamos a nuestro constructor, y nuestros servicios ahora son la colección
de servicios. Entonces, sigamos adelante y reemplacemos los servicios con cobranza
de servicios. Entonces creamos nuestro método de
extensión, sin embargo, no lo agregamos
al programa dot TS. Entonces esto debería fallar porque
todavía está usando Swagger,
como puedes ver Sin embargo, no tenemos nuestro middleware
Swagger gen inyectado Entonces, sigamos adelante y ejecutemos
esto para ver qué pasa, y esto debería
generar una excepción. Bien, entonces sí
generó una excepción. Sigamos adelante y
agreguemos el middleware. Así Constructor punto Servicios, punto añadir swagger el
auto completo para mí adelante y
agreguemos eliminar el Gen. Si golpeo Control Dot, puedo ver que me falta
la extensión de uso de la API web Entonces sigamos adelante e
incluyamos eso ahí dentro. Y ahora tenemos nuestro add Swagger. Mmm. Si hago clic derecho en esto y pico definición
o simplemente voy a definición, puedo ver que está
apuntando a nuestra Swagger, clase de extensión de configuración Entonces, sigamos adelante y ejecutemos
esto para ver qué pasa. Como puedes ver ahora, tenemos
Swagger correctamente habilitado.
13. Personalización de Swagger: Oigan, todos. Bienvenido de nuevo. Ahora que tenemos
nuestra Swagger Config,
sigamos adelante y volvamos
a ver nuestro programa Entonces aquí en ese programa, tenemos nuestro en Swagger
como nuestro método de extensión Y aquí abajo, podemos ver
que el entorno de aplicaciones también incluye a Swagger en
el pipeline de solicitudes Entonces podemos ver que esto incluye Swagger como una aplicación web Entonces lo que podemos hacer
ahora es seguir adelante y crear una extensión de
la aplicación web. Entonces, si vamos a nuestra
Swagger Config, puedo crear otro método
estático Y llamémoslo,
usa diseños swagger. Entonces esto es de tipo aplicación
web. Y lo que podemos hacer ahora es seguir
adelante y copiar este código. Al método de extensión. No necesitamos la app. En realidad,
la aplicación web es la app, como puedes ver. Así que básicamente mantuvimos la misma descripción que el último programa dot
Cs Gorey comportamiento Y vamos a seguir adelante e incluir este uso Swagger diseño
en el programa punto Cs Entonces, lo que vamos a hacer ahora es app dot use diseños Swagger Ahora bien, si miro o si
voy a la definición, veré que ahora
se está utilizando esto Nos acabamos de guardar
un par de líneas de código en el programa Cs. Como puedes ver, se ve
mucho más limpio que antes. Y ahora podemos hacer crecer nuestras
configuraciones de swagger dentro nuestra clase de extensión swagger En este caso, nuestra clase de configuración
Swagger. Si ejecuto esto, debería
poder ver a Swagger normalmente. Ahí lo tienes. API web, pronóstico del tiempo, tienes un par de encabezados. Ahora podemos personalizar Swagger. Podemos cambiar el título. Podemos poner una descripción. Podemos poner datos de
licencia de contacto. Y esa voluntad en caso de que
quieras hacer eso, lo
harás aquí en el
anuncio Swagger Gen, No hagamos eso, pero por si
acaso necesitas hacerlo, solo
agregas, digamos, opciones Entonces sigues adelante y abres
el Option swagger Llamemos a este punto de vista uno. Y sigamos adelante y
creamos una nueva información API abierta. Y aquí, puedes agregar, por ejemplo, Version Von. Podría agregar título. Digamos con API. Y sólo vamos a alquilarlo. No quiero tener
demasiada información. API web UDM, como puedes ver, API web
UDM versión uno, uno Así podrás agregar, ya
sabes, todos los parámetros, propiedades o personalizar la documentación arrojada
a través de esta Como puedes ver,
esta clase puede crecer y sobre todo crecerá
en proyectos comunes. Y mantuvimos esto mucho más limpio. Y esto vendrá
en el futuro cuando empecemos a inyectar nuestros servicios a la hora de implementar una arquitectura
limpia.
14. Presentación del problema y requisitos: Oigan, chicos. Bienvenido de nuevo. Ahora, hablemos de
los requisitos para una aplicación
que vamos a desarrollar y que vamos a implementar una arquitectura limpia. La idea aquí es presentar un problema simple y luego resolverlo de manera rápida, luego implementar una arquitectura
limpia dentro de ese alcance dado. Entonces primero, veamos nuestros requisitos
funcionales. Vamos a crear una API web que básicamente
ya creamos, y vamos a
crear un punto final, y la entrada de ese punto final
es una lista de enteros La API debe ordenar
la lista de menor a mayor Después de eso, la API debe enviar un correo electrónico con la lista ordenada en el
cuerpo del correo electrónico. Entonces es una implementación bastante
simple. Y consideremos que esta implementación respecto
al mecanismo de clasificación es parte de nuestras reglas de negocio. Así que revisemos nuestros requisitos
funcionales. Cree una API web que contenga
un punto final para ordenar. La entrada del punto final
es una lista de enteros. Recuerda, esto es parte
de nuestras reglas de negocio. Después de ordenar el punto final, se debe
enviar
un correo electrónico con una especie de lista para ordenar en cours.com, que es solo un correo electrónico de ejemplo Así que ahora veamos nuestros requisitos no
funcionales. Queremos asegurarnos de que
haya una arquitectura
limpia para
esta aplicación. Entonces tendremos nuestra
capa de presentación con nuestra API web. Vamos a tener
una capa de aplicación que represente nuestra implementación de
lógica de negocios, y vamos a tener nuestra
capa central con las abstracciones También tendremos
la infraestructura
con el servicio de correo electrónico. Entonces nuestro estado actual es que
solo tenemos un proyecto API web. Actualmente, la
API web se implementa en.net. Así que vamos a hacer un resumen. Tenemos nuestros requisitos funcionales y
no funcionales, que es básicamente
ordenar una lista de enteros y enviar un correo electrónico, implementando arquitectura limpia Los ejemplos estarán
en.net pero podrían ser fácilmente replicables en otros lenguajes de
software. H,
15. Crea el controlador: Oigan, chicos. Bienvenido de nuevo. Ahora, comencemos
alguna implementación. Entonces lo primero es
lo primero, lo que queremos
hacer es crear nuestro controlador
Sort. Así que sigamos adelante y hagamos
clic derecho en la carpeta Controladores. Haga clic en AD. Vamos a agregar una nueva
clase, y vamos a nombrarla. Controlador de clasificación. Oh, ahora tenemos nuestra nueva
clase de controlador de clasificación. Para convertirlo en un punto final de API web, sigamos adelante y
veamos los atributos del controlador de
weathercast predeterminado Entonces queremos tener el
controlador API y la ruta. Voy a seguir adelante y copiar
esto solo por simplicidad. Ahora, sigamos adelante y
creamos un constructor vacío. Dejémoslo aquí por ahora. Y vamos a crear nuestro punto final. Entonces voy a tener un
público vamos a tenerlo como yo numerable de t porque
queremos devolver una lista de nt Sigamos adelante y llamémoslo tipo. Y también queremos tener una
lista de Int como parámetro. Así que vamos a seguir adelante y tener
matriz de Int como parámetro. Fresco. Volvamos array. Y voy a seguir adelante
y hacer de esto un post TTB. Ejecutemos
esto rápidamente. Entonces ahora solo estoy recibiendo una lista de y
devolviendo esa misma lista. Aquí tenemos nuestro tipo.
Vamos a probarlo. 012, ejecutar cero, uno, dos. Fresco. Entonces eso está funcionando. Ahora, sigamos adelante e implementemos
un simple tipo de burbuja. Entonces tengo esto como método
privado. Recuerda, vamos a
hacerlo rápido y rápido,
y luego
vamos a refaccionarlo Tan privada nt. Vamos
a llamarlo tipo burbuja. También va a contener
array t como parámetro. Vamos al segundo grado para el suyo aquí. Uno. Oh, campo de Attack para costilla. J menor que la longitud de la matriz. J más más. ¿Quién? Todo bien. Así que tenemos dos cuatro patas
pasando por la matriz. Ahora vamos a verificar
el valor y luego a intercambiar. Entonces solo un simple
tipo de burbuja en este caso, queremos verificar si J es
mayor que J más uno. Entonces, si J es
más grande que J más uno, entonces cambiaremos J. Entonces matriz en J más un tipo de hacerlo hacia atrás en temp y tendremos
matriz en J más uno. Y luego tendremos
array en J Ghost Temp. Sigamos adelante y devolvamos esto. Matriz de retorno. Y
voy a usar el método bubble sort
que acabamos de implementar. Y queremos
devolver el resultado. Resultado. Muy bien,
veamos qué pasa Esto debería ser suficiente
para ordenar nuestra lista. Así que hagamos clic en
SOR. Pruébalo. Vamos a tener cero,
uno, dos, tres, cero, uno, dos, tres,
haga clic en Ejecutar. Vamos a acurrucar
cero, cero, uno, uno, dos, dos, tres,
tres. Entonces ahí vamos. Tenemos nuestra lista ordenada. Creamos nuestro controlador, y ahora podemos pasar
al siguiente paso.
16. Creación de la capa de aplicación: Oigan, chicos. Bienvenido de
nuevo. Ahora, continuemos con nuestros detalles de
implementación. Entonces, veamos primero esta
diapositiva de aquí. Entonces hablemos de
la capa de aplicación. La capa de aplicación contiene la
implementación de lógica de negocios, que es una especie de parte
del código donde
queremos proteger. Estamos considerando el
mecanismo de clasificación , la lógica de negocio. No queremos complicar demasiado
las cosas. Entonces consideraremos
que, ya sabes, una especie simple es
la lógica de negocio, que es la parte más importante de nuestra aplicación que
queremos proteger. Si miramos el diagrama aquí, la aplicación tiene la implementación de lógica de
negocios. Y también queremos
asegurarnos de que arquitectura
limpia esté en su lugar. Y cuando miramos el principio de
responsabilidad única, establece
que una clase debe tener una y sólo
una razón para cambiar. Entonces nuestra clase de controlador tiene la lógica de negocio para clasificar, y también es un controlador
para el patrón MVC Entonces lo que queremos hacer es
crear la capa de aplicación y mover esa implementación
a esa capa. Entonces volvamos al código. Entonces lo
primero es lo primero, lo que
vamos a hacer es hacer
clic derecho en la solución, y agreguemos un nuevo proyecto. Busquemos biblioteca de clases. Vamos a llamarlo aplicación.
Haga clic en Siguiente. Lo tendré as.net siete, que es la última versión
actual como la grabación de este video. Voy a dar click en Crear. Fresco. Ahora tenemos una nueva
capa llamada aplicación. Sigamos adelante y miremos
nuestro controlador de clasificación. Entonces aquí tenemos
la implementación del tipo burbuja en
nuestro controlador de clasificación. Recuerda, queremos tener esto
a nivel de aplicación. Entonces lo que vamos a hacer es mover esta lógica hasta
la aplicación. Así que sólo voy a
cortar este código aquí. Voy a pegarlo aquí
como parte de esta clase. Voy a seguir adelante y renombrar esta clase para ordenar servicio. También cambiaré el nombre de la clase
en la estructura de carpetas. Ordenar servicio. Fresco. Entonces ahora tenemos
una nueva clase pública. Hagamos público este método porque queremos que
sea accesible. Ahora tenemos nuestra capa de
aplicación que implementa el BubbleSort Ahora, Bubble Sort ya no está disponible en la capa API web. Entonces tenemos que incluir la dependencia de la
aplicación. Así que vayamos a nuestras
dependencias y hagamos
clic derecho en Referencia del proyecto Sigamos adelante y
agreguemos la aplicación. Fresco. Entonces ahora, si
miramos la capa de aplicación, podemos ver que esta es una clase. Entonces, sigamos adelante y
escribamos una nueva instancia de esa clase. Entonces nuevo servicio de clasificación. Tipo de burbuja. Y
volvamos a ejecutar esto. Ordenar 01201, ejecutar Fresco. Entonces
parece que está clasificando, y lo tenemos todo resuelto. Entonces ahora
volvamos a las diapositivas. Entonces como puedes ver aquí,
ahora tenemos nuestra API web, que incluye la capa de
aplicación.
17. Creación de la capa de dominio: Oigan, chicos. Bienvenida de nuevo. Así que echemos un vistazo a
nuestra aplicación. Tenemos nuestra capa API web
en nuestra capa de aplicación. Entonces ahora queremos
mirar la capa central. Entonces, ¿qué es la capa central? Entonces en este caso, esta capa
contiene las abstracciones. ¿Y cuáles son las abstracciones? Las abstracciones son básicamente
las interfaces que definen los contratos y generalmente
se definen entre capas Entonces, si miramos el diagrama, podemos ver que el núcleo
define las abstracciones La aplicación tiene la implementación
de lógica de negocios. Por supuesto, esta es una adaptación a nuestro entorno actual. Para que el núcleo defina las abstracciones
en la aplicación para implementarlas realmente, tenemos que mirar el principio de inversión de
dependencia,
justo, donde podemos
inyectar la Si nos fijamos en el principio de
inversión de dependencia, que forma parte de sólido, dice, dependemos de abstracciones
y no Entonces, si nos fijamos en el nivel de
controlador, tenemos una nueva instancia de
la clase de servicio sort, y eso depende la concreción o
la implementación Para tener las abstracciones a nivel de dominio o
a nivel core, tenemos que inyectar la
dependencia en la startup principal En este caso, la capa de
presentación. Entonces echemos un vistazo al código. Entonces, lo primero que queremos ver
es nuestro controlador de clasificación. Entonces aquí podemos ver que esto está sintiendo un nuevo servicio de tipo,
y no queremos eso Queremos depender de
las abstracciones. Entonces, sigamos adelante y
agreguemos una nueva biblioteca de clases. En este caso, una nueva capa. Vamos a llamarlo núcleo. Y ahora queremos crear la interfaz para
ese servicio de clasificación. Si hacemos clic derecho, podríamos generar una interfaz
automáticamente. No obstante, sigamos adelante y
solo implementémoslo, ¿verdad? Entonces tenemos el servicio Sort, y luego tenemos el
tipo burbuja como el contrato. Entonces déjame copiar a este tipo. Déjame seguir adelante y renombrar
esto al servicio de Isurce. Tengamos esto como interfaz. Sigamos adelante y
agréguela aquí. Fresco. Entonces ahora tenemos una interfaz, que es la abstracción, y
tenemos la implementación. Ahora tenemos que definir que el servicio de origen
es de servicio de eSRT En este caso, tenemos que
agregar esa dependencia. Así que sigamos adelante
y pulsemos con
el botón derecho en la dependencia de la capa de
aplicación. Agregar referencia de proyecto, y seguir adelante y agregar nuestro núcleo. Fresco. Déjame golpear Control
Dot y usar Core. Entonces importa ese espacio de nombres. Bueno, ahora tenemos nuestro servicio SRT como
servicio de ESRT. Ahora queremos cambiar
nuestra implementación a nivel API o nivel de
presentación. Entonces lo primero que queremos hacer es configurar para inyección de
dependencia, y podemos hacerlo en
el programa punto Cs, que es una especie de
nuestro inicio principal. Entonces aquí en el programa punto Cs,
sigamos adelante y agreguemos servicios de punto
Builder. Vamos a agregarlo como ámbito
agregar alcance Recuerde, tenemos que agregar también
las dependencias Entonces la API web conoce
la aplicación, pero no conoce el núcleo. Entonces, si miramos si ampliamos proyectos de
dependencias,
conoce la aplicación Sigamos adelante y agreguemos el core para que pueda reconocer
esa interfaz. Incluyamos el servicio SRT, y esa interfaz
es implementada por el servicio SRT SRT a nivel
de Fresco. Entonces ahora que agregué mi inyección de dependencia en
el inicio principal, within.net, es bastante simple porque las bibliotecas ya
existen Así que ahora básicamente puedo inyectar mi interfaz en el controlador de
clasificación a nivel constructor. Entonces déjame seguir adelante
e inyectarlo aquí. Ahora, en lugar de usar
esta concreción, puedo seguir adelante y
usar la abstracción, que configuré en mi principal, y tengo todas mis
dependencias Y puedo quitar el uso de la aplicación porque ahora
solo estoy dependiendo
directamente del core, que es mi abstracción. Y puse ese núcleo en el
nivel de inyección de dependencia en mi programa punto Cs. Entonces déjame dirigir esto. Y ahí está el
tipo 012, 010 0112. Entonces está funcionando bien.
Volvamos con este tipo. Entonces, si miramos
nuestros estados actuales, tenemos una API web, y ahora
básicamente se encargará de enviar
los correos electrónicos. Aún no lo hemos implementado
, pero lo haremos. Incluye la capa de
aplicación para la concreción donde implementamos o declaramos
la inyección de dependencia También incluye la capa
central donde tenemos la abstracción para la inyección de
dependencia, y luego usamos esa abstracción
a nivel de controlador. Y ahora esto empieza
a parecerse un poco más a la arquitectura
limpia.
18. Creación de la capa de infraestructura: Oigan, chicos. Bienvenida de
nuevo. Bueno, sigamos adelante y
miremos algunas diapositivas. Entonces hablemos de la capa de
infraestructura. Entonces esta capa contiene el framework y
los drivers de nuestro código. Estos frameworks son
conexiones a la base de datos, conexiones al servicio de almacenamiento, conexiones al
servicio de correo electrónico o similares. Cuando miramos el diagrama, podemos ver que la
infraestructura está en la
parte más externa de la capa. Por lo que la infraestructura
no debe o debe considerarse un detalle y
no debe tener ninguna influencia
sobre las capas internas, que son la aplicación
en las capas centrales. Entonces, sigamos adelante y
miremos el código. Entonces ahora lo que
queremos hacer es enviar el correo electrónico para ordenar en cours.com Y en el cuerpo del correo electrónico, vamos a seguir adelante
y tener la matriz ordenada. Entonces ya seguí adelante e
implementé esta parte para nosotros. Implementé a nivel de
controlador o a nivel de presentación
para ahorrar algo de tiempo. Entonces cuando miramos
esto, podemos ver hay un
correo electrónico de envío que tenemos de. Ahí está el cuerpo, y
luego estoy configurando esto a lo estoy enviando
a una carpeta local, solo para fines de prueba. Entonces, si miro o abro
mi carpeta de correo electrónico local, podemos ver que está vacía.
Déjame refrescarlo. Podemos ver que está vacía. Entonces, lo que
queremos hacer ahora es crear nuestra
capa de infraestructura para que podamos tener nuestra implementación
del método send email. Entonces, hagamos clic en la solución, haga clic en Agregar nuevo proyecto. Busquemos Biblioteca de
clases a continuación. Vamos a nombrar a esta Infraestructura. Siguiente y crear. Fresco. Ahora tenemos nuestra clase de
infraestructura. Vamos a seguir adelante y nombrar este servicio de correo electrónico
para cambiar el nombre de la clase. Sigamos adelante y cortamos
y peguemos nuestro método. Hagámoslo público. Ahora, agreguemos nuestras
abstracciones al núcleo. Entonces voy a seguir adelante
y copiar este nombre, clic en AD
voy a seguir adelante y
agregar I Servicio de correo electrónico. Tenerlo como interfaz pública. Y luego sólo tienes que seguir adelante
y copiar la firma. Fresco. Así que ahora tenemos nuestro servicio
I Email. Con el servicio de correo electrónico, y luego nuestra infraestructura
necesitará esa dependencia. Entonces, sigamos adelante y agreguemos el
núcleo a la infraestructura. Recuerde, la infraestructura
está en la capa más externa, por lo que puede depender de
las partes internas. Entonces ahora vamos
a incluir core. Me gusta, Bien, vamos a controlar
eso aquí y agregar el espacio de nombres Quién. Sigamos adelante y agreguemos la
capa de infraestructura a nuestra API web. Entonces agreguemos la capa de
infraestructura. Y sigamos adelante y configuremos nuestra inyección de dependencia
en el programa punto Cs. Entonces aquí voy a tener
Builder dot services ADS COPE I email
service Email service Email service. Fresco. Y en el nivel del
controlador de clasificación, vamos a inyectar esa dependencia. Por lo tanto, servicio de correo electrónico de
solo lectura privada . Servicio de correo electrónico. Y vamos a configurarlo aquí
a nivel de contratista. Fresco. Ahora, en lugar de enviar el correo electrónico como una
implementación concreta,
sigamos adelante y utilicemos nuestra interfaz de servicio de
correo electrónico. Entonces servicio de correo electrónico enviar correo electrónico. Fresco. Entonces, vamos a poner en marcha esto. Para
que podamos probar nuestros resultados. Entonces déjame abrir mi carpeta de correo electrónico, como podemos ver, está vacía. Volvamos al código y esperemos hasta que se inicie la
aplicación. Aquí tenemos nuestra swagger.
Probemos esto. 01, dos, cero,
uno, dos, Ejecutar. 0011, dos, dos. Parece que está bien. Sigamos adelante y
abramos nuestro correo electrónico. Déjame abrir con el correo 001122,
y ahí está
tosortatcurs.com y ahí está
tosortatcurs.com Entonces ahora cumplimos con nuestros requisitos. Volvamos a las diapositivas. Y podemos ver ahora que nuestra API web está utilizando
la infraestructura, que contiene el servicio de
correo electrónico. También utiliza la capa central
para las abstracciones y
la capa de aplicación para
la implementación de clasificación Ahora tenemos algún
tipo de flexibilidad. No nos
preocupa la infraestructura, y no nos preocupa
la capa de presentación. Estamos preocupados por nuestra
aplicación y la capa central, que contiene nuestro algoritmo, contiene nuestra lógica de negocio,
contiene nuestras abstracciones La infraestructura en la API
web es solo un detalle. Si nos fijamos en el diagrama
de Arquitectura limpia, este diagrama a la
derecha es básicamente una representación muy similar
del diagrama a la izquierda.
19. Conclusión y descripción general: Oigan, chicos. Ahora, revelemos algunas de las
cosas que aprendimos. Entonces primero, pasamos por
los sólidos principios. Hablamos del principio de
responsabilidad única,
el principio abierto y cerrado,
el principio de lista de
sustitución,
el principio de
segregación de la interfaz
y el principio de
inversión de dependencia Luego revisamos los conceptos del modelo C
cuatro, entrando en el contexto del sistema, el diagrama de contenedores,
el diagrama de componentes y luego el diagrama de código. Hablamos de capas y responsabilidades a la
hora de diseñar software. Finalmente, revisamos los conceptos
de arquitectura limpia. Entonces aprendemos que es un enfoque centrado en el
dominio. Aprendemos sobre las
responsabilidades de cada capa y por qué las tenemos. Finalmente, implementamos código basado en un conjunto de requisitos. El diseño final
de lo que se ha implementado está representado
por este diseño aquí. Así que creamos una API web. Creamos una capa de aplicaciones, una capa central para abstracciones y luego nuestra
capa de infraestructura para servicios de correo electrónico Bueno, estos son algunos
libros que recomiendo. Tan limpia Arquitectura de
Robert C. Martin, tío Bob. Y también hay un libro electrónico que es gratuito llamado Architect in Modern Web Applications con asp.net core y
Microsoft Azure En este libro de Steve Smith, habla brevemente sobre la arquitectura
limpia. Pero es un libro bastante redondeado,
bueno, bien redondeado. Bueno, si llegaste hasta aquí, gracias por tu
tiempo y esfuerzo. Espero que disfrutes el contenido. Si te gustan los clores,
por favor deja una reseña. Gracias, y cuídate.