Un import peut se terminer sans erreur et laisser, pourtant, une partie des données de côté. C'est le scénario le plus trompeur : l'interface affiche « terminé », le processus s'arrête avec un code de sortie à zéro... et, quelque part entre le fichier et la base, des enregistrements n'ont jamais été écrits. Le problème ne se manifeste pas forcément par une erreur technique. Il apparaît plutôt après coup : un dossier introuvable, une commande qui n'est jamais arrivée, une information qui « n'a jamais existé ».
Ce cas vient souvent d'un parseur construit à partir d'un seul exemple. Renommer une colonne, laisser une cellule vide, ou changer légèrement la structure d'une section suffit à faire dévier une ligne vers une branche que le programme ignore. Le traitement continue. Et le bilan de succès ne mesure que la progression du programme, pas l'intégrité du résultat.
Si vous voulez éviter cette fausse réussite, traitez la perte silencieuse comme un défaut de conception. Voici comment réconcilier les volumes, rendre les rejets visibles, choisir un mode strict (ou une quarantaine bien cadrée), et vérifier qu'un import préserve bien chaque partie de sa source.
Pourquoi un import peut réussir tout en perdant des données
Imaginons un import ponctuel d'un tableur vers une application métier. Le programme lit chaque ligne, transforme les colonnes en enregistrements internes, puis écrit ces enregistrements dans une base. Sur le papier, c'est « simple » : lire, convertir, enregistrer.
Le risque arrive quand une ligne ne correspond pas exactement à l'exemple qui a servi à concevoir le parseur. L'intitulé d'une colonne a changé. Une cellule est vide. Un champ optionnel est présent dans une section mais pas dans une autre. Ou la donnée est imbriquée autrement. Dans ce moment-là , le code doit décider quoi faire. Et s'il choisit de « passer » sans produire de rejet explicite, le traitement continue - et peut ressortir avec un bilan très propre.
« Aucune erreur » ne veut pas dire « aucune perte »
Un code de sortie à zéro indique généralement que le programme est allé au bout sans erreur non gérée. Mais ça ne prouve pas que toutes les lignes ont été traitées, ni que toutes les valeurs ont été conservées.
Le signal observé ne répond pas à la question métier. Le programme dit : « je n'ai pas crashé ». La question métier demande : « les données attendues sont-elles dans la destination ? ». Et un import peut répondre oui à la première, non à la seconde.
Dans un exemple concret, un fichier contient 1 200 lignes. Le programme en accepte 800, ignore 400 parce qu'elles ne correspondent pas à la structure attendue, puis termine normalement. Si le rapport ne mentionne que « import terminé, zéro erreur », personne n'a de raison évidente de soupçonner que 400 lignes ont été avalées.
Ce défaut est d'autant plus vicieux que les lignes conservées peuvent être impeccables. Vérifier quelques enregistrements « qui ont l'air bons » rassure vite. Mais ça ne révèle pas forcément qu'une section entière du fichier a été oubliée.
Le problème dépasse les fichiers tableurs
La mĂŞme logique se retrouve ailleurs :
- un client d'API garde les champs qu'il reconnaît et ignore le reste ;
- un script de migration saute une table dont il ne connaît pas le schéma ;
- une étape de normalisation filtre des valeurs « hors format », puis ne compte que ce qui reste ;
- un traitement par lot écarte les messages mal formés, sans garder leur trace.
Dans tous ces cas, le traitement peut « fonctionner » au sens informatique, tout en donnant une image incomplète de ce qui est sorti. La vraie question n'est pas seulement « le traitement a-t-il planté ? » mais « qu'est-ce qu'il est arrivé à chaque élément d'entrée ? ».
C'est aussi une règle utile pour la validation des données : toute transformation qui peut rejeter ou modifier des éléments doit rendre ces décisions observables. Sinon, la qualité du résultat repose sur une hypothèse non vérifiée : la source reste toujours proche de l'exemple de départ.
Pourquoi un agent choisit parfois de ne rien signaler
Un agent de programmation produit du code à partir d'une demande, d'un contexte et souvent d'un exemple. Si l'exemple est « régulier », il devient facile de construire un chemin nominal : lire les colonnes connues, créer l'objet attendu, l'enregistrer. Les variations absentes du contexte ne rentrent pas naturellement dans la solution.
Ça ne veut pas dire que l'agent « décide » de perdre des données. Le code reflète surtout une définition incomplète du succès. Si la consigne dit simplement « convertis ce fichier » sans préciser ce que le programme doit faire des lignes inconnues, il peut privilégier la continuité d'exécution plutôt que la visibilité des écarts.
La tolérance devient dangereuse sans comptabilité
Continuer malgré une ligne invalide peut être la bonne option. En traitement massif, arrêter un lot entier pour un cas douteux peut coûter cher. Mais, dans un import ponctuel qui alimente une base de production, accepter une perte silencieuse est souvent beaucoup plus risqué.
La tolérance n'est donc pas le problème. Le problème, c'est l'absence de contrepartie : compter les rejets, conserver une référence, et expliquer pourquoi une ligne n'a pas été acceptée. Sans cette comptabilité, « ne pas bloquer » finit par vouloir dire « ne pas savoir ».
En pratique, on voit souvent une branche du type « si la ligne ne correspond pas, passer à la suivante ». Elle ressemble à une mesure de prudence : pas d'arrêt brutal. Mais si elle n'incrémente aucun compteur et ne produit aucun rapport de rejet, l'anomalie devient invisible.
Pour bien cadrer une tâche confiée à un agent, formulez des règles explicites :
- préciser le nombre de lignes attendu (ou la façon de le calculer) ;
- définir les colonnes obligatoires et les types acceptés ;
- décider si une ligne invalide doit arrêter le traitement ou être mise en quarantaine ;
- exiger un bilan des lignes lues, acceptées, rejetées et échouées ;
- demander que les clés et colonnes inconnues soient signalées.
Cette précision n'est pas de la bureaucratie. Elle réduit l'espace d'interprétation et transforme une demande vague (« importe ce fichier ») en contrat vérifiable.
Vérifier le « chemin heureux » ne suffit pas
Un test basé uniquement sur l'exemple fourni prouve que le cas prévu fonctionne. Il ne dit rien sur les autres sections du fichier, les champs absents, ni les valeurs dont le type varie.
Le plus raisonnable est de comparer plusieurs lignes représentatives : une par section, ou par variante de format - pas une ligne choisie uniquement parce qu'elle est simple. L'objectif n'est pas de tester chaque ligne « à la main », mais de vérifier les différentes formes que la source peut prendre.
Cette idée rejoint les tests automatisés : un test utile couvre les frontières du contrat, pas seulement son centre. Si une section du fichier possède des colonnes spécifiques, elle mérite au minimum un exemple de test. Sinon, elle risque de rester hors du champ de validation et de disparaître sans bruit.
Les contrĂ´les qui rendent les pertes visibles
Il n'y a pas un seul réglage magique qui garantit l'intégrité d'un import. En revanche, quelques contrôles complémentaires rendent les pertes beaucoup plus difficiles à masquer. Le niveau de rigueur dépend du coût d'une donnée absente, mais le bilan quantitatif et la traçabilité des rejets devraient être présents dans presque tous les contextes de données.
Réconcilier les volumes de bout en bout
Comptez : lignes source, lignes acceptées, lignes rejetées et erreurs techniques. Le rapport doit permettre de suivre le parcours de chaque ligne, pas seulement d'annoncer que le programme a « fini ».
Une réconciliation minimale peut suivre cette règle :
lignes lues = lignes acceptées + lignes rejetées + lignes en erreur
Cette égalité n'a de valeur que si les catégories sont définies sans ambiguïté. Par exemple, une ligne rejetée après validation ne doit pas aussi compter comme une erreur d'écriture. Et si une ligne peut produire plusieurs enregistrements, il faut distinguer le nombre de lignes source du nombre d'objets créés.
Pour un import de 1 200 lignes, un bilan exploitable pourrait ressembler à : 1 200 lues, 1 160 acceptées, 35 rejetées (colonne obligatoire manquante) et 5 en erreur lors de l'écriture. Le traitement peut continuer, mais on ne devrait pas le déclarer « parfaitement réussi » sans mentionner ces écarts.
Le seuil de succès relève ensuite d'une décision métier. Pour une migration de données financières, la politique peut imposer zéro rejet avant validation. Pour un flux tolérant aux erreurs, un taux de rejet limité peut être acceptable si les éléments concernés sont récupérables et attribuables. Dans tous les cas, le seuil doit être explicite : il ne doit pas être déduit du fait que le processus s'est terminé.
Choisir entre mode strict et mise en quarantaine
En mode strict, le parseur refuse toute entrée qui ne respecte pas le contrat : en-tête inconnu, colonne obligatoire absente, type incohérent. C'est souvent le meilleur choix pour un import ponctuel ou une migration où la complétude prime. L'échec précoce évite de découvrir après coup qu'une partie du fichier n'a pas été prise en compte.
Le mode strict a toutefois un coût : une anomalie isolée peut bloquer tout le lot. Si le traitement doit continuer, la quarantaine est généralement une alternative plus maîtrisée. La ligne rejetée est conservée à part, avec une raison, un numéro de ligne (ou un identifiant stable), et idéalement une référence vers le fichier source.
La règle pratique est simple : soit le traitement s'arrête clairement, soit il continue avec un registre de rejets complet. Ignorer une ligne sans trace n'est pas une troisième voie acceptable.
Les rejets peuvent contenir des données personnelles ou sensibles. Dans un contexte français et européen, le fichier de rejet doit respecter les exigences de sécurité et de conservation : accès limité, durée définie, contenu minimisé et suppression maîtrisée. Un journal utile n'a pas besoin de recopier toute une « copie » du dossier ; un identifiant et un motif peuvent suffire.
Surveiller les champs et colonnes inconnus
Un élément inconnu révèle un écart entre ce que le programme attend et ce que la source contient. Le supprimer sans le signaler revient à jeter un indice.
Pour un tableur, le contrôle porte notamment sur les en-têtes inattendus, les colonnes obligatoires absentes et les valeurs dont le type ne correspond pas à ce qui est attendu. Pour une réponse d'API, il peut s'agir de clés supplémentaires ou d'une structure imbriquée nouvelle. Selon le niveau de compatibilité recherché, une clé inconnue peut être bloquante ou simplement signalée. Mais dans tous les cas, la politique doit être documentée et testée.
Un rapport structuré vaut mieux qu'un message « ça a l'air bon ». Il peut inclure un identifiant de ligne, le champ concerné, le type d'écart et le statut de traitement. Et évitez d'y coller des valeurs sensibles sans nécessité : l'objectif est de diagnostiquer, pas de dupliquer.
Tester au moins une ligne de chaque variante
Avant d'accepter un import, prenez un échantillon de chaque section (ou forme distincte) et vérifiez son résultat dans la destination. Comparez les champs attendus, y compris les champs optionnels, les valeurs vides et les conversions de type.
Une checklist courte peut servir de point de départ :
- Le rapport indique-t-il les nombres de lignes lues, acceptées, rejetées et en erreur ?
- Chaque ligne rejetée a-t-elle un motif exploitable et une référence ?
- Les en-tĂŞtes inconnus, champs obligatoires absents et types inattendus sont-ils visibles ?
- Une ligne de chaque section distincte a-t-elle été vérifiée jusqu'à la destination ?
- Le seuil qui autorise le statut « succès » est-il écrit et justifié ?
- Le traitement peut-il être relancé sans créer de doublons ni écraser des données valides ?
Ce dernier point compte. Un import qui rejette correctement mais crée des doublons à chaque relance reste fragile. La validation doit couvrir le cycle complet : lecture, transformation, écriture, bilan, puis reprise.
La même fragilité dans les API et les contrats de données
Les clients d'API vivent le même problème, mais de façon moins visible. Un client généré (ou écrit) à partir d'une réponse « connue » peut ne lire que les propriétés qu'il attend. Si le serveur ajoute un champ, le client peut l'ignorer sans avertissement. Ça peut rester acceptable si le contrat prévoit explicitement que les champs inconnus sont ignorés. Ça devient un défaut si l'application suppose, implicitement, que « tout ce qui compte » a été consommé.
Il n'y a pas une seule bonne réponse du point de vue compatibilité. Dans certains systèmes, ignorer des propriétés inconnues permet de faire évoluer l'API sans casser les anciennes versions. Mais cette compatibilité a une limite : elle ne doit pas être confondue avec une validation complète. Un champ ignoré peut être une évolution attendue... ou une erreur de version... ou une donnée nécessaire à une fonctionnalité.
Le bon réflexe est de choisir une politique adaptée au contrat :
- Contrat strict : les champs inconnus déclenchent un échec, utile quand la conformité exacte est prioritaire.
- Compatibilité contrôlée : les champs inconnus sont acceptés, mais comptés et signalés dans les logs ou les environnements de test.
- Extension documentée : certains champs sont explicitement prévus comme extensibles, avec une règle claire sur leur conservation ou leur ignorance.
La même logique s'applique aux migrations, aux événements et aux échanges entre services. Un contrat de données n'est pas seulement une liste de champs : il dit aussi ce qui se passe quand le format évolue. Ce choix mérite d'être écrit, plutôt que laissé au « comportement par défaut » d'un parseur ou d'une bibliothèque.
Et pour suivre ces écarts dans le temps, rattachez les alertes aux outils d'observabilité. L'objectif n'est pas de transformer chaque champ nouveau en incident. L'objectif est de distinguer un changement connu d'une dérive non maîtrisée, puis de rendre ce diagnostic actionnable pour l'équipe qui maintient le flux.
Conclusion : un succès doit prouver que les données ont survécu
Arriver à la dernière ligne du processus n'est pas une preuve de réussite. Le code de sortie et le message « import terminé » disent que le traitement s'est achevé ; ils ne disent pas ce qu'il est arrivé à chaque enregistrement.
Pour accepter un import, commencez par vérifier la réconciliation des volumes. Ensuite, choisissez clairement entre arrêt strict et mise en quarantaine avec motifs. Enfin, testez plusieurs formes de la source et rendez visibles les champs inconnus. Ces contrôles ne rendent pas un format plus stable « par magie » : ils évitent surtout qu'une variation se transforme en perte invisible.
Avant votre prochain import, demandez un bilan qui expose les lignes lues, acceptées, rejetées et en erreur. Si le rapport ne permet pas de répondre à « où sont passées les lignes manquantes ? », le traitement n'est pas encore prêt à être déclaré fiable.
