Comments (5)
Yes, let's talk about this. Thanks for opening the issue.
from eventsourcing.
Hi Alex,
Sorry it's taken me a while to find a good answer to this question. It seems to me, at the moment at least, that one way to resolve this concern is to say the following:
Firstly, it would be an error to have stored events in an event store that have no corresponding domain object class in the code. So if the domain model code is changed, then it should be changed in such a way that events generated and stored by a previous version of the code are still working.
Secondly, it follows that if the domain model code is changed so that there would be stored events that will no longer work, then the stored events should be migrated so that whatever stored events there are do have corresponding domain object classes.
Thirdly, it follows that if we want never to migrate stored events, then we must restrict the changes we make to domain model code to be strictly additive. We can add a new aggregate and have it trigger new events, and expect existing aggregates to work just fine. We can add a new command to an existing aggregate and have it trigger new events, and expect existing events from an existing commands to continue to work. Similarly, we can replace the events of an existing command with new events, and expect existing events will continue to work, so long as the old event class is not removed. Furthermore, we can add new attributes to an existing event, so long as we provide default values to supplement the state of existing stored events. If this results over time in a lot of clutter, then it would be possible to reduce the clutter by migrating stored events and removing old classes from the code.
If you feel that these considerations do not resolve the concern, please reopen this issue. :-)
All good wishes,
John
from eventsourcing.
Hi John,
Thanks for the detailed comment.
I am actually looking to implement "strictly additive changes" along with a "insert only data storage" and as such I need to be able to execute potentially different actions for the existing stored event (while doing reconstruction) depending on the desired point in time (system version).
So all events will have a corresponding domains, potentially even more than one. If no point in time has been specified, then everything works as does now - the most recent (default) domain is used for an event. So far so good.
If a point in time is specified, then the "dispatcher" that links domains to stored events will use a domain that was the "most recent (default)" at that time (system version).
Point in time could be the actual point in time or just a version of the system.
This gives the ability to see the whole system state as it was at a specific time (version of the system) and allows for changes/fixes to the domains (code) to be implemented by strict "addition" of a new domain (version of domain).
Ideally I would like for all code to be present in the system and changes to be made by adding new code (classes, modules). So the existing events may trigger new actions added later. This is conceptually similar to Windows "Side-by-Side assemblies" (to certain extent).
In the current "eventsourcing" implementation each event can invoke only one predefined class (class name is actually stored in the event itself) and to change the actions performed for a particular event, this class must be changed. Once this done, old class is no longer available. If the new aggregate (class) is defined, it will not consume "old" events due to the different class path.
There are ways around this, but not exactly elegant or explicitly provided by this library, which is pity for the otherwise an impressive library.
The immediate solution that comes to mind is to implement a configurable "dispatcher factory" that is solely responsible for providing "topic" (class path) for given domain and linking an event to a class (domain) which can be defined/customized (bidirectional link "event" <-> "class"). A default one will just use the existing logic, once extended it can invoke different/descendant classes.
Thanks.
Regards,
Alex.
from eventsourcing.
Yes it would be useful to make a TopicStrategy that can be replaced. You could, in the meantime, provide your own implementation of get_topic
and resolve_topic
(eventsourcing.utils.topic
). Just be careful to either patch that module before it is imported by other things in the library. Or if you do it later than that, then make sure also to set your functions in the library modules that use those functions (eventsourcing.domain.model.entity
, eventsourcing.domain.model.events
, eventsourcing.utils.transcoding
, eventsourcing.infrastructure.sequenceditemmapper
).
from eventsourcing.
@alexyarmoshko I just made some changes (35288f6) which allow new topics to be substituted for old ones. When a topic is resolved, the dict eventsourcing.utils.topic.substitutions
is consulted. So if you set a key as old topic with the new topic as the value, then you can move and rename domain classes and still read old events. Let me know if you think that's helpful at all?
from eventsourcing.
Related Issues (20)
- Question: how to make domain event listener without making another aggregate HOT 2
- MongoDB EventStore support. HOT 2
- Question: Any intention to extend/fork this library to async? HOT 7
- Postgres does not accept idle_in_transaction_session_timeout as float string HOT 2
- Postgres schema change possibility HOT 5
- Investigating potential problem when saving events for multiple aggregates HOT 2
- Custom Postgres schema breaks followers HOT 3
- Aggregate Not Found when AGGREGATE_CACHE_MAXSIZE not set HOT 13
- monotonic HOT 2
- support postgresql as alias for postgres persistence module HOT 3
- Support for rabbitmq HOT 10
- Best way to befriend sqlalchemy database and eventsourcing HOT 6
- Is it necessary to re-hydrate an aggregate to check it exists in a repository? HOT 4
- Suggested approach to Entities in 9.x? HOT 1
- Slack invite not working HOT 3
- Snapshot in aggregate8 example won't work for custom object in aggregate HOT 8
- `Follower(Application)` does not call `self.construct_mapper()` HOT 5
- Additional examples HOT 2
- How to set aggregate/application state for tests? HOT 1
- Automatic snapshotting not work for functional style aggregate HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from eventsourcing.