Définition des cas d'utilisation de l'application
Dans cette section, nous allons explorer comment dĂ©finir les cas dâutilisation de votre application Ă lâaide de Lino CLI. Les cas dâutilisation reprĂ©sentent des interactions spĂ©cifiques entre les utilisateurs ou les systĂšmes externes et lâapplication, en encapsulant les rĂšgles mĂ©tier et en promouvant une architecture orientĂ©e domaine. Nous aborderons la sĂ©paration des opĂ©rations de lecture et dâĂ©criture Ă travers le pattern CQRS, ainsi que la standardisation des rĂ©ponses en utilisant le Result Pattern.
Le pattern CQRS (Command Query Responsibility Segregation) propose de sĂ©parer les opĂ©rations qui modifient lâĂ©tat de lâapplication (Commands) de celles qui ne font que consulter les donnĂ©es (Queries). Cette approche permet dâoptimiser chaque type dâopĂ©ration de maniĂšre indĂ©pendante, amĂ©liorant ainsi lâĂ©volutivitĂ©, les performances et la maintenabilitĂ© du systĂšme.
Le Result Pattern est utilisĂ© pour standardiser le retour des opĂ©rations, en encapsulant des informations sur le succĂšs ou lâĂ©chec, les messages dâerreur et les donnĂ©es rĂ©sultantes. Cela facilite la gestion cohĂ©rente des rĂ©ponses Ă travers les diffĂ©rentes couches de lâapplication.
Nous verrons comment sont structurés les fichiers de Commands et de Queries, la validation des données, comment la logique métier est appliquée dans les Handlers, et comment retourner des résultats de maniÚre standardisée. Tout cela est réalisé grùce à la génération automatique de ces composants via le CLI de Lino.
Remarque : Bien que cela ne soit pas obligatoire, Lino propose actuellement deux options pour appliquer le pattern CQRS dans la couche applicative : en utilisant le pattern Mediator via la bibliothĂšque MediatR (de Jimmy Bogard) ou la bibliothĂšque Mediator (de Martin Othamar).
Vue dâensemble des cas dâutilisation
Un cas dâutilisation reprĂ©sente une interaction complĂšte entre des utilisateurs ou des systĂšmes externes et lâapplication, dĂ©crivant des scĂ©narios mĂ©tier spĂ©cifiques. Dans Lino, chaque cas dâutilisation est divisĂ© en :
- Command : reprĂ©sente lâintention de modifier lâĂ©tat du systĂšme (crĂ©er, mettre Ă jour, supprimer, etc.).
- Query : reprĂ©sente lâintention de consulter des donnĂ©es sans modifier lâĂ©tat du domaine.
Cette sĂ©paration favorise la clartĂ© du code, facilite les tests, permet une scalabilitĂ© indĂ©pendante pour la lecture et lâĂ©criture, et sâaligne sur les principes de lâarchitecture propre et les bonnes pratiques du Domain-Driven Design (DDD).
Commandes
Une Commande est un message immuable qui contient uniquement les donnĂ©es nĂ©cessaires pour exĂ©cuter une action modifiant lâĂ©tat du systĂšme (par exemple, CreateInvoice, DeactivateUser).
Elle doit contenir uniquement les propriĂ©tĂ©s reprĂ©sentant les informations essentielles Ă lâexĂ©cution de lâopĂ©ration.
CaractĂ©ristiques dâune Commande
- Immutabilité : implémentée comme un
recordou une classe avec uniquement desget, sans setters publics. - Nom Ă lâimpĂ©ratif : reflĂšte lâaction qui sera exĂ©cutĂ©e, par exemple
CreateOrder,UpdateCustomerAddress. - DonnĂ©es minimales : contient uniquement les champs nĂ©cessaires Ă lâexĂ©cution de lâopĂ©ration, sans retourner de grandes quantitĂ©s de donnĂ©es.
- Validation isolĂ©e : chaque Commande possĂšde ses propres rĂšgles de validation, garantissant sa cohĂ©rence avant dâatteindre le gestionnaire (Handler).
Validateurs de Commande
Les Validateurs de Commande sâassurent que la Commande est bien formĂ©e et respecte les exigences mĂ©tier avant dâĂȘtre envoyĂ©e au gestionnaire. Dans Lino, nous utilisons la bibliothĂšque FluentValidation pour implĂ©menter ces validations, car elle est largement adoptĂ©e dans les projets .NET et offre une API Fluent pour la crĂ©ation des rĂšgles.
RĂšgles communes de validation
NotEmpty,NotNullpour les champs obligatoires.InclusiveBetweenpour les plages numériques (ex. : valeurs monétaires, quantités minimum/maximum).MaximumLengthetMinimumLengthpour la longueur des chaßnes de caractÚres.RuleForEachpour la validation des éléments dans les collections (List<T>).Mustpour les rÚgles personnalisées (ex. : format des documents, validation des dates).
Gestionnaires de Commande
Le Gestionnaire de Commande est responsable dâexĂ©cuter la logique mĂ©tier associĂ©e Ă cette Commande. Il orchestre les repositories, les unitĂ©s de travail (IUnitOfWork), les services auxiliaires et dĂ©clenche les Ă©vĂ©nements de domaine si nĂ©cessaire.
ModĂšle dâimplĂ©mentation dâun gestionnaire
- Recevoir les dépendances (repositories, services externes, UnitOfWork) via injection de dépendances.
- Mapper et instancier les entités du domaine, garantissant la cohérence initiale.
- Appliquer les rĂšgles mĂ©tier (validations supplĂ©mentaires, calcul des valeurs, dĂ©clenchement dâĂ©vĂ©nements de domaine).
- Persister les modifications via
IUnitOfWorkou des repositories directs. - Retourner un Résultat de Commande, indiquant succÚs ou échec (
Result<T>).
Résultats de Commande et Result Pattern
Le RĂ©sultat de Commande doit ĂȘtre un DTO simple contenant uniquement les donnĂ©es minimales nĂ©cessaires pour que lâappelant (par exemple, une API ou un front-end) puisse continuer. Il inclut gĂ©nĂ©ralement lâidentifiant de lâentitĂ© créée ou mise Ă jour (Id) et, en cas dâĂ©chec, des informations standardisĂ©es sur lâerreur.
Pour les scĂ©narios oĂč la Commande peut Ă©chouer, nous utilisons le Result Pattern : une abstraction qui encapsule le rĂ©sultat dâune opĂ©ration, pouvant ĂȘtre un succĂšs ou un Ă©chec. En .NET, il est courant dâutiliser des types comme Result<T> (ou des bibliothĂšques similaires), qui :
- Permettent de définir une
Valueen cas de succĂšs (par exemple, un DTO simple). - En cas dâĂ©chec, stockent des codes ou messages standardisĂ©s (
Error), Ă©ventuellement avec des mĂ©tadonnĂ©es supplĂ©mentaires (codes HTTP, dĂ©tails de validation, etc.). - Facilitent lâunification du flux de gestion des erreurs Ă travers toute lâAPI, maintenant la cohĂ©rence entre les couches.
Créer une Commande avec le CLI
Lino simplifie la génération de tous les artefacts nécessaires pour une nouvelle Commande via la commande :
lino command new
Lors de lâexĂ©cution de cette commande, lâassistant interactif demandera :
- Service â Nom du service oĂč la Commande sera créée.
- Module â Dans les services modulaires, dĂ©finit le module cible.
- EntitĂ© â EntitĂ© de domaine liĂ©e Ă la Commande (optionnelle mais recommandĂ©e).
- Nom de la Commande â Nom final de la Commande (par exemple,
CreateOrder).
AprÚs confirmation, Lino créera automatiquement les fichiers :
CreateOrderCommand.csCreateOrderCommandValidator.csCreateOrderCommandHandler.csCreateOrderCommandResult.cs
Exemple de structure générée
Considérez la Commande CreatePerson. La structure générée ressemblera à :
MyApp/
âââ src/
âââ Services/
âââ MyService/
âââ Application/
âââ MyApp.MyService.Application.csproj
âââ UseCases/
âââ People/
âââ Commands/
â âââ CreatePerson/
â âââ CreatePersonCommand.cs
â âââ CreatePersonCommandValidator.cs
â âââ CreatePersonCommandHandler.cs
â âââ CreatePersonCommandResult.cs
âââ Queries/
âââ ...
RequĂȘtes
Une requĂȘte reprĂ©sente lâintention dâobtenir des donnĂ©es sans modifier lâĂ©tat du domaine. Les requĂȘtes sont conçues pour ĂȘtre efficaces en lecture, en retournant uniquement les champs nĂ©cessaires, sans charger des entitĂ©s complĂštes lorsquâelles ne sont pas demandĂ©es.
CaractĂ©ristiques dâune RequĂȘte
- Immuable â comme les Commandes, une RequĂȘte ne doit pas ĂȘtre modifiĂ©e aprĂšs sa crĂ©ation.
- Nom descriptif â reflĂšte les informations recherchĂ©es, par exemple :
GetCustomerById,ListOrdersByDateRange. - Filtres et Pagination â peut recevoir des paramĂštres pour appliquer des recherches spĂ©cifiques (dates, statut, page, tri).
- Projection â doit retourner un DTO ou un modĂšle de vue contenant uniquement les champs nĂ©cessaires, Ă©vitant le chargement complet des objets de domaine.
Validateurs de RequĂȘte
Les validateurs de requĂȘte ont pour responsabilitĂ© de valider les paramĂštres dâentrĂ©e, tels que les filtres, les valeurs de pagination (page, pageSize) et les rĂšgles de sĂ©curitĂ© (autorisations utilisateur, visibilitĂ© des donnĂ©es). Ils sont Ă©galement implĂ©mentĂ©s avec FluentValidation.
RĂšgles de Validation Courantes pour les RequĂȘtes
GreaterThanOrEqualToouLessThanOrEqualTopour les filtres par plage (ex. : dates).Lengthpour les filtres textuels (ex. : recherche par nom ou e-mail).InclusiveBetweenpour les paramĂštres de pagination (ex. : nombre minimum/maximum dâĂ©lĂ©ments par page).
Gestionnaires de RequĂȘte
Le gestionnaire de requĂȘte est responsable dâinterroger les dĂ©pĂŽts ou le contexte de base de donnĂ©es et de retourner des projections optimisĂ©es, en Ă©vitant le chargement complet des entitĂ©s du domaine.
Dans Lino, il est recommandĂ© dâutiliser des projections avec des mĂ©thodes comme .Select() pour mapper directement les donnĂ©es dans le format attendu du DTO, garantissant ainsi efficacitĂ© et meilleures performances.
RĂ©sultats de RequĂȘte
Dans Lino, les rĂ©sultats des requĂȘtes sont toujours reprĂ©sentĂ©s par des records nommĂ©s avec le suffixe QueryResult.
Cette convention sâapplique quel que soit le type de rĂ©ponse â quâil sâagisse dâune liste dâĂ©lĂ©ments (avec ou sans pagination) ou dâun Ă©lĂ©ment unique dĂ©taillĂ©.
CrĂ©er une RequĂȘte avec le CLI
Comme pour les Commandes, Lino fournit la commande suivante :
lino query new
Lâassistant vous demandera :
- Service â le service dans lequel la requĂȘte sera créée.
- Module â si applicable, dĂ©finit le module du domaine.
- EntitĂ© â lâentitĂ© ou lâagrĂ©gat auquel la requĂȘte est associĂ©e (facultatif).
- Nom de la RequĂȘte â par exemple :
GetOrderByIdouListProductsByCategory.
Lino générera automatiquement :
GetOrderByIdQuery.csGetOrderByIdQueryValidator.csGetOrderByIdQueryHandler.csGetOrderByIdQueryResult.cs
Exemple de Structure GĂ©nĂ©rĂ©e pour les RequĂȘtes
MyApp/
âââ src/
âââ Services/
âââ MyService/
âââ Application/
âââ MyApp.MyService.Application.csproj
âââ UseCases/
âââ Orders/
âââ Commands/
| âââ ...
âââ Queries/
âââ GetOrderById/
âââ GetOrderByIdQuery.cs
âââ GetOrderByIdQueryValidator.cs
âââ GetOrderByIdQueryHandler.cs
âââ GetOrderByIdQueryResult.cs
Conclusion
AprĂšs avoir compris comment dĂ©finir et structurer les Use Cases (Commands et Queries) dans Lino, vous ĂȘtes prĂȘt Ă crĂ©er des scĂ©narios mĂ©tier robustes et Ă©volutifs, en segmentant clairement la logique dâĂ©criture et de lecture. Utilisez le CLI pour accĂ©lĂ©rer le dĂ©veloppement, mais pensez toujours Ă revoir et ajuster les implĂ©mentations selon les besoins spĂ©cifiques de votre domaine.
Ensuite, explorez comment gĂ©rer la persistance, les Ă©vĂ©nements de domaine et les services dâinfrastructure pour composer toute lâarchitecture de votre application.
