DEV Community

Gravisto
Gravisto

Posted on • Updated on

🇫🇷 [ANGULAR] Transformez Votre Code en Forteresse : Adoptez l'Immutabilité !

Dans le domaine de la programmation fonctionnelle, l’immutabilité des données est un des concepts les plus importants mais aussi un des plus durs à assimiler. Il est beaucoup plus simple de travailler avec des objets mutables et dans la grande majorité des cas le code n’en est pas affecté. Alors préférer l’immutabilité des données dans son application web, ça peut sembler s’infliger des contraintes supplémentaires sans fondement, pourtant ça ne viendrait pas à l’idée d’un collégien de faire ses exercices dans son manuel emprunté au CDI. Traiter toutes ses données comme un livre emprunté, c’est garantir que tous les lecteurs accèdent aux données non corrompues. Dans cet article, on va expliquer la différence entre les données mutables et immutables, ce que cela implique dans votre code javascript et appliquer les bonnes pratiques de manipulation de données.

Le cas des variables mutables

En javascript, seuls les objets sont mutables. Mais si vous avez déjà entendu que tout est objet en javascript alors c’est perdu, tout serait donc mutable ? La réalité est un peu plus complexes que ça. En effet, il existe 7 types primitifs immutables, parmi eux : string, number, boolean, undefined, etc. Mais il existe un objet wrapper autour de chaque type primitif. Donc en principe, tout ce avec quoi on interagit quand on écrit du code javascript est mutable.

Mais in fine, ça veut dire quoi (im)mutable ? On dira qu’une valeur est immutable si pour l’éditer on doit recréer une valeur. Ouvrez la console et essayez le code suivant, la chaine de caractère associée ne sera pas éditée :

const foo = "Coucou le monde!";
foo[1] = "s";
console.log(foo) // output: "Coucou le monde!"
Enter fullscreen mode Exit fullscreen mode

memes sur l'immutabilité


⚠️ Dans le cas de mutabilité, on parle de la valeur (dans l’exemple : "Coucou le monde!") et pas de la variable (dans l’exemple : foo) associée. La variable peut donc changer autant de fois de valeur, cela ne qualifiera pour autant pas le caractère mutable de ces valeurs. ⚠️

Inversement, pour une liste, on peut modifier n’importe quel élément, en ajouter et en enlever sans recréer une liste à chaque fois.

Les mots clefs const et readonly n’ont rien à voir avec la mutabilité des valeurs. Ils garantissent juste que l’on ne peut réassigner de valeurs. On n'en parlera donc pas.

En pratique, les valeurs mutables que l’on utilise sont les objets et les listes.


ℹ️ On parlera de méthode mutable si la méthode modifie la valeur de l’objet sur laquelle elle s’applique. Inversement, un méthode immutable créera une nouvelle référence avec les nouvelles valeurs. En pratique, on parle de fonction pure.ℹ️

Pourquoi travailler avec des données immutables ?

Maintenant qu’on a vu la différence entre valeur mutable et valeur immutable, on va donner deux exemples en Angular pour saisir l’impact que la mutabilité des valeurs peut avoir sur le résultat de notre code.

ChangeDetector d’Angular

stackblitz about cdr

Dans cet exemple de code, on veut créer une animation dans laquelle chaque élément de la liste s’affiche après chaque seconde. Mais pourquoi l’animation du haut ne se met pas à jour ? La différence se situe sur les méthodes pour mettre à jour notre liste.

crd bad example

cdr good example

Le changeDetector d’Angular ne détecte pas les mutations de valeur. Donc si on ne crée pas une nouvelle valeur, le composant (OnPush) ou le pipe (pure) ne mettra pas à jour la valeur dans la vue, même si les valeurs sont correctes.

Il faut bien comprendre que dans les deux cas la liste est bel et bien mise à jour, mais Angular ne peut détecter ces changements car pour lui la liste mutée est la même.


ℹ️ Muter (= modifier une liste de manière mutable) une liste c’est lui ajouter, enlever ou modifier un ou plusieurs élément. On ne peut pas changer une liste de manière immutable, il faut la recréer.ℹ️

Partage de valeur

stackblitz about immutability

Dans ce deuxième exemple, nous avons deux composants qui partagent un objet configuration. On change sa propriété color parce qu’à la place d’une valeur hexadécimale, on veut une valeur RGB pour le CSS. Malheureusement, si je change la valeur pour l’un, la valeur change pour les deux.

immutable bad example

immutable good example

Pour répondre au problème, on peut appliquer nos changement à la liste de manière immutable. On verra dans la partie suivante comment faire dans le cas général en Javascript.

Ces problématiques ne sont pas propres à Angular, ni même au code Javascript mais quand on manipule beaucoup de données, on a intérêt à appliquer des changements immutables aux valeurs que l’on manipule. Ces deux exemples sont simples puisqu’il n'y a que deux-trois composants mais quand les données ont des parcours plus complexes, ce sont généralement des bugs très difficiles à déceler.

Fake it till you make it

poisson avec une aile de requin acroché dessus

Comment travailler avec des données mutables ? Faîtes semblant que les données soient immutables. Ainsi, à chaque update de valeur, il faut recréer son objet.

Le problème de cette méthode c’est qu’elle nécessite de bien connaître les méthodes mutables associées à son objet. Pour les objets issus de librairies, bon courage car il faudra tester à la main. Pour les objets natifs comme Array, MDN saura vous répondre.

Vous pouvez dès à présent bannir sort et accueillir sa petite sœur mutable toSorted tout frais du standard 2023 d’EcmaScript (cf.Nouveautés 2023 JS). Plus simplement, toutes les méthodes qui s’écrivent sous la forme newValue = oldValue.method() ont de bonnes chances d’être immutables.


ℹ️ Pour aller plus loin, il existe des librairies JS (immutable& immer) qui implémentent diverses structures de données immutables pour remplacer les objets natifs javascript mutables. Ces structures de données sont plus sûres à utiliser mais nécessitent que les développeurs soient formés sur ces librairies. Leur grand intérêt est surtout au niveau des performances.ℹ️

Conclusion

Comme le précise la documentation MDN au sujet de l’immutabilité, il est dur de travailler qu’avec des structures de données immutables si aucune sémantique de langage ne le garantit (Rappel, le mot clef const ne garantit pas l’immutabilité des données, seulement de la variable).

Dans le cas de Javascript, cela est avant tout un contrat entre développeurs que les mutations ne sont pas de bons pattern de développement (Par exemple en utilisant Object.freeze ou des librairies spécialisées).

Comme on l’a vu dans la partie d’exemple, le grand intérêt de l’immutabilité est d’éviter des bugs où les mutations ne se transposent pas sur là où on les fait, ou pire qu’elles se transposent là où on ne les fait pas.

Enfin, l’immutabilité est l’un des principes clefs de la programmation fonctionnelle et ouvre les portes aux fonctions pures.

TL;DR: Avoid in place mutation, prefer replacing

Source

JavaScript data types and data structures - JavaScript | MDN
Immutable - MDN Web Docs Glossary: Definitions of Web-related terms | MDN
How everything is Object in JavaScript ?
Prototype and Protypal Inheritance in JavaScript
Primitive - MDN Web Docs Glossary: Definitions of Web-related terms | MDN
Immutability
How is almost everything in Javascript an object?

Top comments (0)