Implementation de IsDirty

6 views
Skip to first unread message

Guillaume JAY

unread,
Mar 9, 2010, 4:50:20 AM3/9/10
to paris...@googlegroups.com
Bonjour,

je me pose la question d'implémenter un IsDirty sur mes objets du domaine, afin de savoir si je dois les persister ou pas.

Je me pose déjà la question de si c'est vraiment nécessaire. Mais bon, admettons.

Comment implémenter facilement, , vu qu'il faut agir sur toutes les propriétés de chaque objet ? Autrement dit, sans me taper le code a la main sur chaque set.

J'ai trouvé un (gros) framework qui doit permettre de faire cela, CSLA.Net, mais c'est sans aucun doute trop complet pour moi, donc, j'envisageais plutot de l'AOP, par PostSharp.

Quelqu'un aurait un commentaire, remarque, avis ?

Guillaume

Romain Verdier

unread,
Mar 9, 2010, 5:46:13 AM3/9/10
to altnetfr
Salut,

Oui, le change tracking est typiquement le genre de truc pour lequel
on peut s'appuyer sur l'AOP.

Romain

Jérémie Chassaing

unread,
Mar 9, 2010, 6:07:05 AM3/9/10
to altnetfr
A mon avis, évite d'implémenter IsDirty sur tes entités....

Il y a plusieurs raisons de s'en passer.
- C'est galère à implémenter
- Ya des frameworks (genre NHibernate) qui gèrent ca très bien pour
toi à l'exterieur des objets du domaines
- Un objet métier bien encapsulé n'a pas de Setters, mais des méthodes
qui représentent les verbes du domaine.

jeremie / thinkbeforecoding

Guillaume JAY

unread,
Apr 1, 2010, 5:01:34 AM4/1/10
to paris...@googlegroups.com
Je reviens sur un sujet..

2010/3/9 Jérémie Chassaing <jeremie....@thinkbeforecoding.com>

A mon avis, évite d'implémenter IsDirty sur tes entités....

Il y a plusieurs raisons de s'en passer.
- C'est galère à implémenter
- Ya des frameworks (genre NHibernate) qui gèrent ca très bien pour
toi à l'exterieur des objets du domaines

Soit, mais je veux faire de l'event sourcing en même temps...

Après, je peux cumuler les deux, si je detecte qu'il y a un besoin d'event sourcing, c'est que mon objet a été modifié (enfin, la, c'est une lapalissade...). Bref (je reflechis tout haut), soit je fais un isDirty "realtime" propriété par propriété, soit je compare au moment de l'enregistrement l'entité (le DTO?) actuel et sa valeur en base. J'avais déjà implémenté une solution de ce type la, il y a bien longtemps, en VB6..

 
- Un objet métier bien encapsulé n'a pas de Setters, mais des méthodes
qui représentent les verbes du domaine.

Ca, j'attend de voir la Wave du restaurant pour bien comprendre, parceque j'ai un peu de mal avec des setters vraiment simple, style nom prenom.

Guillaume

Mathias Kluba

unread,
Apr 1, 2010, 5:48:25 AM4/1/10
to paris...@googlegroups.com
Salut,

J'ai lu un truc sympa sur CQRS récemment: http://abdullin.com/journal/2010/3/23/dddd-cqrs-and-other-enterprise-development-buzz-words.html

D'après ce que je comprend de l'esprit de CQRS, c'est qu'implémenter "isDirty" n'est pas du tout dans la philosophie du truc.
Si tu stockes une pile de "Command", tu peux en déduire ton entité. On part donc des commandes pour construire les entités, et non l'inverse. Savoir qu'une entité à changé te donc un non-sens, car ce changement ne devrait pas se produire sans commande.

J'avoue que stocker une pile de commandes au lieu de l'entité semble un peu barbare. Mais en y réfléchissant bien, il est rare que l'ont ai une pile immense qui ralenti la construction de l'objet. Sans compter qu'on peut avoir des "tag" un peut comme SVN, c'est à dire stocker l'état de l'entité à un instant T.

Ceci dit, je reste septique concernant le CQRS, mais je suppose que ça doit bien marcher dans certains cas.
Pour ma part, j'ai rarement eu besoin de revenir dans le temps pour retrouver l'état de mon entité à un instant T. Mais il est vrai que je fais souvent transiter des DTO avec trop d'information sans raison, au lieu de ne faire transiter que le delta.
Je fais donc de plus en plus des entités avec des property nullable pour ne faire transiter que le Delta.
Le coté distribué de CQRS me fait penser tout simplement à SVN et ses clones: Checkin == command, Checkout == query.
Il serait donc intéressant d'étudier comment l'information est stocké dans SVN/HG/GIT/etc. pour faire un équivalent.
Je pense que réaliser un framework qui est capable de calculer le delta entre 2 entités, ou de merger le delta, ne doit pas être si compliqué que cela (à la automapper). Dans le genre, j'ai vu SyncFramework aux Techdays, mais je trouve ça trop complexe pour ce que c'est.
Si on admet que l'entité que l'on voit est déjà obsolète (ce que nous dit bien Udi à propos de Data staleness), et si l'ont veut faire l'analogie avec SVN, on peut alors considérer que tu travailles avec une "working copy" de ton entité, et qu'elle possède une référence vers son état précédent:
class Entity
{
private EntityState<Entity> initialState;

public int? MyProperty {get;set;}

public bool IsDirty{ get { return this.initialState.CompareTo(this) := 0; } }
}

struct EntityState<T> : IComparable
{
  public T State;

  public int Revision;

  public int CompareTo(T entity){}

  public Entity ComputeDelta(Entity entity){}
}

Qu'en pensez-vous?

Guillaume JAY

unread,
Apr 1, 2010, 6:16:50 AM4/1/10
to paris...@googlegroups.com


2010/4/1 Mathias Kluba <mathia...@gmail.com>

Déjà, je trouve que ton idée de rapprochement avec SVN est très pertinente, a priori. Il faut que j'y reflechisse plus avant.

 

J'avoue que stocker une pile de commandes au lieu de l'entité semble un peu barbare.

Moi je vois surtout un probléme (qui vient peut être d'une mauvaise définition du mot commande) : si tu stockes ta commande plutot que l'etat resultat de cette commande, il faut être certain que ta commande est deterministe. Et je vois tout un tas de cas (du bug corrigé aux paramètrages changeant) qui rendent cela sinon impossible, tout en moins trés complexe et peu "secure".
 

Pour ma part, j'ai rarement eu besoin de revenir dans le temps pour retrouver l'état de mon entité à un instant T. Mais il est vrai que je fais souvent transiter des DTO avec trop d'information sans raison, au lieu de ne faire transiter que le delta.

Je fais pareil, a l'heure actuelle.
 

Je pense que réaliser un framework qui est capable de calculer le delta entre 2 entités, ou de merger le delta, ne doit pas être si compliqué que cela (à la automapper).

Comme j'ai dit, j'avais déjà fait ce genre en VB6, pour comparer deux recordset ADO (le modifié en  mémoire, et celui pris de la base avant écriture du modifié). Ce n'est effectivement pas très compliqué.

Si on admet que l'entité que l'on voit est déjà obsolète (ce que nous dit bien Udi à propos de Data staleness), et si l'ont veut faire l'analogie avec SVN, on peut alors considérer que tu travailles avec une "working copy" de ton entité, et qu'elle possède une référence vers son état précédent:

J'aime bien.  Cependant, pour continuer la comparaison avec SVN, il me semble que ta classe fais la différence "Working Copy"-"Base" (locale) et non "Working-copy" - "Header Version" (pour résoudre le souci Data Staleness, bien sur). Enfin, tout dépend de quand tu charge InitialState.

Guillaume

Jérémie Chassaing

unread,
Apr 1, 2010, 8:35:31 AM4/1/10
to altnetfr
Attention, en event sourcing, on ne sauve pas les commandes, mais les
evenements.
Ensuite, on ne sauve pas la différence d'état, mais le changement
métier qui est intervenu..

Je m'explique :
La commande ne contient que les parametres d'entrée. Le changement
impliqué dépendra de plusieurs parametres :
Etat actuel de l'aggregat,
Contenu de la commande,
Logique métier actuelle.

Si le code métier est redéployé, la suite de commande risque de mener
à un état actuel différent (et les divergences risquent de
s'accumuler).

Pour cette raison, on prefère sauver les evenements qui résultent de
l'appel de la commande.
Ils capturent alors l'état actuel de la logique métier indépendément
des changements futurs de cette logique.

Par exemple, dans notre resto, imaginons qu'on calcule la tva sur les
commandes..
Avant le 1er juillet dernier, la commande EmitBill comptait une tva à
19,6.
Depuis le 1er juillet, elle compte une tva a 5.5

Si on rejout les commandes d'avant le 1er juillet, il faut prendre en
compte l'ancienne tva et utiliser la nouvelle pour les commandes qui
datent d'après. Ceci peut obliger à utiliser des objets temporels ce
qui complique pas mal le code, en particulier si ce type de changement
n'a pas été anticipé.

En sauvant les commandes, on aura un evenement BillEmited { TvaRate :
19,6%, TotalTva : 5€ } pour les commandes appelées avant le 1er
juillet et BillEmited { TvaRate: 5,5%, ToalTva 2€ } pour les autres.
Il sera alors inutile d'utiliser des objets temporels.

L'autre point important est que l'on n'a pas besoin de déterminer si
l'objet à changer.. on emet un changement ou l'on en emet pas :

public void Move(Address newAddress)
{
if (adress == currentAddress)
return;
var event = new UserMoved { Address = newAddress, Far =
IsMovingFar(address, newAddress) };
OnUserMoved(event);
SaveAndPublish(event);
}

private void OnUserMoved(UserMoved event)
{
address = event.address;
}

Ici, meme si la logique IsMovingFar change, le résultat est sauvé dans
les evenements passés.
On voit ici que le pattern repose sur CQS.
La préparation de l'évenement ne change pas l'état du système (Q),
L'application de l'évenement n'utilise pas l'état actuel du système et
ne retourne rien (C).

On a une correspondance exacte entre le changement interne de l'objet
et ce qui est publié.

[Au fait, CQRS != Event Sourcing, on peut faire du CQRS sans event
sourcing et de l'event sourcing sans CQRS ]

jeremie / thinkbeforecoding


On 1 avr, 12:16, Guillaume JAY <guillaume....@gmail.com> wrote:
> 2010/4/1 Mathias Kluba <mathias.kl...@gmail.com>

Guillaume JAY

unread,
Apr 2, 2010, 5:04:23 AM4/2/10
to paris...@googlegroups.com


2010/4/1 Jérémie Chassaing <jeremie....@thinkbeforecoding.com>

Attention, en event sourcing, on ne sauve pas les commandes, mais les
evenements.
Ensuite, on ne sauve pas la différence d'état, mais le changement
métier qui est intervenu..

Merci pour l'exemple, ca correspondait bien a ce que je voyais, en fait (sur evenement, plutot que commande), et c'est tres parlant pour du CQRS réel

Sinon, par rapport a ce que tu me disais deux emails avant, sur "Pas de setters sur metier"
Je viens de lire ceci :
http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/03/31/strengthening-your-domain-avoiding-setters.aspx
et ceci
" operations can be generally divided into two categories: data operations and behavioral operations.  For data operations, where Fee has a Comments property, there’s no inherent need to encapsulate changing the Comments behind a method, simply because there’s no behavior there.  Anyone can change the Fee’s comments at any time, and it won’t affect the consistency of the Fee aggregate root.  For data operations, I personally leave the setters in place."
me parle tout a fait.

Guillaume

Jérémie Chassaing

unread,
Apr 2, 2010, 6:01:20 AM4/2/10
to altnetfr
J'ai juste une objection. Le fait d'utiliser un setter indique que le
commentaire change,
mais ne donne pas la raison du changement.
J'aurais donc tendance à ne jamais utiliser de setter sur les
aggregate root quand même.

Mais après, ce genre de chose est à l'appréciation de chacun...

jeremie / thinkbeforecoding


On 2 avr, 11:04, Guillaume JAY <guillaume....@gmail.com> wrote:
> 2010/4/1 Jérémie Chassaing <jeremie.chassa...@thinkbeforecoding.com>


>
> > Attention, en event sourcing, on ne sauve pas les commandes, mais les
> > evenements.
> > Ensuite, on ne sauve pas la différence d'état, mais le changement
> > métier qui est intervenu..
>
> Merci pour l'exemple, ca correspondait bien a ce que je voyais, en fait (sur
> evenement, plutot que commande), et c'est tres parlant pour du CQRS réel
>
> Sinon, par rapport a ce que tu me disais deux emails avant, sur "Pas de
> setters sur metier"

> Je viens de lire ceci :http://www.lostechies.com/blogs/jimmy_bogard/archive/2010/03/31/stren...
> et ceci
> " *operations can be generally divided into two categories: data operations
> and behavioral operations*.  For data operations, where Fee has a Comments

SerialSeb

unread,
Apr 2, 2010, 6:26:41 PM4/2/10
to altnetfr
Greg dirais meme qu'on a pas besoin de getter non plus.

On Apr 2, 11:01 am, Jérémie Chassaing

> > Guillaume- Hide quoted text -
>
> - Show quoted text -

Reply all
Reply to author
Forward
0 new messages