Nos logiciels reposent sur une base de données et une demande ne peut pas être conçue sans se projeter sur les données qu’elle va manipuler. Les jeux de données à mettre en place se décident au moment de rédiger le ticket, pas au moment de développer.
C’est le pendant des cas de test : les cas disent ce qu’on attend, le jeu de données fournit la matière qui permet de le vérifier.
Les trois natures que nous maintenons
- minimal : les données sans lesquelles le logiciel ne fonctionne pas, initialisées à l’installation de n’importe quel environnement, production comprise. Les profils administrateurs, les référentiels, le paramétrage de base.
- fake : des données factices que nous chargeons en une commande en développement ou sur un environnement de test, pour se projeter dans l’utilisation réelle du logiciel.
- volume : un nombre de données aléatoires à charger pour éprouver ce que le fake ne montre pas, la tenue des listes et les temps de réponse.
Les trois cohabitent sur un projet et n’ont pas le même cycle de vie. Le minimal suit le logiciel en production, le fake s’enrichit à chaque fonctionnalité, le volume se charge à la demande.
Le jeu de données se conçoit depuis les règles métier
Concevoir un jeu de données, ce n’est pas remplir des tables : c’est relire les règles de gestion de la demande en se demandant quelles situations doivent exister pour qu’on puisse les observer.
Prenons le développement de statistiques de facturation. La lecture de la demande impose la liste suivante :
- une facture suppose un client, et ce client a des contrats associés
- les paramètres de facturation peuvent être surchargés par client : il faut donc au moins un client sans surcharge et un client avec
- la facturation des contrats couvre quatre types de prestation : forfait, nouveau contrat, renégociation et suivi
- les statistiques se consultent par année et par mois : il faut plusieurs factures réparties dans le temps pour vérifier les calculs de montants regroupés
Cette liste n’est pas une annexe technique du ticket, c’est une relecture de la conception. Une donnée qu’on ne sait pas produire est presque toujours une règle de gestion qui n’a pas été tranchée.
Monter ces données à la main à chaque installation est une source de perte de temps et d’erreurs considérable, et elle se paye à chaque intervention sur le projet, pas seulement la première fois. Le jeu de données est programmé et versionné avec le code, et il s’enrichit au fil des développements et des corrections.
Le fake pour être efficace
Le fake sert à démarrer le projet avec un logiciel déjà utilisable, sans avoir à cliquer une demi-journée pour créer de quoi travailler. Le gain est triple :
- la personne qui développe retrouve un environnement complet à chaque installation et à chaque mise à jour
- la personne en charge de la validation en intégration observe le comportement sur des données que toute l’équipe connaît
- un cas de test qui suppose une situation particulière trouve dans le fake la donnée qui le rend reproductible, au lieu de dépendre de ce que quelqu’un a saisi un jour
C’est ce dernier point qui compte le plus dans la durée : un test qui repose sur une donnée saisie à la main finit par tomber en panne sans que personne ne sache pourquoi.
Le volume, pour ce que le fake ne montre pas
Le volume vient en complément du fake. Il sert aux fonctionnalités qui ne se jugent qu’à l’échelle : la pagination d’une liste, un export, un écran de recherche, et plus généralement la performance de ce que nous développons.
Le volume à charger doit correspondre aux objectifs chiffrés avec le client en début de projet, ou les dépasser légèrement. En dessous, nous validons une situation qui n’arrivera jamais.
Charger du volume consomme du temps et des ressources serveur. Il ne se charge donc pas par défaut, et jamais dans la CI, où il rallongerait chaque build sans rien apprendre.
La mise en oeuvre sur nos projets Symfony
Nous chargeons les jeux de données avec theofidry/alice-data-fixtures, qui s’appuie sur Nelmio Alice pour la déclaration en YAML et sur FakerPHP pour la génération des valeurs.
Le jeu de données fake est déclaré dans le répertoire fixtures/fake du projet, une entité par fichier. Voici la
création d’une entité, avec les références vers d’autres fixtures et le tirage aléatoire de certaines valeurs :
App\Entity\Client\Prospect:
prospect_base_template:
etablissement: '@etablissement_siege<current()>'
type: !php/enum App\Enum\Client\ProspectTypeEnum::BASE
commercials: [ '@commercial_miclaud_1', '@commercial_miclaud_3' ]
lastCallStatus: <randomElement([!php/enum App\Enum\Client\ProspectCallStatusEnum::STANDARD_NOMINATIF, !php/enum App\Enum\Client\ProspectCallStatusEnum::BARRAGE])>
nextRdvAt: <dateTimeBetween('+5 days', '+20 days')>
priority: 10
importFile: '@campaign_prospect_import_file_<randomElement([1, 2])>'
comment: "commentaire\rcommentaire"
projet: "projet\rprojet"
Le volume réutilise les mêmes templates, en multipliant les instances et en piochant dans les références déjà chargées. Ici, cent contrats rattachés aléatoirement aux clients, domaines et fournisseurs existants :
App\Entity\Contrat:
contrat_{1..100} (extends contrat_template):
client: '@client*'
domaine: '@domaine*'
fournisseur: '@fournisseur*'
Un jeu de données qui se lit comme celui-ci a un effet secondaire utile : il documente le modèle de données du projet mieux que n’importe quel schéma, parce qu’il montre des cas réels et qu’il ne peut pas se périmer sans que le chargement ne casse.