Certaines situations exceptionnelles peuvent être prévisibles, mais arrivent une fois sur cent. Sans ordinateur, un être humain qui suit une procédure les remarque souvent spontanément, et adapte son comportement en conséquence.

Un ordinateur, lui, suit bêtement la règle, et l’applique dans des cas qu’un gamin de quatre ans trouverait débiles. D’où les classiques des débuts de l’informatisation administrative, comme les factures à 0,00 franc, ou les dossiers d’inscription à l’école envoyés à de vieilles dames de 106 ans. Les sociétés qui transforment des humains en téléopérateurs-perroquets assimilés à des machines sans initiative génèrent le même genre de bugs, juste avec de la viande en guise de matériel.

Je me méfie comme de la peste des spécifications écrites par des gens qui raisonnent « en règle générale » (à peu près la totalité de la population). Or, pour un développeur, il n’y a pas une règle générale et son 0,0001% d’exception, mais bien deux cas à traiter. Si le deuxième, exceptionnel, est renvoyé à un humain, cela me convient ; encore faut-il anticiper et détecter cette exception, prévenir cet humain, et donner à celui-ci le droit et le moyen matériel de passer « en manuel ». Notre civilisation pèche de plus en plus sur ce point.

Donc par déformation professionnelle, je dois devenir vicieux et mettre en doute les choses les mieux établies. Prenons quelques exemples. Demandez-vous si les règles suivantes sont vraiment universelles :

  • Toutes les années ont 365 jours.

Non, il y a les années bissextiles. Je sais, c’est facile. Mais il faut y penser réellement quand on calcule, par exemple, un taux annuel à partir de quantités journalières, et la formule devient subtilement plus compliquée qu’une bête multiplication. L’impact n’est pas négligeable (une journée de travail en plus, c’est 0,5% d’heures travaillées en plus sur l’année, et 5% en plus en février) et des comparaisons entre années doivent en tenir compte.

Cela fait aussi un cas à ajouter au jeu de test...

  • Toutes les années divisibles par 4 sont bissextiles.

Ça c’était au temps du calendrier julien. En calendrier grégorien, les années divisibles par 100 (1800, 1900...) ne sont pas bissextiles.

Pour les informaticiens versés dans les dates lointaines et étrangères, il faut faire attention : selon les pays, le passage au calendrier actuel s’est étalé de 1582 à 1929.

  • Toutes les années divisibles par 4 non divisibles par 100 sont bissextiles.

Depuis l’an 2000, on sait que non : par exception à l’exception qui veut que les années divisibles par 100 ne soient pas bissextiles, les années divisibles par 400 sont bissextiles. Il reste à espérer que les logiciels retouchés pour l’an 2000 ne l’ont pas été avec une simple exception pour 2000, sinon ceux encore en activité en 2400 nous sauteront à nouveau à la face.

  • Toutes les années divisibles par 4 non divisibles par 100 sont bissextiles, et aussi celles divisibles par 400.

Le 1er avril 1999, le site des éditions allemandes Heise annonçait la découverte de documents d’époque révélant que lors de la mise en place du calendrier grégorien et de la règle de la divisibilité par 100 ou 400, il avait été aussi précisé que les années divisibles par 1000 ne seraient pas non plus bissextiles, même si elles étaient divisibles par 400 (cas de l’an 2000), avec l’exception de 5è niveau des années divisibles par 4000, qui seraient bien bissextiles.

Cette règle flanquait par terre une bonne partie du travail effectué pour corriger le bug de l’an 2000, et l’industrie entière a préféré prendre cette histoire comme un poisson plutôt que reprendre de zéro le travail. Je vous laisse vous faire votre avis. :-)

  • L’année commence en janvier et finit en décembre.

Ne pensent cela que ceux qui n’ont pas travaillé avec des comptables. Les années fiscales et civiles n’ont pas forcément grand rapport, il y a un décalage de plusieurs mois.

  • Il y a 12 mois dans l’année (calendrier grégorien).

Pour le commun des mortels en Occident, oui.

Pour un système de gestion financière de collectivité locale française, il peut y en avoir 14 :

- les 12 mois habituels ;
- un pseudo-mois nommé par exemple « Décembre N-1 » rattaché à l’année N mais comprenant par exemple toutes les décisions prises à la fin de l’année civile antérieure (on vote en décembre le budget de l’année prochaine) ;
- un pseudo-mois « Journée complémentaire » qui regroupe toutes les opérations qui doivent être rattachées à cette même année N, mais qui pour des raisons pratiques sont effectuées en réalité au début de l’année suivante.

Pour une entreprise qui change sa référence d’année fiscale (par exemple de mars à mars au lieu de janvier à janvier), une année de transition est démesurément longue ou raccourcie.

Je suis sûr qu’il y a dans le monde une flopée d’exemples d’astuces de ce genre propres à un métier, une administration, une entreprise, un service, qui flanquent en l’air nombre d’algorithmes un peu naïfs.

  • En Occident, les mois sont janvier, février, mars, avril...

J’ai des ancêtres nés en ventôse de l’an V de la République...

Un logiciel traitant de cadastres, de généalogie, d’actes juridiques... peut avoir besoin de ces données remontant à deux siècles. Le recalcul permanent en calendrier grégorien est source d’erreurs, et il vaut mieux aussi stocker la date originelle pour comparer avec les documents originaux. (Bon, soyons réaliste, un champ « commentaire » pourrait suffire en pratique.)

  • Il n’y a pas de 30 février ni de 31 juin.

Dans le calendrier grégorien occidental récent, non.

Dans un champ rempli par les utilisateurs, et non contrôlé, on peut avoir n’importe quoi.

L’exemple type est le « flexfield » d’Oracle Applications (l’ERP). En gros, c’est un champ optionnel avec filtre paramétrable qui s’ajoute aux champs habituels d’un écran, et que peut remplir l’utilisateur. L’endroit idéal pour stocker une information non prévue dans le logiciel original, par exemple un code, un texte... ou une date de départ ou d’arrivée ou de rappel ou de Dieu sait quoi.

J’ai vu cent fois le cas de dates totalement corrompues dans ces champs : la valeur est stockée dans une colonne dédiée prévue pour cela (genre SEGMENT1, SEGMENT2, ... SEGMENT20), qui est forcément une chaîne (type Oracle VARCHAR2). Si cela ne porte pas à conséquence pour stocker un nombre (sauf pour le symbole décimal), les ambiguïtés pour une date sont énormes :

- L’utilisateur peut remplir un peu n’importe quoi s’il est mal luné.
- Il n’est pas à l’abri d’une faute de frappe et on obtient une année 202.
- Le symbole de délimitation n’est pas clair.
- Si des Américains sont impliqués, il y a le risque de voir des dates au format MM/JJ/AAAA... (et le pire est que pour les jours inférieurs à 13, vous ne pourrez pas détecter une erreur.)
- Les années de champs remplis avant l’an 2000, voire après, risquent d’être sur deux chiffres.
- Si des données sont importées d’autres systèmes, ou écrites par un programme directement en base (ça se fait, sous Oracle Appli...), en contournant les filtres éventuellement en place pour éviter les cas précédents, un développeur imprudent risque de stocker dans le format par défaut de sa session, qui ne sera pas forcément celui prévu par une autre session (DD/MM/YYYY n’est pas la même chose que DD-MON-RR HH24:MI:SS). S’il n’y a pas ambiguïté pour un humain, l’ordinateur ne trouvera pas tout seul le bon format.

Une autre erreur est de caser les dates sous forme de chiffres (!). On peut donc tomber sur un 20051232 pour le 32 décembre 2005. Oui, ça peut arriver quand on fait des calculs sous forme DateB = DateA + 1 comme il est si pratique avec un vrai champ DATE de base de données qui est fait pour ça, et que la routine de calcul est boguée.

Bref, je me méfie toujours des dates non stockées sous forme de champ de type DATE (et même : la faute de frappe qui oublie un chiffre à l’année reste possible si l’interface humaine n’est pas blindée...).

  • Il n’y a pas eu réellement de 30 février (bis).

Oui, moi aussi je l’ai cru.

Dans leur chaotique transition au calendrier grégorien au XVIIIè siècle, les Suédois ont réussi à créer un 30 février. Un calendrier révolutionnaire soviétique rapidement abandonné aurait eu des mois de 30 jours. Dans des modèles mathématiques, on arrondit parfois les mois à 30 jours (mais peut-on encore les nommer avec les noms habituels auxquels ils ne correspondent plus ?).

Voir l’article de Wikipédia pour les détails.

(Ajout du 1er janvier 2012) Et puis tant qu’on y est dans les bizarreries : les Samoa, ayant changé deux fois de fuseau horaire et franchi deux fois la ligne de changement de date, ont eu deux 4 juillet 1892, mais pas de 30 décembre 2011. Ce genre de bizarrerie disparaît si toutes les dates sont stockées et calculées en Temps universel, mais quel développeur en prend la peine dans les applications où les fuseaux horaires ne jouent habituellement pas ?

  • Il y a 52 semaines dans une année.

Comme il y a bien toujours sept jours dans la semaine depuis des temps immémoriaux, et en laissant de côté les cas des années de transition entre les calendriers julien et grégorien, on peut calculer qu’il y a 365/7= 52,14 semaines dans l’année. Donc le 31 décembre peut tomber dans un début de 53è semaine. Quoi qu’on fasse, on n’aura jamais un nombre entier de semaines dans une année.

Il y a un moyen normalisé de calculer le numéro de la semaine, c’est la semaine ISO. Le 1er janvier peut tomber la semaine 01 de l’année en cours, ou 52 ou 53 de l’année précédente. Le système ISO prévoit donc carrément des années différentes de longueur variable avec un nombre entier de semaines, mais ce n’est pas du tout entré dans les mœurs. En conséquence, un tableau qui affiche année civile/trimestre/mois/semaine ISO commencera à 2008/1/janvier/1 et finira à 2008/4/décembre/1. D’où deux semaines 1 dans l’année (civile) 2008...

Ce qui est rigolo, c’est que j’ai vu des différences dans le calcul de la semaine entre le monde entier et Outlook, ou entre deux versions de Business Objects (6.5 et XIR2). Je n’ai pas pu creuser, c’est peut-être lié aux paramétrages locaux.

  • Il y a toujours 24 heures dans une journée.

...Sauf deux fois dans l’année lors des transitions entre heure d’hiver et heure d’été... Donc de 23 à 25 heures. Et il faut éventuellement prévoir le gag d’avoir un événement à 2h59 (heure d’été) suivi d’un autre à 2h01 (heure d’hiver).

  • Une heure comprend toujours 3600 secondes.

Plutôt entre 3599 et 3601 : presque chaque année, des secondes sont enlevées ou rajoutées en fin d’année pour recaler le temps universel et la rotation de la Terre (tout de même la référence finale). Si dans un ERP on néglige le problème (le développeur est déjà heureux si tous les serveurs sont synchrones à la seconde près entre eux), les calculs de trajectoires de satellites doivent en tenir compte.

D’ailleurs le calcul temporel en orbite doit être assez folklorique puisqu’il faut même tenir compte d’éventuelles corrections relativistes (les détails sordides sont et ).

  • Le numéro de Sécurité Sociale identifie un individu de manière unique.

Non, il y a même une possibilité de doublon entre des gens nés à cent ans d’intervalle au même endroit. Voir Wikipédia pour les détails et le passionnant historique. D’ailleurs il est possible de changer de numéro de Sécu (par exemple pour un transexuel ou quelqu’un né dans l’Algérie française).

Noter aussi qu’il existe des gens n’en possédant pas : étrangers, enfants... De plus, en Europe, le numéro de Sécurité Sociale est considéré comme une donnée personnelle, à diffusion restreinte et il n’est donc pas censé se retrouver n’importe où, doit être anonymisé, etc.

C’est un exemple fascinant à verser au dossier du débat « clé primaire arbitraire vs. clé primaire fonctionnelle. » (J’en causerai un jour. Ajout postérieur : C’est fait !)

  • Les numéros des départements français ont deux chiffres.

...Sauf dans les DOM-TOMs ! Guadeloupe : 971 , St Pierre & Miquelon : 975

...Et vous avez tout faux si vous croyez que c’est du numérique (Corse : 2A et 2B).

De manière plus générale, la géographie offre une montagne d’aberrations diverses à toute personne cherchant à y établir des règles. Rien que la transposition des lois votées à Paris par l’assemblée de Tahiti, ou leur compatibilité avec la loi alsacienne, donne du travail à maints juristes.

  • Un enfant a biologiquement un et un seul père et une et une seule mère.

Évidemment non.

Depuis quelques années il existe des mères porteuses, ce qui est autorisé dans certains pays. On peut choisir de prendre en compte la mère porteuse, ou celle qui a fourni l’ADN (qui peut d’ailleurs être une autre que celle qui va élever l’enfant), mais ce choix doit être conscient.

Comme dans le cas des enfants adoptés, où la filiation est modifiée par l’adoption. Selon le cadre et le but du logiciel développé (généalogie, études génétiques...) il faudra trancher, et se demander ce que l’on fait dans certains cas tordus du genre des enfants clonés (ça arrivera), ou pour un transexuel (devenu homme) qui accouche d’un enfant (biologiquement c’est juste une femme qui a un enfant, mais civilement il est le père). Je prédis l’enfer informatique à cette famille, aucun logiciel n’est prévu pour gérer ce genre de cas.

  • Il n’y a que deux sexes.

En fait, cela dépend de ce que vous voulez faire de l’information. En tête du numéro Sécu peuvent apparaître 3, 7 ou 8 pour les transexuels et autres statuts provisoires. Pour un simple libellé de courrier, il y a trois possibilités traditionnelles (M., Mme, Mlle).

Dans une application pour un zoo ou un laboratoire de biologie, il faudra tenir compte des bestioles capables de changer de sexe à volonté. Sans compter les hermaphrodites comme les escargots, ou les espèces où le concept de sexe n’existe pas.

  • Tout le monde a un nom et un ou plusieurs prénoms.

J’ai rencontré pendant mes études un Indonésien qui n’avait qu’un nom. Je ne sais pas comment il avait rempli sa demande de visa.

  • 12 > 2

Si vous manipulez des nombres, déclarés comme nombres auprès de l’ordinateur, oui.

Si vous manipulez des nombres stockés sous forme de chaînes de caractère (cela arrive tous les jours...), l’ordre lexicographique prend le pas et vous aurez tout ce qui commence par « 1 » qui sera trié avant (donc inférieur à) « 2 » : « 1 », « 10 », « 12561265463 »,..., « 2 », « 2564536 », ..., « 3 »,... Une conversion explicite en nombre peut être nécessaire suivant l’outil et le langage.

Je suis preneur de toute autre « règle générale qui ne l’est pas » à ajouter à cette liste !