Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmus committed Sep 4, 2015
2 parents f2d58ac + 4e57c4d commit cbb45fa
Show file tree
Hide file tree
Showing 138 changed files with 2,007 additions and 422 deletions.
147 changes: 147 additions & 0 deletions Documentation/Commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Commands

Commands are the basic value objects, or models, that represent write operations
that you can perform in your domain.

As an example, one might implement create this command for updating user
passwords.

```csharp
public class UserUpdatePasswordCommand : Command<UserAggregate, UserId>
{
public Password NewPassword { get; private set; }
public Password OldPassword { get; private set; }

public UserUpdatePasswordCommand(
UserId id,
Password newPassword,
Password oldPassword)
: base(id)
{
Username = username;
Password = password;
}
}
```

Note that the `Password` class is merely a value object created to hold the
password and do basic validation. Read the article regarding
[value objects](./ValueObjects.md) for more information. Also, you don't
have to use the default EventFlow `Command<,>` implementation, you can create
your own, it merely have to implement the `ICommand<,>` interface.

A command by itself doesn't do anything and will throw an exception if
published. To make a command work, you need to implement one (and only one)
command handler which is responsible for invoking the aggregate.

```csharp
public class UserUpdatePasswordCommandHandler :
CommandHandler<UserAggregate, UserId, UserUpdatePasswordCommand>
{
public override Task ExecuteAsync(
UserAggregate aggregate,
UserUpdatePasswordCommand command,
CancellationToken cancellationToken)
{
aggregate.UpdatePassword(
command.OldPassword,
command.NewPassword);
return Task.FromResult(0);
}
}
```

## Ensure idempotency

Detecting duplicate operations can be hard, especially if you have a
distributed application, or simply a web application. Consider the following
simplified scenario.

1. The user wants to change his password
1. The user fills in the "change password form"
1. As user is impatient, or by accident, the user submits the for twice
1. The first web request completes and the password is changed. However, as
the browser is waiting on the first web request, this result is ignored
1. The second web request throws a domain error as the "old password" doesn't
match as the current password has already been changed
1. The user is presented with a error on the web page

Handling this is simple, merely ensure that the aggregate is idempotent
is regards to password changes. But instead of implementing this yourself,
EventFlow has support for it and its simple to utilize and is done per
command.

To use the functionality, merely ensure that commands that represent the
same operation has the same `ISourceId` which implements `IIdentity` like
the example blow.

```csharp
public class UserUpdatePasswordCommand : Command<UserAggregate, UserId>
{
public Password NewPassword { get; private set; }
public Password OldPassword { get; private set; }

public UserCreateCommand(
UserId id,
ISourceId sourceId,
Password newPassword,
Password oldPassword)
: base(id, sourceId)
{
Username = username;
Password = password;
}
}
```

Note the use of the other `protected` constructor of `Command<,>` that
takes a `ISourceId` in addition to the aggregate root identity.

If a duplicate command is detected, a `DuplicateOperationException` is thrown.
The application could then ignore the exception or report the problem to the
end user.

The default `ISourceId` history size of the aggregate root, is ten. But it can
be configured using the `SetSourceIdHistory(...)` that must be called from
within the aggregate root constructor.


### Easier ISourceId calculation

Ensuring the correct calculation of the command `ISourceId` can be somewhat
cumbersome, which is why EventFlow provides another base command you can use,
the `DistinctCommand<,>`. By using the `DistinctCommand<,>` you merely have
to implement the `GetSourceIdComponents()` and providing the
`IEnumerable<byte[]>` that makes the command unique. The bytes is used to
create a deterministic GUID to be used as an `ISourceId`.

```csharp
public class UserUpdatePasswordCommand :
DistinctCommand<UserAggregate, UserId>
{
public Password NewPassword { get; private set; }
public Password OldPassword { get; private set; }

public UserUpdatePasswordCommand(
UserId id,
Password newPassword,
Password oldPassword)
: base(id)
{
Username = username;
Password = password;
}

protected override IEnumerable<byte[]> GetSourceIdComponents()
{
yield return NewPassword.GetBytes();
yield return OldPassword.GetBytes();
}
}
```

The `GetBytes()` merely returns the `Encoding.UTF8.GetBytes(...)` of the
password.

Its important that you don't use the `GetHashCode()`, as the implementation
is different for e.g. `string` on 32 bit and 64 bit .NET.
25 changes: 16 additions & 9 deletions Documentation/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Implementation notes
* Make sure to read the comments about how this code should be improved at
the bottom


## Create an aggregate

Initially you need to create the object representing the _identity_
Expand All @@ -21,16 +22,14 @@ started.
```csharp
public class UserId : Identity<UserId>
{
public UserId(string value) : base(value)
{
}
public UserId(string value) : base(value) { }
}
```

Next, let us start by creating a aggregate to represent our users.

```csharp
public class UserAggregate : AggregateRoot<UserAggregate>
public class UserAggregate : AggregateRoot<UserAggregate, UserId>
{
public UserAggregate(UserId id)
: base(id)
Expand All @@ -39,10 +38,11 @@ public class UserAggregate : AggregateRoot<UserAggregate>
}
```


## Create event

```csharp
public class UserCreatedEvent : AggregateEvent<UserAggregate>
public class UserCreatedEvent : AggregateEvent<UserAggregate, UserId>
{
public string Username { get; private set; }
public string Password { get; private set; }
Expand All @@ -63,6 +63,7 @@ Important notes regarding events
emitted a event, you should never change it. You can deprecate
it, but you should never change the data stored in the event store


## Update aggregate

We update our aggregate by creating a new method called `Create(...)` that
Expand Down Expand Up @@ -113,14 +114,15 @@ public class UserAggregate : AggregateRoot<UserAggregate, UserId>,
}
```


## Create command

Even though it is possible, we are not allowed to call the newly
created `Create` method on our `UserAggregate`. The call must be
made from a command handler, and thus we first create the command.

```csharp
public class UserCreateCommand : Command<UserAggregate>
public class UserCreateCommand : Command<UserAggregate, UserId>
{
public string Username { get; private set; }
public string Password { get; private set; }
Expand All @@ -137,13 +139,18 @@ public class UserCreateCommand : Command<UserAggregate>
}
```

Note that you can read the article regarding [commands](./Commands.md) for
more details, e.g. on ensuring idempotency in a distributed application.


## Create command handler

Next we create the command handler that invokes the aggregate with the command
arguments.

```csharp
public class UserCreateCommand : ICommand<UserAggregate, UserCreateCommand>
public class UserCreateCommand :
ICommand<UserAggregate, UserId, UserCreateCommand>
{
public Task ExecuteAsync(
UserAggregate aggregate,
Expand Down Expand Up @@ -179,5 +186,5 @@ await _commandBus.PublishAsync(command, cancellationToken);

There are several areas the code can be improved.

- Use value objects for e.g. username and password that validate the value,
i.e., ensure that the username isn't the empty string
- Use [value objects](ValueObjects.md) for e.g. username and password that
validate the value, i.e., ensure that the username isn't the empty string
44 changes: 33 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ the [dos and don'ts](./Documentation/DoesAndDonts.md) and the
Here is a list of the EventFlow concepts. Use the links to navigate
to the documentation.

* [**Aggregates**](./Documentation/Aggregates.md): Domains object
* [**Aggregates:**](./Documentation/Aggregates.md) Domains object
that guarantees the consistency of changes being made within
each aggregate
* **Command bus:** Entry point for all command execution.
* [**Command bus and commands:**](./Documentation/Commands.md)
Entry point for all command/operation execution.
* **Event store:** Storage of the event stream for aggregates.
Currently there is support for these storage types.
* In-memory - only for test
Expand All @@ -44,21 +45,21 @@ to the documentation.
read model storage types.
* In-memory - only for test
* Microsoft SQL Server
* [**Queries:**](./Documentation/Queries.md): Value objects that represent
* [**Queries:**](./Documentation/Queries.md) Value objects that represent
a query without specifying how its executed, that is let to a query handler
* [**Event upgrade:**](./Documentation/EventUpgrade.md): As events committed to
* [**Event upgrade:**](./Documentation/EventUpgrade.md) As events committed to
the event store is never changed, EventFlow uses the concept of event
upgraders to deprecate events and replace them with new during aggregate load.
* **Event publishing:** Sometimes you want other applications or services to
consume and act on domains. For this EventFlow supports event publishing.
* [RabbitMQ](./Documentation/RabbitMQ.md)
* [**Metadata**](./Documentation/Metadata.md):
* [**Metadata:**](./Documentation/Metadata.md)
Additional information for each aggregate event, e.g. the IP of
the user behind the event being emitted. EventFlow ships with
several providers ready to use used.
* [**Value objects**](./Documentation/ValueObjects.md): Data containing classes
* [**Value objects:**](./Documentation/ValueObjects.md) Data containing classes
used to validate and hold domain data, e.g. a username or e-mail.
* [**Customize**](./Documentation/Customize.md): Almost every single part of
* [**Customize:**](./Documentation/Customize.md) Almost every single part of
EventFlow can be swapped with a custom implementation through the embedded
IoC container.

Expand Down Expand Up @@ -105,9 +106,31 @@ EventFlow is greatly opinionated, but its possible to create new implementations
for almost every part of EventFlow by registering a different implementation of a
a interface.

## Useful links

* [CQRS Journey by Microsoft](https://msdn.microsoft.com/en-us/library/jj554200.aspx)
## Useful articles related to EventFlow and DDD

Many of the technical design decisions in EventFlow is based on articles. This
section lists some of them. If you have a link with a relevant article, please
share it by creating an issue with the link.

* **General CQRS+ES**
- [CQRS Journey by Microsoft](https://msdn.microsoft.com/en-us/library/jj554200.aspx)
published by Microsoft
- [An In-Depth Look At CQRS](http://blog.sapiensworks.com/post/2015/09/01/In-Depth-CQRS/)
by Mike Mogosanu
- [CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/)
by Greg Young
- [Busting some CQRS myths](https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/)
by Jimmy Bogard
- [CQRS applied](https://lostechies.com/gabrielschenker/2015/04/12/cqrs-applied/)
by Gabriel Schenker
* **Eventual consistency**
- [How To Ensure Idempotency In An Eventual Consistent DDD/CQRS Application](http://blog.sapiensworks.com/post/2015/08/26/How-To-Ensure-Idempotency/)
by Mike Mogosanu
* **Why _not_ to implement "unit of work" in DDD**
- [Unit Of Work is the new Singleton](http://blog.sapiensworks.com/post/2014/06/04/Unit-Of-Work-is-the-new-Singleton.aspx/)
by Mike Mogosanu
- [The Unit of Work and Transactions In Domain Driven Design](http://blog.sapiensworks.com/post/2015/09/02/DDD-and-UoW/)
by Mike Mogosanu

## License

Expand Down Expand Up @@ -135,4 +158,3 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

45 changes: 44 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,47 @@
### New in 0.11 (not released yet)
### New in 0.12 (not released yet)

* Breaking: Aggregate root no longer have `Aggregate` removed from their
when name, i.e., the metadata property with key `aggregate_name` (or
`MetadataKeys.AggregateName`). If you are dependent on the previous naming,
use the new `AggregateName` attribute and apply it to your aggregates
* Breaking: Moved `Identity<>` and `IIdentity` from the `EventFlow.Aggregates`
namespace to `EventFlow.Core` as the identities are not specific for aggregates
* Breaking: `ICommand.Id` is renamed to `ICommand.AggregateId` to make "room"
for the new `ICommand.SourceId` property. If commands are serialized, then
it _might_ be important verify that the serialization still works. EventFlow
_does not_ serialize commands, so no mitigation is provided. If the
`Command<,>` is used, make sure to use the correct protected constructor
* Breaking: `IEventStore.StoreAsync(...)` now requires an additional
`ISourceId` argument. To create a random one, use `SourceId.New`, but it
should be e.g. the command ID that resulted in the events. Note, this method
isn't typically used by developers
* New: Added `ICommand.SourceId`, which contains the ID of the source. The
default (if your commands inherit from `Command<,>`) will be a new
`CommandId` each time the a `Command<,>` instance is created. You can pass
specific value, merely use the newly added constructor taking the ID.
Alternatively you commands could inherit from the new
`DistinctCommand`, enabling commands with the same state to have the
same `SourceId`
* New: Duplicate commands can be detected using the new `ISourceId`. Read the
EventFlow article regarding commands for more details
* New: Aggregate names can now be configured using the attribute
`AggregateName`. The name can be accessed using the new `IAggregateRoot.Name`
property
* New: Added `Identity<>.NewDeterministic(Guid, string)` enabling creation of
[deterministic GUIDs](http://code.logos.com/blog/2011/04/generating_a_deterministic_guid.html)
* New: Added new metadata key `source_id` (`MetadataKeys.SourceId`) containing
the source ID, typically the ID of the command from which the event
originated
* New: Added new metadata key `event_id` (`MetadataKeys.EventId`) containing a
deterministic ID for the event. Events with the same aggregate sequence
number and from aggregates with the same identity, will have the same event
identity
* Fixed: `Identity<>.With(string)` now throws an `ArgumentException` instead of
a `TargetInvocationException` when passed an invalid identity
* Fixed: Aggregate roots now build the cache of `Apply` methods once, instead
of when the method is requested the first time

### New in 0.11.751 (released 2015-08-24)

* Breaking: `EventFlowOptions.AddDefaults(...)` now also adds event
definitions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using System;
using Autofac;
using EventFlow.Aggregates;
using EventFlow.Configuration;
using EventFlow.Configuration.Registrations;
using EventFlow.Configuration.Registrations.Services;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using System.Threading.Tasks;
using EventFlow.Aggregates;
using EventFlow.Configuration;
using EventFlow.Core;
using EventFlow.EventStores.EventStore.Extensions;
using EventFlow.Extensions;
using EventFlow.MetadataProviders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System.Net;
using EventFlow.Configuration;
using EventFlow.Configuration.Registrations;
using EventFlow.Core;
using EventFlow.Extensions;
Expand Down
Loading

0 comments on commit cbb45fa

Please sign in to comment.