Comment se représenter l'argent ?
28 02 2025Ce post, c'est la deuxième fois que je l'écris. Pourquoi ? Parce que la première version était bourrée de code. Mais en y repensant, je me suis rendu compte que ce n'était pas ce que je voulais partager. Le code, c'est facile à écrire. Ce qui est plus difficile (et plus intéressant !), c'est d'expliquer les choix qui nous amènent à écrire ce code. Alors aujourd’hui, on va parler de Value Objects et pourquoi ils ont changé ma manière de gérer l'argent dans mon projet. (pas encore dans ma vie... 😭)
En tant que développeur web travaillant actuellement sur une plateforme e-commerce, la gestion des prix est un aspect essentiel. Calculs de montants, application de remises, conversions entre différentes devises… La manière dont on manipule l'argent en code est cruciale pour garantir la fiabilité de l'application. De prime abord, on pourrais dire qu'il suffit uniquement de représenter l'argent avec des chiffres. oui. (mais non)
👉 Le problème initial
Un choix fréquent consiste à stocker les montants sous forme d'entiers en base de données (par exemple, 1234 pour représenter 12.34€). Cela évite les erreurs d'arrondi associées aux nombres flottants. Mais cette approche a ses limites :
- Est-ce 12,34€ ou 1234€ ? 🤔
- Quelle devise ? Euros ? Dollars ? Crayons ?
- Et si quelqu'un le modifie n'importe comment dans le code ? (c'est pas moi, promis)
De plus, lorsuque l'on parle de montant monétaire, on parle de 2 choses : une devise ($, €...) et d'une valeur (17, 0.50...).
Si je prend l'idée de représenter un montant d'une commande stockée en base de données via un entier je n'ai aucune idée de quelle devise on parle et aucune idée de la fomre dans laquelle le prix est stocké (j'éxagère car on stock généralement en centimes).
👉 La solution : Les Value Objects
Plutôt que de manipuler de simples nombres, pourquoi ne pas encapsuler tout ce qui fait un montant (valeur, devise, format...) dans une structure unique et fiable ? C’est là qu’interviennent les Value Objects : des objets qui ne stockent pas seulement une donnée, mais imposent des règles autour d’elle.
👉 Pourquoi cette approche est meilleure ?
Donc en PHP, les Value Objects (objets de valeur) sont des classes qui représentent des valeurs plutôt que des entités. Ils sont souvent utilisés pour encapsuler des données qui sont immuables une fois initialisées. Voici quelques caractéristiques clés des Value Objects :
- Ne peut pas être modifié par accident (immutabilité).
- Me permet de comparer facilement deux montants (même devise, même valeur = même argent)
- Supprime la confusion entre centimes et euros : il sait toujours dans quelle unité il est stocké.
- S'intègre naturellement dans les règles métier : il empêche des erreurs d’arrondi ou de conversion.
☝️ Comment je l'implémente ?
Dans un projet Symfony, un Value Object comme Money peut être utilisé directement dans les entités pour améliorer la clarté et la fiabilité du code. Plutôt que de stocker simplement un int dans la base de données, on peut mapper un Value Object dans une entité grâce aux Doctrine Embeddables ou aux Custom Doctrine Types.
Par exemple, au lieu d'avoir dans l'entité Order :
$amount stocké en centimes et utilisé un peu partout dans le code
On définit une propriété de type Money, qui encapsule la valeur et la devise. Symfony et Doctrine peuvent alors convertir automatiquement l’objet pour le stockage en base de données.
En plus d’améliorer la lisibilité, cela permet d’appliquer une logique métier stricte : toutes les opérations monétaires passent par l’objet Money, empêchant les erreurs de conversion et garantissant une cohérence totale dans l’application.
☝️ Un dernier mot ?
En les utilisant, je ne manipule plus des nombres sans contexte, mais des objets intelligents qui garantissent que l'argent dans mon application reste cohérent, précis et sécurisé. Et finalement, c'est ça le vrai but du développement : écrire du code qui nous protège de nos propres erreurs. (elle est belle celle là, c'est cadeau)