Estructurando el Proyecto
Lino fue desarrollado para simplificar la creación de proyectos escalables y modulares de manera eficiente. Ofrece una solución bien estructurada, con una clara separación de responsabilidades entre las capas, y está preparado para crecer a medida que evolucionen las necesidades de su proyecto.
Al crear un proyecto con Lino, generas una solución .NET organizada según las mejores prácticas de arquitectura y modularización, enfocada en el rendimiento, la escalabilidad y la facilidad de mantenimiento.
Creando un Nuevo Proyecto
El comando lino project facilita la creación de nuevos proyectos .NET de manera simple y eficiente. Con él, puedes configurar la estructura de tu proyecto, seleccionar las dependencias necesarias y definir configuraciones de idioma e infraestructura.
Para crear un nuevo proyecto, utiliza el siguiente comando:
lino project new
Durante la ejecución, la CLI solicitará la siguiente información:
- Espacio de nombres del Proyecto: Define el espacio de nombres principal de la soluciĂłn.
- Nombre de VisualizaciĂłn: Nombre amigable que se muestra en las interfaces.
- Lenguaje de ProgramaciĂłn: Actualmente solo se admite C# (.NET).
- Stack de Desarrollo: Actualmente .NET 9 con Aspire.
- ÂżUtilizar Analizadores de CĂłdigo? Elige entre SĂ o No.
- ¿Utilizar Caché Distribuido? Elige entre Sà o No.
- ÂżUtilizar ComunicaciĂłn AsĂncrona? Elige entre SĂ o No.
- Idioma de los Datos: Define el idioma utilizado para los nombres de las entidades y otros datos informados en el sistema.
- Idiomas Soportados por la AplicaciĂłn: Permite agregar soporte para hasta 10 idiomas para internacionalizaciĂłn (i18n).
- Idioma Predeterminado: Define el idioma principal utilizado en APIs, mensajes de retorno, validaciones y en la interfaz de usuario.
Después de confirmar la información, Lino creará automáticamente la estructura del proyecto, como se muestra a continuación:
MyApp/ ├── MyApp.sln ├── src/ │ ├── Aspire/ │ │ ├── AppHost/ │ │ │ └── MyApp.AppHost.csproj │ │ └── ServiceDefaults/ │ │ └── MyApp.ServiceDefaults.csproj │ └── Services/ │ └── Shared/ │ ├── API/ │ │ └── MyApp.Shared.API.csproj │ ├── Application/ │ │ └── MyApp.Shared.Application.csproj │ ├── Domain/ │ │ └── MyApp.Shared.Domain.csproj │ ├── Infrastructure/ │ │ └── MyApp.Shared.Infrastructure.csproj │ └── Infrastructure.Persistence/ │ └── MyApp.Shared.Infrastructure.Persistence.csproj └── tests/
Analizadores de CĂłdigo
Los analizadores de código estático son herramientas poderosas que ayudan a garantizar la calidad y consistencia del código durante el desarrollo. Lo hacen inspeccionando el código fuente sin necesidad de ejecución, detectando errores, problemas de estilo y otras inconsistencias.
Cuando eliges habilitar los analizadores de código durante la creación del proyecto, la CLI configurará automáticamente los siguientes paquetes para ti:
- StyleCop.Analyzers: Realiza verificaciones de estilo de cĂłdigo, como formato de sangrĂas, espaciado y convenciones de nombres.
- SonarAnalyzer.CSharp: Un conjunto de reglas de calidad de cĂłdigo y seguridad, que ayuda a detectar fallas comunes y vulnerabilidades potenciales en el cĂłdigo.
- Roslynator.Analyzers: Ofrece una variedad de reglas de calidad y mejoras para el cĂłdigo C#, ayudando a identificar oportunidades de refactorizaciĂłn y optimizaciĂłn.
Ventajas de los Analizadores de CĂłdigo:
- Mejora de la Calidad: Ayudan a mantener el cĂłdigo limpio, legible y libre de problemas comunes.
- PrevenciĂłn de Errores: Detectan errores antes de que se ejecuten, permitiendo que el desarrollador corrija los problemas temprano en el proceso.
- Estándarización: Aseguran que todos los desarrolladores sigan las mismas convenciones y reglas de estilo, mejorando la consistencia del código.
- RefactorizaciĂłn Asistida: Facilitan la refactorizaciĂłn del cĂłdigo, proporcionando sugerencias de mejora.
Al activar los analizadores de código, tendrás una forma proactiva de mejorar la calidad de tu código y reducir el riesgo de fallos en el entorno de producción.
Caché Distribuido
El caché distribuido es una técnica utilizada para mejorar el rendimiento y escalabilidad de las aplicaciones, almacenando datos frecuentemente accedidos en una capa de caché externa a la base de datos. Permite que las instancias de la aplicación compartan datos en caché de manera eficiente, garantizando alta disponibilidad y reducción del tiempo de respuesta.
Si decides habilitar el caché distribuido durante la creación de tu proyecto, Redis será integrado a tu contenedor Aspire, proporcionando un sistema de caché de alta disponibilidad.
Ventajas del Caché Distribuido:
- Mejora del Rendimiento: Reduce el tiempo de respuesta de las solicitudes, minimizando el acceso a la base de datos.
- Escalabilidad: Permite que la aplicación sea escalada horizontalmente, ya que el caché puede ser accedido por diferentes instancias de forma transparente.
- Alta Disponibilidad: Con Redis, el caché se mantiene disponible incluso en caso de fallos, ofreciendo una solución robusta para sistemas distribuidos.
- ReducciĂłn de Costos: Disminuye la carga en la base de datos y en el sistema, reduciendo la necesidad de procesamiento en solicitudes repetitivas.
Al habilitar el caché distribuido, mejorarás significativamente el rendimiento de tu aplicación, garantizando una respuesta más rápida a los usuarios y reduciendo la carga en los sistemas backend.
ComunicaciĂłn AsĂncrona
La comunicaciĂłn asĂncrona es un enfoque que permite que los sistemas y componentes se comuniquen de manera no bloqueante, es decir, sin que el envĂo o recepciĂłn de datos interrumpa el procesamiento de otras tareas. Esto es especialmente Ăştil en sistemas distribuidos y en situaciones de alta carga, donde la eficiencia y la resiliencia son cruciales.
Si eliges habilitar la comunicaciĂłn asĂncrona, RabbitMQ será integrado en tu proyecto y MassTransit se configurará para facilitar el uso de esta comunicaciĂłn asĂncrona en tu aplicaciĂłn.
Ventajas de la ComunicaciĂłn AsĂncrona:
- Mejor Rendimiento: Permite que las operaciones se realicen en paralelo, sin bloquear el flujo de ejecuciĂłn del sistema.
- Escalabilidad: Facilita la escalabilidad del sistema, permitiendo que maneje grandes volúmenes de datos y usuarios simultáneos sin perder rendimiento.
- Resiliencia: En caso de fallos temporales, la comunicaciĂłn asĂncrona permite que los mensajes sean procesados nuevamente o almacenados para su procesamiento posterior.
- Desacoplamiento: Los sistemas pueden ser diseñados para comunicarse sin depender directamente de respuestas inmediatas, promoviendo mayor flexibilidad y organización.
La integración con RabbitMQ y el uso de MassTransit hacen que la comunicación entre los componentes sea más eficiente y resiliente, ayudando a garantizar la escalabilidad y flexibilidad de tu aplicación.
PrĂłximos Pasos
Ahora que has creado tu proyecto .NET con Lino, ábrelo en tu editor de código favorito. Puedes usar Visual Studio, Visual Studio Code o cualquier otro IDE de tu elección.
Con el proyecto abierto, puedes comenzar a agregar y configurar los servicios que componen tu aplicaciĂłn. Este es el siguiente paso en el flujo de desarrollo.
En la siguiente sección, te mostraremos cómo crear y configurar estos servicios en tu nuevo proyecto, preparándolo para crecer de manera organizada y escalable según las necesidades de tu aplicación.
CreaciĂłn y gestiĂłn de servicios
DespuĂ©s de crear el proyecto, el siguiente paso es agregar servicios. Lino ofrece una forma simple e intuitiva de crear servicios, que pueden ser utilizados en sistemas monolĂticos o arquitecturas de microservicios.
Para crear un nuevo servicio, utiliza el siguiente comando:
lino service new
Durante la ejecución, el CLI pedirá la siguiente información:
- Namespace del servicio: Define el nombre y el namespace del servicio.
- Nombre para mostrar: Nombre amigable mostrado en las interfaces.
- Tipo de servicio: Elige entre Simple o Modular.
- Base de datos: Elige entre PostgreSQL o SQL Server.
Si el tipo de servicio elegido es Simple, también se pedirá la siguiente información:
- Estilo arquitectĂłnico: Actualmente, solo Clean Architecture.
- ÂżUsar Strongly Typed ID? Elige entre SĂ o No.
Tipos de servicio
Servicio simple: Un servicio simple tiene una estructura más liviana, adecuada para sistemas monolĂticos o proyectos de microservicios donde cada servicio tiene una responsabilidad independiente.
Servicio modular: Para sistemas más grandes, que requieren una mayor organizaciĂłn y escalabilidad, puedes optar por un servicio modular. Este tipo permite dividir el servicio en mĂłdulos más pequeños y especĂficos, facilitando el mantenimiento y la expansiĂłn del sistema.
Tanto si el servicio es simple como modular, la base de datos será única para cada servicio. La arquitectura y el uso de Strongly Typed IDs se aplican a los servicios simples. En el caso de los servicios modulares, la decisión sobre esto se tomará a nivel de cada módulo creado dentro del servicio.
La estructura de Lino es flexible, permitiendo crear servicios simples y modulares dentro del mismo proyecto.
Estilo arquitectĂłnico
Lino ya aplica Clean Architecture para todos los servicios. Esto garantiza que tu aplicaciĂłn siga una arquitectura bien estructurada, promoviendo la separaciĂłn de responsabilidades y facilitando el mantenimiento y la escalabilidad.
Ventajas de Clean Architecture:
- Desacoplamiento: La lógica de negocio es independiente de los detalles técnicos, lo que proporciona una mayor flexibilidad y capacidad de prueba.
- Mantenibilidad: Dado que las capas están bien separadas, es más fácil hacer cambios sin afectar otras partes del sistema.
- Capacidad de prueba: La separaciĂłn de preocupaciones facilita la creaciĂłn de pruebas unitarias e integraciĂłn para cada capa de forma independiente.
- Escalabilidad: El proyecto es más fácil de escalar, ya que los componentes pueden ser modificados o reemplazados sin afectar la lógica de negocio.
Si decides crear un servicio simple utilizando la implementación de Clean Architecture, el proyecto será generado con la siguiente estructura:
MyApp/ ├── MyApp.sln ├── src/ │ ├── Aspire/ │ │ ├── AppHost/ │ │ │ └── MyApp.AppHost.csproj │ │ └── ServiceDefaults/ │ │ └── MyApp.ServiceDefaults.csproj │ ├── Integrations/ │ │ └── Internal/ │ │ └── MySimpleService/ │ │ └── Http/ │ │ ├── Clients/ │ │ │ └── MyApp.Integrations.MySimpleService.Http.Clients.csproj │ │ └── Contracts/ │ │ └── MyApp.Integrations.MySimpleService.Http.Contracts.csproj │ └── Services/ │ ├── Shared/ │ │ ├── API/ │ │ │ └── MyApp.Shared.API.csproj │ │ ├── Application/ │ │ │ └── MyApp.Shared.Application.csproj │ │ ├── Domain/ │ │ │ └── MyApp.Shared.Domain.csproj │ │ ├── Infrastructure/ │ │ │ └── MyApp.Shared.Infrastructure.csproj │ │ └── Infrastructure.Persistence/ │ │ └── MyApp.Shared.Infrastructure.Persistence.csproj │ └── MySimpleService/ │ ├── API/ │ │ └── MyApp.MySimpleService.API.csproj │ ├── Application/ │ │ └── MyApp.MySimpleService.Application.csproj │ ├── Domain/ │ │ └── MyApp.MySimpleService.Domain.csproj │ ├── Infrastructure/ │ │ └── MyApp.MySimpleService.Infrastructure.csproj │ ├── Infrastructure.Persistence/ │ │ └── MyApp.MySimpleService.Infrastructure.Persistence.csproj │ └── IntegrationEvents/ │ └── MyApp.MySimpleService.IntegrationEvents.csproj └── tests/ └── Services/ └── MySimpleService/ ├── IntegrationTests/ │ └── MyApp.MySimpleService.IntegrationTests.csproj └── UnitTests/ └── MyApp.MySimpleService.UnitTests.csproj
Si eliges un servicio modular, el proyecto adoptará la siguiente estructura, permitiendo agregar nuevos módulos de forma flexible y organizada a lo largo del desarrollo del servicio:
MyApp/ ├── MyApp.sln ├── src/ │ ├── Aspire/ │ │ ├── AppHost/ │ │ │ └── MyApp.AppHost.csproj │ │ └── ServiceDefaults/ │ │ └── MyApp.ServiceDefaults.csproj │ └── Services/ │ ├── Shared/ │ │ ├── API/ │ │ │ └── MyApp.Shared.API.csproj │ │ ├── Application/ │ │ │ └── MyApp.Shared.Application.csproj │ │ ├── Domain/ │ │ │ └── MyApp.Shared.Domain.csproj │ │ ├── Infrastructure/ │ │ │ └── MyApp.Shared.Infrastructure.csproj │ │ └── Infrastructure.Persistence/ │ │ └── MyApp.Shared.Infrastructure.Persistence.csproj │ └── MyModularService/ │ ├── Host/ │ │ └── MyApp.MyModularService.Host.csproj │ ├── Infrastructure/ │ │ └── MyApp.MyModularService.Infrastructure.csproj │ └── Modules/ └── tests/
Strongly Typed ID
Strongly Typed ID es un enfoque que busca mejorar la seguridad y la claridad del cĂłdigo al garantizar que los tipos de identificadores (IDs) sean más especĂficos y fuertemente tipados, evitando el uso de tipos genĂ©ricos como int
o guid
para representar entidades Ăşnicas.
Con el Strongly Typed ID, en lugar de usar tipos genĂ©ricos, como un nĂşmero entero para representar un identificador de usuario, crearĂas un tipo especĂfico para el ID de usuario. Esto ayuda a evitar errores comunes, como el uso incorrecto de IDs de diferentes tipos en contextos equivocados.
Ventajas de usar Strongly Typed IDs:
- Seguridad de tipos: Garantiza que los IDs se usen correctamente, evitando mezclar diferentes tipos de identificadores, como IDs de usuarios con IDs de productos.
- Claridad: El cĂłdigo se vuelve más claro, ya que cada tipo de ID se representa explĂcitamente mediante una clase especĂfica.
- Facilidad de refactorizaciĂłn: Si el tipo de identificador cambia, solo debes modificar el tipo especĂfico de ID y el resto del cĂłdigo se mantiene seguro.
- Evita errores: Reduce la posibilidad de errores relacionados con el uso incorrecto de identificadores genéricos en contextos erróneos.
CreaciĂłn y GestiĂłn de MĂłdulos
Después de crear un servicio modular, el siguiente paso es agregar módulos a él. Los módulos permiten organizar la lógica de negocios de forma independiente, lo que aporta aún más escalabilidad y organización al sistema.
Para crear un nuevo mĂłdulo, usa el siguiente comando:
lino module new
Durante la ejecución, la CLI solicitará la siguiente información:
- Servicio: Define a qué servicio se agregará el nuevo módulo.
- Namespace del MĂłdulo: Define el nombre y namespace del mĂłdulo.
- Nombre de VisualizaciĂłn: Nombre amigable que se muestra en las interfaces.
- Estilo Arquitectural: Actualmente solo Clean Architecture.
- ÂżUsar ID fuertemente tipado? Elige entre SĂ o No.
Al final, Lino generará el nuevo módulo manteniendo la estructura de tu servicio modular:
MyApp/ ├── MyApp.sln ├── src/ │ ├── Aspire/ │ │ ├── AppHost/ │ │ │ └── MyApp.AppHost.csproj │ │ └── ServiceDefaults/ │ │ └── MyApp.ServiceDefaults.csproj │ ├── Integrations/ │ │ └── Internal/ │ │ └── MyModularService/ │ │ └── MyModule/ │ │ └── Http/ │ │ ├── Clients/ │ │ │ └── MyApp.Integrations.MyModularService.MyModule.Http.Clients.csproj │ │ └── Contracts/ │ │ └── MyApp.Integrations.MyModularService.MyModule.Http.Contracts.csproj │ └── Services/ │ ├── Shared/ │ │ ├── API/ │ │ │ └── MyApp.Shared.API.csproj │ │ ├── Application/ │ │ │ └── MyApp.Shared.Application.csproj │ │ ├── Domain/ │ │ │ └── MyApp.Shared.Domain.csproj │ │ ├── Infrastructure/ │ │ │ └── MyApp.Shared.Infrastructure.csproj │ │ └── Infrastructure.Persistence/ │ │ └── MyApp.Shared.Infrastructure.Persistence.csproj │ └── MyModularService/ │ ├── Host/ │ │ └── MyApp.MyModularService.Host.csproj │ ├── Infrastructure/ │ │ └── MyApp.MyModularService.Infrastructure.csproj │ └── Modules/ │ └── MyModule/ │ ├── API/ │ │ └── MyApp.MyModularService.MyModule.API.csproj │ ├── Application/ │ │ └── MyApp.MyModularService.MyModule.Application.csproj │ ├── Domain/ │ │ └── MyApp.MyModularService.MyModule.Domain.csproj │ ├── Infrastructure/ │ │ └── MyApp.MyModularService.MyModule.Infrastructure.csproj │ ├── Infrastructure.Persistence/ │ │ └── MyApp.MyModularService.MyModule.Infrastructure.Persistence.csproj │ └── IntegrationEvents/ │ └── MyApp.MyModularService.MyModule.IntegrationEvents.csproj └── tests/ └── Services/ └── MyModularService/ └── Modules/ └── MyModule/ ├── IntegrationTests/ │ └── MyApp.MyModularService.MyModule.IntegrationTests.csproj └── UnitTests/ └── MyApp.MyModularService.MyModule.UnitTests.csproj
Estructura de la Base de Datos
Es importante destacar que la base de datos está vinculada al servicio. Dentro de un servicio modular, cada módulo está representado por su propio esquema en la base de datos asociada. Este enfoque proporciona aislamiento y organización, sin necesidad de crear múltiples bases de datos distintas.
Sobre la Independencia entre MĂłdulos
Al igual que los servicios no tienen dependencias directas entre sĂ, los mĂłdulos tambiĂ©n se crean como proyectos independientes dentro del servicio.
Ventajas de este desacoplamiento:
- Aislamiento: Cada mĂłdulo puede evolucionar de forma independiente, facilitando el mantenimiento y la evoluciĂłn continua.
- OrganizaciĂłn: La aplicaciĂłn se vuelve verdaderamente modular, respetando los lĂmites de contexto (Bounded Contexts) y promoviendo buenas prácticas de arquitectura de software.
- Flexibilidad: Permite agregar, eliminar o refactorizar mĂłdulos sin afectar directamente a otros mĂłdulos del servicio.
- Facilidad para las pruebas: Cada mĂłdulo puede probarse de forma aislada, aumentando la confiabilidad y la calidad del sistema.
Con esto, concluimos el proceso de creación de módulos. En los próximos temas, veremos cómo estructurar los elementos internos de un módulo, como entidades, objetos de valor, enumeraciones, comandos, consultas, APIs, integraciones y mucho más.