La transparence référentielle est ce que vous recherchez lorsque vous développez. L'immutabilité ? Le déterminisme ? C'est dépassé ! La transparence référentielle est le spécialiste des problèmes techniques. Elle va vous aider à retrouver le plaisir de coder. Résolution de la dette technique, succès social, réussite dans vos projets. Les résultats sont immédiats.

Dans cette première partie, nous allons voir ce à quoi correspond la transparence référentielle et différents use cases. Puis, nous allons parler de son pire ennemi : les effets.

Définition

Selon Wikipédia, une expression est référentiellement transparente si elle peut être remplacée par sa valeur sans changer le comportement du programme (c'est-à-dire que le programme a les mêmes effets et les mêmes sorties pour les mêmes entrées, quel que soit son contexte d'exécution). À l'inverse, une expression est référentiellement opaque si elle n'est pas référentiellement transparente.

En dehors de l’enthousiasme qu'elle semble susciter, comment cette chimère académique peut-elle avoir le moindre intérêt ?

La transparence + référentielle quand on ne sait pas ce que c'est !

La transparence + référentielle quand on ne sait pas ce que c'est !

Bien qu'elle n'aide pas forcément tant que ça, cette définition fait apparaître la notion de "comportement" et le fait qu'on ne change pas ce comportement. Ce qui est intéressant, puisque c'est à la base du refactoring (la version anglaise de cette notion est un peu plus parlante). Nous allons voir que les deux termes sont intimement liés et que nous allons trouver dans la transparence référentielle des conditions pour améliorer la lisibilité du code, sa maintenabilité et sa testabilité. Nous avons donc là un concept digne d'être connu par les partisans du software crafting, qui nous amène à nous poser de bonnes questions, tout en faisant (indirectement) la promotion de la programmation fonctionnelle pure.

Use cases

Pour commencer, nous allons partir à l'inverse de la définition vue plus haut : nous avons des valeurs et nous allons les remplacer par des expressions. Voici une expression où une valeur est répétée.

List(42, 42, 42)

Par refactoring, cette expression est équivalente à :

val lifeTheUniverseAndEverythingElse = 42

List(
  lifeTheUniverseAndEverythingElse,
  lifeTheUniverseAndEverythingElse,
  lifeTheUniverseAndEverythingElse)

Nous avons un cas classique où par transparence référentielle, on peut passer par la création d'une constante pour donner un sens à un nombre magique, sans changer le comportement de ces lignes de code.

Nous pouvons faire le même exercice avec un chaînage d'appel de méthode. L'exemple ci-dessous est un cas typique de oneline, c'est-à-dire écrire tout une expression virtuellement en une seule ligne ou en un seul chaînage d'appels. Malheureusement, cette pratique ne facilite pas la lecture du code.

val wordCounts =
  myText
    .split("[\\r\\n]+")
    .flatMap(line => line.split("\\\\s+"))
    .groupBy(word => word)
    .mapValues(occurrences => occurrences.size())

Par transparence référentielle, il est possible de refactorer le code ci-dessus en introduisant au choix une variable intermédiaire ou une fonction, à nouveau sans changer de comportement.

def wordsIn(text: String): Array[String] =
  text
    .split("[\\r\\n]+")
    .flatMap(line => line.split("\\\\s+"))

val wordCounts =
  wordIn(myText)
    .groupBy(word => word)
    .mapValues(occurrences => occurrences.size())

Le nom ici permet de donner un plus de sens au code, d'en clarifier l'intention.

La notion de "changer de comportement" est plutôt subjectif et va potentiellement varier en fonction du contexte. Au minimum, il va s'agir de s'intéresser uniquement au résultat de ces expressions. Mais si on est sur un projet où l'on doit porter une attention aux performances, alors cette performance perçue fait partie du comportement et il est possible de constater une différence de comportement dans les différentes solutions vues plus haut. Dans ce cas et dans ce cas uniquement les différentes alternatives ne sont pas référentiellement transparentes.