Structuration du projet
Lino a été développé pour simplifier la création de projets évolutifs et modulaires de manière efficace. Il offre une solution bien structurée, avec une séparation claire des responsabilités entre les couches, et est prêt à évoluer selon les besoins de votre projet.
Lors de la création d'un projet avec Lino, vous générez une solution .NET organisée selon les meilleures pratiques d'architecture et de modularisation, en mettant l'accent sur les performances, l'évolutivité et la facilité de maintenance.
Création d'un Nouveau Projet
La commande lino project facilite la création de nouveaux projets .NET de manière simple et efficace. Avec elle, vous pouvez configurer la structure de votre projet, sélectionner les dépendances nécessaires et définir les configurations de langue et d'infrastructure.
Pour créer un nouveau projet, utilisez la commande suivante :
lino project new
Lors de l'exécution, l'outil CLI vous demandera les informations suivantes :
- Espace de noms du Projet : Définit l'espace de noms principal de la solution.
- Nom d'Affichage : Nom convivial affiché dans les interfaces.
- Langage de Programmation : Actuellement, seul le C# (.NET) est pris en charge.
- Stack de Développement : Actuellement .NET 9 avec Aspire.
- Utiliser des Analyseurs de Code ? Choisissez entre Oui ou Non.
- Utiliser un Cache Distribué ? Choisissez entre Oui ou Non.
- Utiliser la Communication Asynchrone ? Choisissez entre Oui ou Non.
- Langue des Données : Définit la langue utilisée pour les noms des entités et autres données dans le système.
- Langues Supportées par l'Application : Permet d'ajouter la prise en charge jusqu'à 10 langues pour l'internationalisation (i18n).
- Langue par Défaut : Définit la langue principale utilisée dans les API, les messages de retour, les validations et l'interface utilisateur.
Après avoir confirmé les informations, Lino créera automatiquement la structure du projet, comme indiqué ci-dessous :
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/
Analyseurs de Code
Les analyseurs de code statique sont des outils puissants qui aident à garantir la qualité et la cohérence du code pendant le développement. Ils le font en inspectant le code source sans exécution, détectant les erreurs, les problèmes de style et d'autres incohérences.
Lorsque vous choisissez d'activer les analyseurs de code lors de la création du projet, l'outil CLI configurera automatiquement les paquets suivants pour vous :
- StyleCop.Analyzers : Effectue des vérifications de style de code, telles que la mise en forme des indentations, les espacements et les conventions de nommage.
- SonarAnalyzer.CSharp : Un ensemble de règles de qualité du code et de sécurité, qui aide à détecter les défauts courants et les vulnérabilités potentielles dans le code.
- Roslynator.Analyzers : Offre une variété de règles de qualité et d'améliorations pour le code C#, aidant à identifier des opportunités de refactorisation et d'optimisation.
Avantages des Analyseurs de Code :
- Amélioration de la Qualité : Ils aident à maintenir le code propre, lisible et exempt de problèmes courants.
- Prévention des Erreurs : Ils détectent les erreurs avant qu'elles ne soient exécutées, permettant au développeur de corriger les problèmes tôt dans le processus.
- Standardisation : Ils garantissent que tous les développeurs suivent les mêmes conventions et règles de style, améliorant la cohérence du code.
- Refactorisation Assistée : Ils facilitent la refactorisation du code en offrant des suggestions d'amélioration.
En activant les analyseurs de code, vous avez une méthode proactive pour améliorer la qualité de votre code et réduire le risque d'échecs en production.
Caché Distribué
Le cache distribué est une technique utilisée pour améliorer les performances et l'évolutivité des applications, en stockant les données fréquemment accédées dans une couche de cache externe à la base de données. Il permet aux instances de l'application de partager efficacement les données mises en cache, garantissant une haute disponibilité et une réduction du temps de réponse.
Si vous choisissez d'activer le cache distribué lors de la création de votre projet, Redis sera intégré à votre conteneur Aspire, offrant un système de cache à haute disponibilité.
Avantages du Cache Distribué :
- Amélioration des Performances : Réduit le temps de réponse des demandes en minimisant l'accès à la base de données.
- Scalabilité : Permet de faire évoluer l'application horizontalement, car le cache peut être accédé par différentes instances de manière transparente.
- Haute Disponibilité : Avec Redis, le cache reste disponible même en cas de défaillance, offrant une solution robuste pour les systèmes distribués.
- Réduction des Coûts : Réduit la charge sur la base de données et sur le système, diminuant ainsi le besoin de traitement pour les demandes répétitives.
En activant le cache distribué, vous améliorez considérablement les performances de votre application, garantissant une réponse plus rapide aux utilisateurs et réduisant la charge sur les systèmes backend.
Communication Asynchrone
La communication asynchrone est une approche qui permet aux systèmes et aux composants de communiquer de manière non bloquante, c'est-à -dire sans que l'envoi ou la réception de données n'interrompe le traitement des autres tâches. Cela est particulièrement utile dans les systèmes distribués et en cas de forte charge, où l'efficacité et la résilience sont essentielles.
Si vous choisissez d'activer la communication asynchrone, RabbitMQ sera intégré à votre projet, et MassTransit sera configuré pour faciliter l'utilisation de cette communication asynchrone dans votre application.
Avantages de la Communication Asynchrone :
- Amélioration des Performances : Permet d'exécuter les opérations en parallèle sans bloquer le flux d'exécution du système.
- Scalabilité : Facilite l'évolutivité du système, lui permettant de traiter de grands volumes de données et des utilisateurs simultanés sans perdre de performance.
- Résilience : En cas de défaillance temporaire, la communication asynchrone permet de retraiter ou de stocker les messages pour un traitement ultérieur.
- Découplage : Les systèmes peuvent être conçus pour communiquer sans dépendre directement de réponses immédiates, offrant ainsi plus de flexibilité et d'organisation.
L'intégration avec RabbitMQ et l'utilisation de MassTransit rendent la communication entre les composants plus efficace et résiliente, contribuant ainsi à garantir l'évolutivité et la flexibilité de votre application.
Étapes Suivantes
Maintenant que vous avez créé votre projet .NET avec Lino, ouvrez-le dans votre éditeur de code préféré. Vous pouvez utiliser Visual Studio, Visual Studio Code ou tout autre IDE de votre choix.
Une fois le projet ouvert, vous pouvez commencer à ajouter et configurer les services qui composent votre application. C'est la prochaine étape du flux de développement.
Dans la prochaine section, nous vous montrerons comment créer et configurer ces services dans votre nouveau projet, le préparant à se développer de manière organisée et évolutive en fonction des besoins de votre application.
Création et gestion des services
Après la création du projet, l'étape suivante consiste à ajouter des services. Lino offre un moyen simple et intuitif de créer des services, qui peuvent être utilisés dans des systèmes monolithiques ou des architectures de microservices.
Pour créer un nouveau service, utilisez la commande suivante :
lino service new
Lors de l'exécution, le CLI demandera les informations suivantes :
- Namespace du service : Définit le nom et le namespace du service.
- Nom d'affichage : Nom convivial affiché dans les interfaces.
- Type de service : Choisissez entre Simple ou Modulaire.
- Base de données : Choisissez entre PostgreSQL ou SQL Server.
Si le type de service choisi est Simple, les informations suivantes seront également demandées :
- Style architectural : Actuellement, seule la Clean Architecture est disponible.
- Utiliser des Strongly Typed ID ? Choisissez entre Oui ou Non.
Types de service
Service simple : Un service simple a une structure plus légère, adaptée aux systèmes monolithiques ou aux projets de microservices où chaque service a une responsabilité indépendante.
Service modulaire : Pour les systèmes plus grands, nécessitant une plus grande organisation et évolutivité, vous pouvez opter pour un service modulaire. Ce type permet de diviser le service en modules plus petits et plus spécifiques, facilitant la maintenance et l'expansion du système.
Que le service soit simple ou modulaire, la base de données sera unique pour chaque service. L'architecture et l'utilisation des Strongly Typed IDs s'appliquent aux services simples. Pour les services modulaires, cette décision sera prise au niveau de chaque module créé au sein du service.
La structure de Lino est flexible, permettant de créer des services simples et modulaires au sein du même projet.
Style architectural
Lino applique déjà la Clean Architecture à tous les services. Cela garantit que votre application suit une architecture bien structurée, favorisant la séparation des responsabilités et facilitant la maintenance et l'évolutivité.
Avantages de la Clean Architecture :
- Découplage : La logique métier est indépendante des détails techniques, offrant ainsi une plus grande flexibilité et testabilité.
- Maintenabilité : Étant donné que les couches sont bien séparées, il est plus facile d'apporter des modifications sans affecter d'autres parties du système.
- Testabilité : La séparation des préoccupations facilite la création de tests unitaires et d'intégration pour chaque couche de manière indépendante.
- Scalabilité : Le projet est plus facile à faire évoluer, car les composants peuvent être modifiés ou remplacés sans affecter la logique métier.
Si vous choisissez de créer un service simple, en utilisant l'implémentation de Clean Architecture, le projet sera généré avec la structure suivante :
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 vous choisissez un service modulaire, le projet adoptera la structure suivante, permettant l'ajout de nouveaux modules de manière flexible et organisée tout au long du développement du service :
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
Le Strongly Typed ID est une approche visant à améliorer la sécurité et la clarté du code en garantissant que les types d'identifiants (ID) sont plus spécifiques et fortement typés, évitant l'utilisation de types génériques tels que int
ou guid
pour représenter des entités uniques.
Avec le Strongly Typed ID, au lieu d'utiliser des types génériques tels qu'un entier pour représenter un identifiant d'utilisateur, vous créeriez un type spécifique pour l'ID de l'utilisateur. Cela permet d'éviter des erreurs courantes, comme l'utilisation incorrecte d'ID de types différents dans des contextes inappropriés.
Avantages de l'utilisation des Strongly Typed IDs :
- Sécurité des types : Garantit que les ID sont utilisés correctement, en évitant la confusion entre différents types d'identifiants, tels que les ID d'utilisateurs et les ID de produits.
- Clarté : Le code devient plus clair, car chaque type d'ID est explicitement représenté par une classe spécifique.
- Facilité de refactorisation : Si le type d'identifiant doit changer, vous modifiez uniquement le type d'ID spécifique et le reste du code reste sécurisé.
- Évite les erreurs : Réduit le risque de bugs liés à une mauvaise utilisation des identifiants génériques dans des contextes incorrects.
Création et gestion des modules
Après avoir créé un service modulaire, l'étape suivante consiste à y ajouter des modules. Les modules permettent d'organiser la logique métier de manière indépendante, apportant ainsi plus de scalabilité et d'organisation au système.
Pour créer un nouveau module, utilisez la commande suivante :
lino module new
Lors de l'exécution, l'outil CLI demandera les informations suivantes :
- Service : Définit à quel service le nouveau module sera ajouté.
- Namespace du module : Définit le nom et le namespace du module.
- Nom d'affichage : Nom convivial affiché dans les interfaces.
- Style architectural : Actuellement, seul Clean Architecture est disponible.
- Utiliser une ID fortement typée ? Choisissez entre Oui ou Non.
À la fin, Lino générera le nouveau module en préservant la structure de votre service modulaire :
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
Structure de la base de données
Il est important de souligner que la base de données est liée au service. Dans un service modulaire, chaque module est représenté par son propre schéma dans la base de données associée. Cette approche permet l'isolation et l'organisation, sans avoir besoin de créer plusieurs bases de données distinctes.
À propos de l'indépendance entre les modules
Tout comme les services n'ont pas de dépendances directes entre eux, les modules sont également créés comme des projets indépendants au sein du service.
Avantages de cette découplage :
- Isolation : Chaque module peut évoluer de manière indépendante, facilitant ainsi la maintenance et l'évolution continue.
- Organisation : L'application devient véritablement modulaire, respectant les limites du contexte (Bounded Contexts) et favorisant de bonnes pratiques d'architecture logicielle.
- Flexibilité : Permet d'ajouter, de supprimer ou de refactoriser des modules sans affecter directement les autres modules du service.
- Facilité de tests : Chaque module peut être testé de manière isolée, augmentant ainsi la fiabilité et la qualité du système.
Ainsi, nous avons terminé le processus de création des modules. Dans les prochains sujets, nous verrons comment structurer les éléments internes d'un module, tels que les entités, les objets de valeur, les énumérations, les commandes, les requêtes, les API, les intégrations et bien plus encore.