meteor-space / event-sourcing

CQRS and Event Sourcing Infrastructure for Meteor.
MIT License
63 stars 9 forks source link

Basic implementation example #1

Closed rhyslbw closed 9 years ago

rhyslbw commented 9 years ago

Hello,

Do you have an example you could post or link to a bare bones implementation?

DominikGuzei commented 9 years ago

Hey there! A very contrived and bare bones example is the integration test for this package.

But of course, this package mostly makes sense for more complex business domains which are hard to show in a small contrived example :wink:

To give you a basic overview:

space-cqrs is a very simple implementation of a (non-distributed) version of the DDD + CQRS + Event Sourcing patterns. It provides a base class for event-sourced Aggregates and ProcessManagers as well as serializable ValueObjects to model your business domain. It is not a full-blown CQRS framework with a distributed messaging service bus etc. but tries to keep everything as simple as possible and only supports messaging per-process.

It also provides a (currently) extremely basic implementation of a MongoDB based EventStore which works a little bit different than "normal" event store implementations because MongoDB doesn't support transactions. To circumvent this downside of MongoDB space-cqrs uses the concept of a commit which bundles multiple events and commands together into one "transaction" commit. Here is a short blog article talking about the basic concept.

It heavily uses the space-messaging package for Meter EJSON and runtime-checked domain events and commands that are automatically serialized into the MongoDB and restored for you. So you don't have to deal with serialization concerns anywhere but within your value objects.

My plan is to write more about all these topics as soon as I get a little bit more spare time beside my current project Prisma, at the moment there is a lot todo for the launch on 1st of April :wink:

Maybe you could tell me a little bit more about your background with these topics?

withinboredom commented 9 years ago

Hi, I'm interested in this as well. I've implemented pretty large CQRS implementations in C#, and am looking for a good js implementation. The service bus isn't important, but this looks like a pretty nice implementation. Any chance you could go over your integration test in "literate coffeescript"? While its pretty clear what's going on, it takes some experimenting to get things right when actually implementing it.

rhyslbw commented 9 years ago

Thanks for the overview @DominikGuzei. Your response would be great to integrate into the existing readme, as is does fill in the gaps nicely. I understand it's one of those situations, but I guess a small example application to neatly demonstrate the setup with a folder structure that you would likely see in say the smallest projects of this nature would be a good reference. I found the demo app in the UI package, so maybe that can be extended to include the CQRS and EventSourcing elements, even though it's overkill in a real-world scenario. Like @withinboredom mentioned, maybe some comments in the integration test would also help.

DominikGuzei commented 9 years ago

Hey guys, thanks for your feedback – I guess you're right, this package needs some small real-world example that shows the interaction of client / server with real value objects and event-sourced aggregates etc. The problem with the integration test is, that it only shows a pure server-side app.

I will think about the best way to add something :wink:

rhyslbw commented 9 years ago

:+1: Spot on

rhyslbw commented 9 years ago

Also regarding:

It is not a full-blown CQRS framework with a distributed messaging service bus etc. but tries to keep everything as simple as possible and only supports messaging per-process."

Do you think meteorhacks:cluster could help with establishing DDP-based distributed messaging via RPCs?

withinboredom commented 9 years ago

@rhyslbw I would suggest using a truly distributed messaging system like Amazon SQS or Azure ServiceBus. That way you don't have to rewrite the wheel and handle guaranteed once delivery, deduplication, dead letter queues, etc.

DominikGuzei commented 9 years ago

Yeah, as @withinboredom said I would also go with something really stable and well known for this functionality. Distributed messaging is non-trivial and there is a little bit more to it than "just" sending messages between servers :wink:

That's also the reason why this package doesn't include this functionality. I try to avoid distributed architectures as much as possible, its a lot of complexity added to your system and you really need to be sure that you can handle the trade-offs. Also CQRS is not about distributed systems, its just a simple pattern to model your read and write model separately to optimize the read for the UI and the write for business logic. Although this package promotes event-sourcing for your write side, it is actually not necessary for CQRS.

rhyslbw commented 9 years ago

Thanks guys, understood.

I'm working through the space-ui sample app, and it does seem to be an ideal base to fork and enhance with the clear notice indicating this is just to demonstrate the concepts of CQRS and Event Sourcing.

If you could give me a quick paragraph on how you manage projections I'll leave you alone to get your product launched! :smile:

DominikGuzei commented 9 years ago

Hey @rhyslbw this is the easiest part! Just extend Space.messaging.Controller and handle the events: (This is a simple contrived example for an order system)

class OrdersProjection extends Space.messaging.Controller

  Dependencies:
    orders: 'Orders' # Your mapped orders collection (this is not default -> change for your case!)

  @on OrderCreated, (event) -> @orders.insert
    _id: event.sourceId # All events have a sourceId which is the id of the aggregate they belong to
    version: event.version # All events have a version with event-sourcing
    status: Order.STATES.created # Implementation detail
    product: event.productId
    quantity: event.quantity
    # etc ...

  @on OrderCompleted, (event) -> @orders.update event.sourceId, $set:
    version: event.version # All events have a version with event-sourcing
    status: Order.STATES.completed # Implementation detail
    # etc ...
rhyslbw commented 9 years ago

Ah right I see it's similar to the ViewModel example now in the integration test, thanks. I'll definitely have more questions, but in the attempt to keep this thread on track, I'll post separate topics as new issues.

rhyslbw commented 9 years ago

Ok I'm going to close this as I agree that a sample application or "basic implementation example" is just not practical.