GithubHelp home page GithubHelp logo

m-r's People

Contributors

abenedykt avatar ceg-ecoles avatar chrissimmons avatar gautema avatar gregoryyoung avatar joachim127 avatar mklinke avatar synthomat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

m-r's Issues

Clearing uncommitted changes

Hi, thanks for this nice work.
I have a question : when are the uncommited changes of the aggregate cleared ?

Regarding the class naming convention

This is regarding the class naming convention of "BullShitDatabase" that it's being used in ReadModel.cs. It seems to be odd and rude. Better to rename it to something like FakeDatabase or MockDatabase.

AggregateRoot version never updated

It loos like the AggregateRoot Version field is never updated. It should probably be updated at the end of the LoadsFromHistory method (which should probably be renamed LoadFromHistory), with the version of the last event replayed.

Add LICENSE to repository

It would be helpful to explicitly know what the license is for this repository.

For instance - can I fork and refactor for training purposes?

Why do commands include the entity id when creating entities?

I'm curious and I think I know the answer to my own question but I wanted to confirm this. In the example command handler, the "CreateInventoryItem" command includes the InventoryItemId which is used by the aggregate as its identity:

https://github.com/gregoryyoung/m-r/blob/master/SimpleCQRS/CommandHandlers.cs#L16

The reason of doing this, is this because that all commands should pass data that is required to create an entity? Before, I have used immutable value objects for entity ids. I guess my question is: "Who creates an aggregate's Id when using CQRS and DDD?" Before, my entities were generating their own Ids (as value objects).

I can see the advantage of passing an id with a command when that command's execution will create a domain entity because I could replay commands if I would persist these commands and assuming all commands pass required information with them.

What are you thoughts?

About FakeBus sample implementation and contracts for the registration

Even though I know this should be seen as a demonstration for learning CQRS and is just the most simplest implementation... I have seen people jump onto this horse and start to ride. Because of this I wan't to take a note on the implementation of Command, Event, FakeBus and the registration of a handler.

Both Command and Event share the same base class Message here. I don't think you should go this path, especially when looking at the registration.
There are two different contracts for Command registration and Event registration.

  • You can publish to multiple (Event)handlers,
  • but you are not allowed to send a Command to multiple (Command)handlers, there can be only one.

You will notice this here in the FakeBus implementation:

public void Send<T>(T command) where T : Command
{
    List<Action<Message>> handlers;

    if (_routes.TryGetValue(typeof(T), out handlers))
    {
    if (handlers.Count != 1)  // look at this, only 1 handler allowed
        throw new InvalidOperationException("cannot send to more than one handler");
    handlers[0](command);
    }
    else
    {
        throw new InvalidOperationException("no handler registered");
    }
}

... on the other hand the Publish method does not have such a restriction.

But using the RegisterHandler<T>(Action<T> handler) where T : Message method you were already able to register as much as Command handlers for the same Command as you want:

public void RegisterHandler<T>(Action<T> handler) where T : Message
{
    List<Action<Message>> handlers;

    if(!_routes.TryGetValue(typeof(T), out handlers))
    {
        handlers = new List<Action<Message>>();
        _routes.Add(typeof(T), handlers);
    }

        // no rules applied to check and fail early when trying to register 2nd Command handler
    handlers.Add((x => handler((T)x)));
}

Because of this, the RegisterHandler<T>(Action<T> handler) where T : Message should be really something like RegisterEventHandler<T>(Action<T> handler) where T : Event and RegisterCommandHandler<T>(Action<T> handler) where T : Command.
This way you are able to express and check the required rules earlier in the registration process (e.g. throw Exception during startup instead of running a long time with a hidden bug).

I would not even make Command and Event inherit from a shared base class at this point (any reasons to give?). The implemented FakeBus itself might be capable of transport both and might be the same instance. Greg already created two different interfaces, ICommandSender and IEventPublisher so you are able to keep them in separate implementations that wrap a common transport bus.

Should configuration settings be eventsourced?

In an application that I'm trying to develop there are a lot of configuration settings that are user configurable.

Should these type of settings be part of eventsource? Should they be stored in separate db? or read db directly?

What is the semantic of the Version property in the Event class ?

Hi @gregoryyoung ,

could you please explain what is the intended semantic of the Version property in the Event class ?

Is it meant to be the version of the aggregate at the time the event was raised or the version of the aggregate obtained after the event is applied to the aggregate ?

Here is an example to summarize my doubt.

Let's imagine of having an aggregate currently at version 5 materialized from the event store. Then, we issue a command to the aggregate and an event is raised so that, after applying the event to the aggregate state, the new aggregate version is 6.
In such a scenario, do you expect @event.Version = 5 or @event.Version = 6 ? Based on my understanding, it should be @event.Version = 6. Is it correct ?

Thanks for the clarification.

Enrico

How to implement business rules?

I'm wondering how to implement business rule depends on entity current state. For example: "You can change the name of the InventoryItem only if new name is longer".

Missing Version parameter in Details view

Please change the Deactivate link in Details.aspx to:

<%: Html.ActionLink("Deactivate","Deactivate",new{Id=Model.Id, Version=Model.Version}) %>

(current version does not pass Version but controller expects it)

Extraneous properties (and even class)?

I'm curious about a few things:

  • It does not appear that AggregateRoot.Version serves any purpose. While I've seen Version used actively on the aggregate in many examples (books, articles) on ES, in this case it seems extraneous. Is this just serving as an example that a non-trivial real-world app would likely have a Version property on the aggregate?
  • Similarly, it appears that EventStore.EventDescriptor.Id serves no purpose. If you take that as true, EventStore.EventDescriptor as whole seems to have no purpose as it only has Version, which Event already has. Again, is this just an illustration that a real-world ES app would have a "wrapper" like this around Event? I know that NEventStore has the EventMessage class that serves as a similar wrapper concept.

Race between event handlers and read model facade after commands

In case anyone's wondering, there are races between event handlers and the read model facade after commands are issued. This is due to the use of ThreadPool.QueueUserWorkItem in FakeBus.Publish.

You can test one for example by creating a new item and freezing one of the threads handling the InventoryItemCreated event (simulating a long database request); the resulting view will not display the item you just created.

Note that this is no eventual consistency matter.

This shouldn't impact the overall architecture which is the point of this project -- just pointing this out so that nobody embarks on a journey looking for magic and finding bugs instead.

CQRS and CRUD misconception

There are many articles and videos like "CQRS vs CRUD". They're not even the same things. Because you can use CQRS with CRUD (for example, CreateCommand, UpdateCommand, DeleteCommand) and mostly all applications are CRUD. Can you clarify?

Is implementing CRUD using CQRS misusing CQRS?

Is CQRS suitable for implementing REST/resource-based APIs with CRUD mental model, or it's a better fit for RPC APIs?

How do you use CQRS with DDD, how do you map to domain models? Do you map directly from your commands to domain models? Or do you use commands just as DTO holders? see https://stackoverflow.com/questions/50908260/cqrs-with-mediatr-and-re-usability-of-commands

Event is mutable

This makes Event a mutable type.

public class Event : Message
{
    public int Version;
}

I think Commands and Events should be immutable instead.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.