Btw what is "complexity" of public behavior vs method for changing state? I do this normally even if not using event sourcing.
Well of course you can do that but then you are not really event sourcing. You have no guarantee your events could rebuild your domain and lose much of the advantages that ES provides.
That said if those things do not matter then sure use domain state storage. Personally I don't think having to change state in apply that onerous but every implementation and requirement is different.
Btw what is "complexity" of public behavior vs method for changing state? I do this normally even if not using event sourcing.
I think you misunderstand me. I change the structure of my model very often. (move objects around, introduce value object, etc). Replaying events this is a trivial change (just change app,y method), If I have structure then I need to migrate all of the structure.
On Sat, Aug 18, 2012 at 8:32 PM, Greg Young <gregor...@gmail.com> wrote:
Btw what is "complexity" of public behavior vs method for changing state? I do this normally even if not using event sourcing.
I fully agree that changing state "internally" compared to through setters is the better approach, no disagreement here.Could you explain the point where you brought up complexity then? Maybe I am not understanding you properly.
Hi Benjamin,
from my experience, the "complex" part of event sourcing was *only* getting used to it as opposed to data-centric thinking.
For me, the advantages soon outbalanced the initial learning. Any kind of snapshotting, I would strongly advise against unless you determine by performance monitoring that you really need it. Usually it is extra trouble and not worth the effort. Even on the read side, I often drop any kind of persistence and go for in-memory read models, which are regenerated from event store on server startup each time. This does not work for each read model, but in particular for the more complex ones (complex state derivation rather than big data) this works extremely well. Even for a few million events this does not take longer that starting up any kind of tomcat-based jvm server ;)
The event + state persistence idea does never work out as you have two independent representations of you data to cope with.
It might look nice initially but becomes a maintenance nightmare soon afterwards.
Regarding your "apply-method" problem, I initially used a pattern to enforce correct implementation: each entity had only methods that could raise events plus one instance of an state co-class that only handled events and offered its state as "get private set" for it's host class.
E.g. pseudo-code:
public class Customer {
private readonly CustomerState State;
public DoSomething(){
if (!State.Done) EmitDidSomething();
}
class CustomerState {
public bool Done { get; private set; }
internal void OnDidSomething(... e){
Done=true;
}
}
}
+ a bit of connecting code.
While this pattern is a bit of extra code, it solves the mutate-state-by-accident problem.
Additionally, it soon led to the logic of "OnDidSomething" to be refactored into an external method which is now shared by projections and the domain - I call this a "concept" on the event stream. IMO a good application of DRY, avoiding out-of-sync bugs between domain projection logic and readmodel projection logic. Whereever concepts are shared, there is only one pice of code responsible for defining the concept.
Hth,
Yves.
Have you actually benchmarked perf difference? Something tells me your network hit etc will be much larger than the time to replay 10 events.
Snapshot ting introduces its own issues (like now needing two ways of everything). Snapshot ting should be avoided unless needed for performance.
My approach would now be, for every unit of work:
1. save a snapshot of the state into couchdb
2. save all events into a commit document into couchdb
I've skimmed through this thread and it sounds to me like the reason you're making an argument for a "snapshot" over storing events is due to the fact that you are using snapshots for your query/read side. If this is the case then I think you're either making the wrong argument or the argument hasn't been clear. For the read side that what you are saying would make sense, but it would also make sense to have a differently shaped snapshot for each view within your read side. These shapshots/projections are completely different concepts than your storage mechanism for your writes. I've never heard of anybody making an argument for using an event store for a read model so what you're saying can apply to your read side but not the write.
Three approaches with different "problems and drawbacks" are possible:
1. make the snapshot/aggregate the primary source of data, explicitly allowing for "missing" events. Drawback: Event replay for view rebuilding might be inconsistent.
2. Save snapshot AND events into one document - storage space
3. save the events first, then using a single query retrieve snapshot + missing events and apply them. - complexity+performance (requires a View and not a find by key operation)