Code et data : une dualité fondamentale
La frontière entre code et données est bien plus poreuse qu’on ne le pense généralement.
Un programme source n’est, après parsing, qu’un arbre de syntaxe abstraite : une structure de données comme une autre, avec des nœuds, des branches, des feuilles.
Lisp a rendu cette équivalence explicite dès ses origines : le code est une liste, les listes sont des données, et eval transforme une donnée en comportement exécutable. Les macros, les métaprogrammes, les compilateurs : tous manipulent le code comme une donnée que l’on peut inspecter, transformer, générer.
Inversement, une donnée de configuration suffisamment expressive (règles métier en JSON, workflows en YAML) devient du code déguisé, interprété par un runtime qui lui donne sens.
La duplication comme dette
Cette équivalence a une conséquence directe sur la duplication.
Une donnée dupliquée en deux endroits divergera inévitablement : quelqu’un mettra à jour une occurrence en oubliant l’autre, et l’incohérence s’installera silencieusement. C’est pourquoi les bases de données normalisées évitent la redondance : une seule source de vérité, des références vers cette source.
Le code, étant de la donnée, obéit à la même loi. Du code dupliqué finira par diverger : un développeur corrigera un bug dans une copie sans connaître l’existence de l’autre, ou fera évoluer un comportement ici mais pas là.
La duplication est une dette qui porte intérêt. Une règle de calcul de prix dupliquée en quatre endroits et modifiée en trois seulement : c’est un client qui reçoit une facture incohérente, un litige commercial, une perte de confiance. Ces divergences se propagent silencieusement jusqu’au moment où elles deviennent des incidents visibles.
Coïncidence vs comportement partagé
Le réflexe de systématiquement mutualiser tout code similaire est une erreur. Deux fragments de code identiques aujourd’hui ne devront pas nécessairement avoir le même comportement demain : ils peuvent n’être qu’une coïncidence accidentelle, valable aujourd’hui seulement.
La question à se poser n’est donc pas « ces deux morceaux se ressemblent-ils ? » mais « ces deux morceaux doivent-ils évoluer ensemble ? ».
- Si modifier l’un doit toujours entraîner la même modification de l’autre, alors ils représentent un seul comportement et méritent une seule implémentation
- Si l’un pourrait légitimement évoluer indépendamment de l’autre, les fusionner créerait un couplage artificiel et nuisible
Cohérence dans le temps
L’impératif sous-jacent est donc la cohérence du comportement dans le temps, pas la ressemblance syntaxique dans l’instant.
Deux modules distincts qui calculent une TVA à 20% ne devraient pas partager ce code si l’un concerne la France et l’autre un pays dont le taux pourrait changer indépendamment.
Inversement, deux calculs apparemment différents qui doivent toujours produire le même résultat (un prix affiché et un prix facturé, par exemple) devraient partager leur implémentation même si leurs contextes d’appel diffèrent.
La duplication délibérée et la mutualisation délibérée sont toutes deux des choix de design ; seule la duplication accidentelle est une faute.
En contexte réglementaire, cette distinction devient critique. Un auditeur qui demande « où est la source de vérité pour le calcul des frais de dossier ? » attend une réponse précise, pas « dans plusieurs fichiers qu’on maintient synchronisés manuellement ». La duplication de connaissances métier transforme chaque audit en archéologie du code.
DRY bien compris
Cette réflexion rejoint le principe DRY (Don’t Repeat Yourself) souvent - mal - compris comme signifiant « ne jamais écrire deux fois la même chose ».
La formulation originale de Hunt et Thomas est plus subtile :
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
— Andy Hunt & Dave Thomas, The Pragmatic Programmer (1999)
C’est la connaissance qui ne doit pas être dupliquée, pas le texte. Deux lignes identiques peuvent représenter deux connaissances distinctes ; une seule connaissance peut s’exprimer différemment selon le contexte.
Voir le code comme de la donnée, c’est-à-dire une représentation structurée de comportements, nous rappelle que la question n’est jamais syntaxique mais sémantique : quel comportement ce code encode-t-il, et ce comportement est-il un ou multiple ?
Envie d'approfondir ces sujets ?
Nous aidons les équipes à adopter ces pratiques via du conseil et de la formation.
ou écrivez-nous à contact@evryg.com