snapshot/memento pattern

119 views
Skip to first unread message

Christian Setzkorn

unread,
Jun 2, 2014, 4:11:23 AM6/2/14
to ncqr...@googlegroups.com
I hope this question is not too generic for the ncqrs group.

I understand that an aggregate root usually replays all events to put itself in the right state. This can become inefficient, hence people suggested the memento pattern to create a snapshot of the aggregate root. My understanding is that the domain model has nothing to do with persistence. I also think that the snapshot has nothing to do with read model. Could someone please be so kind and point out where the snapshots are usually persisted then? Thanks.

Adam Greene

unread,
Aug 12, 2014, 3:42:14 PM8/12/14
to ncqr...@googlegroups.com
Good day Christian,

the simplest answer (if using the DynamicSnapshot extension) is that the snapshot is a copy of the backing fields of the AggregateRoot.  This is accomplished by analyzing the AggregateRoot's properties, generating a snapshot class dynamically (ie.  if you have a Client class, it creates a Client_Snapshot class for the snapshot) that contains the fields, and then copying the value of the fields into the snapshot, and then serializing the result and storing it in the snapshots table in the database.  The key is to call:  Component.For<Note>().AsSnapshotable()) (as seen in https://github.com/ncqrs/ncqrs/blob/master/Samples/MyNotes%202012/src/MyNotes.ApplicationService/BootStrapper.cs, line 51) to indicate to the DynamicSnapshot extension that you wish to generate snapshots for Note (in this case).

@yreynhout

unread,
Sep 10, 2014, 6:02:56 AM9/10/14
to ncqr...@googlegroups.com
TL;DR; Anywhere you want.

You have to understand that you're taking the snapshot with the intent of restoring an aggregate's state at a later stage (without replaying the events obviously). The snapshot is therefor a contract the model has with any external consumer of that model (most commonly persistence, but you could e.g. envision pushing it to a hot-standby aggregate). In other words, you have to treat it like a message, a structure, that you may or may not want to version. To a certain extent you are leaking "internals" but you're doing it in a deliberate/explicit way. I would be weary of expressing a snapshot using "internal" constructs such as value objects and generally bias towards primitives. Otherwise you might be in for a surprise if those value objects change and break your snapshot-as-a-contract. You'd also be delegating a serialization concern onto your value objects - something that may not be desirable (but to some this will sound like splitting hairs).

As to the persistence of snapshots, you could persist them in a separate stream, the same stream (here be dragons in the form of concurrency issues), a key/value store, a document store, a database acting like a key value store, etc ...

HTH,
Yves.

Adam Greene

unread,
Sep 10, 2014, 7:44:47 AM9/10/14
to ncqr...@googlegroups.com
Hi Yves / Christian,

Yves is right in that snapshotting is best done with primitives.  The way the NCQRS.DynamicSnapshotting project currently works is that it creates a dynamic class made of fields to which it assigns the current values of the internal fields of the domain object (not the properties, and including the backing fields of auto properties).  It then binary serializes that object into a DB table (usually called Snapshots).  The only draw back right now (that I'm personally working on) is the lack of support for non-serializable types (especially Entities).

--
You received this message because you are subscribed to the Google Groups "ncqrs-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ncqrs-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Adam Greene, Lead Software Architect
ad...@cognitivex.com / http://www.cognitivex.com / 1.800.670.COGX (2649)

Please consider the impact on the environment before printing this email

Christian Setzkorn

unread,
Sep 10, 2014, 7:52:18 AM9/10/14
to ncqr...@googlegroups.com
Hi,

Thanks for your reply (started to use the blob approach you discussed a while back). Just curious, why should Entities not be serialize? 

Thanks.

Christian

--
You received this message because you are subscribed to a topic in the Google Groups "ncqrs-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ncqrs-dev/sZJOdaIBdO4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ncqrs-dev+...@googlegroups.com.

Adam Greene

unread,
Sep 10, 2014, 8:05:45 AM9/10/14
to ncqr...@googlegroups.com
It's not that they shouldn't be serialized, but the Ncqrs.DynamicSnapshot project doesn't support them out of box because they are not marked serializeable.  But the bigger problem is reassociating them to the domain object (even if you added [Serializable] to them, they deliberately, and should deliberately, mark the reference to the domain object as non-serializable).  I actually had a version of DynamicSnapshot working with Entities, but lost it when the hard drive it was on got formatted (was a work laptop, long story).  I'm rebuilding that work now (hopefully better).  So if you are only using AggregateRoot's and are staying away from Entity and non-serializable types, then you can use NCQRS.DynamicSnapshot as is.

@yreynhout

unread,
Sep 10, 2014, 8:35:58 AM9/10/14
to ncqr...@googlegroups.com
Not only that but this approach couples your internals to your snapshot which will make this a versioning and refactoring nightmare (imagine renaming a field, changing its type or going from a list to dictionary for tracking your entities/value objects). 

Adam Greene

unread,
Sep 10, 2014, 10:16:18 AM9/10/14
to ncqr...@googlegroups.com
Yes, it does couple it.  But is easy enough to fix, all you have to do when you make a breaking change is delete your snapshots and get the system to regen them.  The power and joy of CQRS/ES :-)

Christian Setzkorn

unread,
Sep 10, 2014, 10:26:28 AM9/10/14
to ncqr...@googlegroups.com
Thanks makes all sense. Just curious, would event versioning as discussed here:


also work? Thanks.

Adam Greene

unread,
Sep 10, 2014, 10:31:36 AM9/10/14
to ncqr...@googlegroups.com
Can you elaborate on "event versioning"?  I have not read that book (and don't have it).  If you are referring to the process by which you upgrade your events based on breaking changes to your aggregate root, there really isn't a process like that that would work for snapshots.  You just delete the snapshots and the next time an event is applied to the domain object, the snapshot will be recreated.

@yreynhout

unread,
Sep 10, 2014, 2:06:17 PM9/10/14
to ncqr...@googlegroups.com
Well, there may not be one in NCQRS, but one could follow a similar approach. Though - in all honesty - the virtue of such an endeavor could be summed up as "painful". After all, what data are you going to base this "upgrade" on? What may be more plausible is having a snapshot v1 & v2 live side by side and selectively loading the one that makes sense or ignoring the one that doesn't make sense, but then we're slowly venturing into having 0 downtime with eventsourcing, a land from which few returned without scars (I'm kidding).

Greg Young

unread,
Sep 10, 2014, 4:41:44 PM9/10/14
to ncqr...@googlegroups.com
This can be a VERY expensive operation. Snapshots are evil in many regards from an agility perspective and should only be used if actually needed
Studying for the Turing test

Adam Greene

unread,
Sep 10, 2014, 10:52:40 PM9/10/14
to ncqr...@googlegroups.com
They may be evil from an agility perspective, but they can make a big difference from a performance stand point in a system that has a lot of events per aggregate.

Greg Young

unread,
Sep 11, 2014, 8:02:00 AM9/11/14
to ncqr...@googlegroups.com
Yes and should be avoided if at all possible. Dev costs often outweigh performance benefits 

On a single server it's better to just use an identity map usually

Adam Greene

unread,
Sep 11, 2014, 11:30:36 AM9/11/14
to ncqr...@googlegroups.com
Just as an aside.  The stock NCQRS.DynamicSnapshot, I would agree the benefits are not that great.  My modified version of DynamicSnapshot I'm working on is 10x faster (600 aggregates loaded/sec to 6000 aggregates loaded/sec), so in a system under heavy load, it is noticeable.
Reply all
Reply to author
Forward
0 new messages