Revenir
en haut

Bases: Value Object et Domain Model

19/12/2011 0

Introduction

Dès que les termes VO ou Value Object ressortent dans une discussion, je constate qu’une remarque revient presque systématiquement : « VO ? » ou encore « VO, tu veux dire un DTO c’est ça ? »

Ces sujets ont déjà été débattus il y a plus de 15 ans, mais certains développeurs « neufs » peuvent parfois ne pas les connaitre (ce qui n’est pas illogique). Je voulais donc faire un billet pour rappeler en quelques lignes de quoi il s’agit.

Notez que très souvent les développeurs utilisent les Value Objects mais ne savent tout simplement pas qu’il y a 15 ou 20 ans, d’autres personnes leur ont donné un nom :-)

Qu’est-ce qu’un Value Object (VO)

Si on reprend la définition de Martin Fowler dans P of EAA :

« A small simple object, like money or a date range, whose equality isn’t based on identity » http://martinfowler.com/eaaCatalog/valueObject.html

Il n’y vraiment pas grand chose à ajouter à cette définition ! Un Value Object est simplement un objet sans identité, c’est à dire un objet dont l’unicité n’est pas déterminée par un attribut du type « Id » (ou autre selon le système de persistance utilisé), mais par simple comparaison de l’ensemble de ses propriétés.

Concrètement ça signifie également qu’un VO n’a pas de vie en dehors de l’objet qui le contient. Il vie et meurt avec cet objet, qui lui, aura sans doute une identité.

L’importance des VOs dans le design du Modèle

En PHP, les VOs étaient très peu utilisés jusqu’à maintenant. Pour la simple raison qu’ils sont compliqués à stocker et à utiliser avec un système de persistance. Il sera par exemple complexe d’effectuer des requêtes avec des conditions sur les propriétés d’un VO.

Ceci est en train de changer (je dis bien « en train », il y a encore du chemin à faire) grâce à l’arrivée d’ORMs qui laissent de plus en plus de libertés aux développeurs dans leur design objet.

Et c’est une grande nouvelle, car les VOs représentent vraiment un outil essentiel pour designer un modèle solide et consistent.

La preuve par l’exemple

J’espère vous le prouvez à travers un exemple très simple (et réaliste) : « Un bout de système de réservation de véhicules de location » (un bout simplifié :p)

Le sujet

Le système propose aux utilisateurs de louer des véhicules sur une période donnée, et en tenant compte des demi-journées. Le prix de la location diminue à partir du 2ème jour. Le prix de la location inclut une distance en kilomètres, et chaque kilomètre supplémentaire sera facturé.

Design basique « à plat »

Ceci est le type de design que nous retrouvons le plus fréquemment.

Avant

Analyse

En analysant le diagramme, il est facile de comprendre pourquoi je parle de design « à plat ». Nous constatons la nature « inflexible » des données ici.

Première chose, à partir du moment où un développeur manipule des données monétaires, un objet Money devrait systématiquement faire partie du design. Je ne comprend d’ailleurs pas pourquoi ce type d’objet ne fait pas partie intégrante de tous les langages.

Manipuler une donnée monétaire n’est pas simplement manipuler un type double. Il s’agit de gérer des arrondis, une devise, et éventuellement des opérations de conversions.

Que se passe-t’il si des doubles se baladent un peu partout dans le code et que le développeur n’applique pas les mêmes règles d’arrondi dans tous les calculs ? Et que se passera-t’il le jour où il est nécessaire de proposer le service dans une autre devise ?

Je pense que vous avez deviné…

En partant de ce principe, nous pouvons extrapoler ces idées aux autres composants du design.

Par exemple, notre métier possède ici des règles particulières sur les dates de réservation. Il ne s’agit pas simplement d’une date de départ et d’une date d’arrivée. Il existe une règle concernant les demi-journées. Cette règle a une influence directe sur le prix de la réservation. Quelle sera la règle pour borner une demi-journée ? Pour borner un ensemble de dates (début et fin) ?

Le design actuel ne laisse entrevoir aucune de ses règles. Comment seront-elles appliquées alors ? Et bien je vous donne la réponse, même si vous la connaissez, un peu partout dans le code, dedans et en dehors de l’objet Booking, dès lors qu’une date de réservation devra être manipulée.

Ceci aura pour incidence d’éparpiller les règles métier, et si ces dernières changent, le système peut facilement devenir défectueux.

De même pour les prix, le prix d’une réservation n’est pas seulement déterminé par un double, factoriser la règle de calcul du prix dans un objet peut s’avérer également payant dans l’avenir.

Pas besoin d’aller plus loin, je pense qu’à ce stade vous avez compris où je veux en venir.

Design « riche » (factorisation et VOs)

Voici maintenant le design que je vous propose pour remplacer le précédent:

Après

Le diagramme parle de lui même. Dès qu’une valeur monétaire entre en jeu un type Money sera retourné. Lors du calcul du prix d’une annonce, l’objet Booking délègue le boulot à l’objet Rental qui lui même le délègue à l’objet PricePack. Les quelques notes vous montrent de quelle manière les différentes règles métier liées aux prix ou aux dates peuvent être implémentées. Si elles changent, un seul objet à modifier et le système fonctionne.

Le design pourrait sans doute être encore amélioré, mais peu importe, le principe est là ;-)

Les VOs ne sont pas des DTOs

Je terminerai avec quelque chose d’important à savoir et qui clarifiera sans doute les choses pour certains:

NON UN VO ET UN DTO CE N’EST PAS LA MÊME CHOSE !

Un DTO (Data Transfer Object) a un rôle bien précis dans l’application. Il s’agit d’un objet transportant le maximum d’informations pour diminuer le nombre de requêtes et d’appels de méthodes. Le but est de transférer le plus de données possible en une seule fois.

Je dirais presque (j’ai dit presque) qu’un DTO est l’inverse d’un VO. Un DTO est un objet qui tente d’aplatir au maximum les données, l’exemple très simple de Martin Fowler illustre très bien ce principe: http://martinfowler.com/eaaCatalog/dataTransferObject.html

Alors qu’un VO, au contraire, va servir à enrichir un design par composition.

Ceci étant dit, merci d’avoir lu cet article, j’espère qu’il vous aura apporté quelque chose !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

*

Tags HTML autorisés : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Tag code : [cc lang="langage"][/cc] (ex. [cc lang="php"][/cc])