Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Xamarin.Forms, Validation des données et Mvvm–Partie 1

Comment valider les données ? Quel retour visuel donner à l’utilisateur ? Le tout en respectant Mvvm ? Tout un programme ! A suivre tout de suite sur votre blog préféré…

Validation des données

Un besoin fondamental

Valider les données n’est pas compliqué en soit mais c’est une obligation connue depuis toujours. On dispose déjà depuis longtemps de découpages des applications en couche métier (BOL, Business Object Layer), couche données (DAL, Data Access Layer), Services, même micro-services, etc. Et toutes ces couches sont capables de valider les données. La couche BOL peut en fonction de règles métier interdire certaines valeurs, la couche DAL peut elle filtrer les valeurs interdites (NULL non accepté pour un champ par exemple), la base de données elle-même peut refuser des clés étrangères non renseignées, etc...

Cette façon de découper une application en couches ayant des responsabilités précises peut toutefois amener à un éclatement des règles de validation. La base de données effectue des validations plutôt “défensives” visant à maintenir l’intégrité des données qu’elle stocke (un article sans référence n’est pas stockable). La couche BOL effectue des validations qui n’ont de sens que dans le cadre du métier (un véhicule de type moto ne peut avoir que deux roues), la couche DAL, intermédiaire, pose déjà le problème de savoir si ses validations n’empiètent pas sur le domaine du SGBD ou du BOL (un facture sans référence client peut relever de la protection de l’intégrité des données du SGBD ou bien avoir un sens fonctionnel particulier pour l’application par exemple pour servir de template pour les nouvelles factures). A vouloir trop bien faire on créée aussi une complexité difficile à gérer… Les tests ne sont pas centralisés, ils sont parfois redondants, et quand ils évoluent il n’évoluent pas identiquement dans tous les recoins de l’application laissant la porte ouverte à des bogues sournois difficiles à trouver, mais pas rares à rencontrer !

Valider les données est toujours très simple sauf exceptions. Techniquement tester un NULL, une valeur inférieure ou supérieure à une limite, etc, tout cela est du niveau débutant. Quelques fois les validations imposent des calculs, l’appel d’API externes, mais cela est plus rare et finalement guère plus complexe, juste plus lourd.

Valider n’est pas informer… et pourtant il le faut !

Mais le plus gros problème est de savoir où et comment ces validations sont faites et surtout quel retour l’utilisateur en aura. Car valider est une opération interne, encore faut-il qu’elle puisse être visible de l’opérateur (utilisateur) pour qu’il puisse corriger l’erreur, et voire mieux, ne pas la commettre !

Nous connaissons tous des logiciels programmés avec les pieds notamment sur le Web où il faut avoir saisi une page d’information puis valider pour se voir refuser cette validation avec un message du genre “les champs avec étoile ont des erreurs”. Et vas-y mon gars ! Retape toi la page à la recherche des fameuses étoiles souvent en corps 4 sous, dessus, à droite, à gauche du champs, faut chercher… Quant à la raison elle est parfois assez absconse.

Les programmeurs qui commettent de tels codes devraient être déchus du droit d’exercer…

Je pense que la plupart des sites de l’administration française au moins sont de ce type, mais pas que… donc on se garde bien de se moquer…

Comme on le comprend il ne suffit pas de se protéger en “validant” les données, encore faut-il “bien” les valider c’est à dire au bon moment et en faisant en sorte que cela soit le moins pénible pour l’utilisateur.

Lorsqu’en plus on doit respecter MVVM, c’est à dire découpler au maximum et rendre le code maintenable et testable automatiquement via du Unit Testing, cela peut compliquer légèrement la tâche du développeur. Mais c’est aussi pour cela qu’il est payé…

D’ailleurs l’avenir de l’informaticien se trouve dans les failles des IA : l’inventivité, la créativité, et une pensée globale, enrobante, que les IA de demain n’auront pas. Quant à celles qui seront douées de conscience, du sens artistique, d’une éthique, etc, on est toujours pour l’instant dans le domaine de la SF. De la SF pour les IA, mais une réalité pour le cerveau de l’humain !  L’informaticien qui fait son travail avec intérêt et passion est en quelque sorte déjà  une machine du futur !

Alors il se préoccupe de tout, il a de l’empathie pour les utilisateurs, il pressent leurs éventuelles frustrations et il évite la cognitive friction, il devance les difficultés à venir, les gomme, il est dès aujourd’hui et pour moins cher finalement, ce que la science arrivera peut-être à créer dans 50, 100 ans ou jamais. Il est cette machine du futur que j’évoquais. A lui de bien se servir de ses “super-pouvoirs” (et de savoir les vendre) !

Bien valider

Bien valider les données est donc à la croisée de plusieurs chemins, celui du fonctionnel, de la technique pure, du design, mais aussi d’une forme d’humanisme. Savoir se mettre à la place de l’utilisateur pour lui faciliter l’accès à une application est un acte d’amour vers l’autre ou au moins de l’empathie. Ceux qui détestent les utilisateurs, qui les critiquent sans cesse, ne sont pas de bons informaticiens. Ils oublient leur mission. Celle qu’une IA n’est pas prête de remplacer… Ceux-là seront les premiers à être remplacés, comme le furent les pupitreurs, les cobolistes et autres dinosaures du musée de l’informatique.

Bref, bien valider n’est pas qu’un boulot de codeur, c’est aussi un travail de design, de conception d’UI efficaces et vendeuses (voir ou revoir ma conférence aux Techdays “Concevoir des interfaces utilisateur efficaces et vendeuses”).

Comment valider les données ?

Par défaut les Xamarin.Forms n’offrent rien de spécial pour effectuer une validation de données, ni sur le plan du code, ni visuellement. Côté code on peut prendre le problème dans l’autre sens et se dire qu’en nous fournissant C# ils ont déjà fait le maximum… Et côté visuel en fournissant avec les Xamarin.Forms de nombreux moyens de personnaliser l’UI le boulot est fait là aussi.

En réalité Xamarin ne peut pas aller beaucoup plus loin, le reste nous incombe !

Et pour se plier à la réalité nous allons créer et mettre en place un système de validation…

Mécanisme de validation

La première chose à mettre en place est un mécanisme de validation suffisamment universel pour couvrir tous les besoins courants de validation, assez simple pour ne pas peser de trop sur le code et l’UI, mais assez complet pour simplifier la prise en compte visuelle de la validation (l’information à l’utilisateur).

On peut mettre en place de nombreux systèmes de ce genre en les adaptant au contexte de l’application, mais voici un schéma assez générique qui vous fournira une base de réflexion ouverte à toutes les améliorations que vous voulez :

image

(rappel : un clic sur l’image vous donne la version à 100 %)


Sur ce schéma on peut voir de nombreux acteurs qui sont :

  • Le contrôle Entry qui permet la saisie des données, données qui devront être validées et complétées par un retour visuel. On aurait pu choisir d’autres éléments d’UI mais le Entry est une sorte de base incontournable pour la saisie de données. Mais il n’est qu’un exemple, le principe présenté fonctionne avec d’autres contrôles.
  • Le ViewModel, pierre angulaire de MVVM, il aura forcément un rôle un jouer
  • SimpleObservableObject, classe servant à créer des classes filles supportant INPC (on peut utiliser toute autre classe à la place du moment qu’elle offre un support de INPC)
  • ValidatableObject<T> La classe qui permettra de créer des objets de validation, sujet même de l’article
  • Les règles de validation qui sont personnalisable pour chaque contrôle à valider.

L’astuce principale de ce “montage” est de substituer aux propriétés classiques exposées par le ViewModel des ValidatableObject<T>. C’est à dire que si la donnée est de type string, au lieu de proposer une propriété “public string NomDeFamille {get;} {set;}” on utilisera à la place une propriété “ValidatableObject<string> {get ….} {set …}”. Nous verrons le détail plus loin.

Pourquoi cette substitution ? Car la classe ValidatableObject<T> en plus de contenir la valeur (ici le nom de famille en string) va fournir les moyens de valider la donnée et de connaître le résultat de cette validation.

Retraçons maintenant la petite histoire racontée par le schéma ci-avant :

Un contrôle servant à saisir une donnée à valider, un Entry dans cet exemple, est databindé à une propriété du ViewModel. Cette propriété n’est pas exposée directement mais elle est encapsulée dans une instance de ValidatableObject<T>, T étant le type de la donnée (string, int…). C’est le ViewModel qui a la charge de créer cette instance à laquelle il fournit des règles de validation propres au champ considéré.

L’UI, via le contrôle, va obtenir l’état de la validation en interrogeant ce dernier depuis l’objet ValidatableObject<T> qui contient comme je le disais à la fois la valeur du champ, la donnée, mais aussi les outils pour le valider et des propriétés pour indiquer les erreurs éventuelles.

Les règles de validation sont des instances de classes supportant IValidationRule<T>. On écrit ces classes de telle façon à ce qu’elles valident une donnée de type T. Le mieux étant qu’une classe Règle ne valide qu’un seul aspect de la donnée. Par exemple une règle peut servir à tester si un string est Null ou vide. Si le champ doit en plus faire plus de 8 caractères on écrira une autre Règle acceptant le nombre de caractères dans son constructeur de telle façon à ce que cette règle puisse être réutiliser dans de nombreux contextes sans réécriture (principe DRY : Don’t Repeat Youself !).

Si un contrôle de saisie nécessite d’être validé par plusieurs règles elles seront ajoutées à l’objet ValidatableObject<T> qui gère une collection de règles.

Chaque Règle, lorsqu’elle est instanciée se voit fournir un message d’erreur à afficher. ValidatableObject<T> expose ainsi cette collection sous la forme d’une propriété ce qui permettra à l’UI de l’utiliser.

On comprend maintenant pourquoi ValidatableObject<T> se substitue au type de la donnée dans le ViewModel, cela permet à la View d’accéder à toutes ses propriétés. La propriété Value sera de type T, ce qui revient donc au même que de l’avoir ainsi déclarée directement. Mais depuis l’UI et sans violer MVVM il sera aussi possible d’accéder à la liste des erreurs éventuelles. Il sera même possible d’accéder à un flag IsValid sans cesse mis à jour indiquant si la donnée saisie est correcte. D’où l’intérêt de faire descendre ValidatableObject<T> d’une classe offrant le support de INPC.

On pourrait fort bien implémenter le support d’INPC directement. Mais puisque nous parlons dans un contexte MVVM nous savons que la plupart des toolkits de ce type offre un type de base, souvent utilisé pour créer les ViewModels. Dans mon exemple SimpleObservableObject est une classe “personnelle” afin de ne pas utiliser la classe de l’une ou de l’autre des librairies MVVM. Dans la pratique vous pouvez parfaitement utiliser une classe similaire déjà présente dans votre application ou bien celle fournie par le toolkit MVVM que vous allez utiliser.

Un peu de visuel !

Nous aussi nous avons besoin d’un retour visuel ! Et pour cela rien ne vaut une petite capture écran en Gif animé pour que vous compreniez ce que nous allons réaliser.

La capture ci-dessous montre :

  • La saisie d’un login qui ne peut être vide. Si c’est le cas le champ se souligne de rouge et un message d’erreur est affiché en dessous.
  • La saisie d’un mot de passe qui ne peut être vide mais qui aussi doit compter au moins 8 caractères. Les deux messages d’erreurs se succéderont (c’est un choix plutôt que d’afficher une liste disgracieuse c’est la première erreur qui est affichée. Au fur et à mesure que l’utilisateur corrigera il verra s’afficher la prochaine erreur et ainsi de suite jusqu’à ce que le champ soit ok).

Ca va aller assez vite pour éviter que le Gif ne soit trop gros, mais comme ça boucle vous pourrez saisir chaque étape tranquillement en attendant le prochain passage de la boucle …


Validation


L’animation ci-dessus est accompagnée d’un suivi de la souris, d’une barre de progression verte à droite (elle arrive tout en haut en fin de boucle) et au centre en bas de l’indication des touches clavier tapées. Cela grâce à l’excellent freeware ScreenToGif que je vous recommande chaudement au passage (il peut créer des vidéos au lieu de Gif, faire la capture de la webcam aussi, dispose de diverses options, bref c’est bien).

Conclusion déjà ?

Et oui, d’où les mots “Partie 1” dans le titre hein…

C’est un gros morceau cet article. Nous allons entrer dans les détails de la réalisation, des personnalisations du contrôle Entry via des Effects Xamarin.Forms etc.. Ca en fait du code et des explications…

Alors prenons une pause avant la partie 2 !

Donc.. donc…

…. Stay Tuned !!!

blog comments powered by Disqus