All Projects → aneshas → tactical-ddd

aneshas / tactical-ddd

Licence: Apache-2.0 license
lightweight helpers that I find myself implementing over and over again related to DDD/Event Sourcing tactical patterns, such as Value Objects, Entities, AggregateRoots, EntityIds etc...

Programming Languages

C#
18002 projects

Projects that are alternatives of or similar to tactical-ddd

Event Sourcing Jambo
An Hexagonal Architecture with DDD + Aggregates + Event Sourcing using .NET Core, Kafka e MongoDB (Blog Engine)
Stars: ✭ 159 (+381.82%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Eventhorizon
CQRS/ES toolkit for Go
Stars: ✭ 961 (+2812.12%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Eventsourcing
A library for event sourcing in Python.
Stars: ✭ 760 (+2203.03%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Dotnet New Caju
Learn Clean Architecture with .NET Core 3.0 🔥
Stars: ✭ 228 (+590.91%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Kreta
Modern project management solution
Stars: ✭ 177 (+436.36%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Akkatecture
a cqrs and event sourcing framework for dotnet core using akka.net
Stars: ✭ 414 (+1154.55%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Revo
Event Sourcing, CQRS and DDD framework for C#/.NET Core.
Stars: ✭ 162 (+390.91%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
eventuous
Minimalistic Event Sourcing library for .NET
Stars: ✭ 236 (+615.15%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Productcontext Eventsourcing
A practical/experimental Event Sourcing application on Product Bounded Context in an e-commerce
Stars: ✭ 88 (+166.67%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Typescript Event Sourcing
Domain Driven Design, Event Sourcing & Command Query Responsibility Segregation with Typescript
Stars: ✭ 83 (+151.52%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Goes
Go Event Sourcing made easy
Stars: ✭ 144 (+336.36%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Eventflow.example
DDD+CQRS+Event-sourcing examples using EventFlow following CQRS-ES architecture. It is configured with RabbitMQ, MongoDB(Snapshot store), PostgreSQL(Read store), EventStore(GES). It's targeted to .Net Core 2.2 and include docker compose file.
Stars: ✭ 131 (+296.97%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Event Sourcing Cqrs Examples
Event Sourcing and CQRS in practice.
Stars: ✭ 265 (+703.03%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Modular Monolith With Ddd
Full Modular Monolith application with Domain-Driven Design approach.
Stars: ✭ 6,210 (+18718.18%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
delta
DDD-centric event-sourcing library for the JVM
Stars: ✭ 15 (-54.55%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Rails event store
A Ruby implementation of an Event Store based on Active Record
Stars: ✭ 947 (+2769.7%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
EcommerceDDD
Experimental full-stack application using Domain-Driven Design, CQRS, and Event Sourcing.
Stars: ✭ 178 (+439.39%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
e-shop
Sample Spring Cloud microservices e-shop.
Stars: ✭ 48 (+45.45%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Event Sourcing Castanha
An Event Sourcing service template with DDD, TDD and SOLID. It has High Cohesion and Loose Coupling, it's a good start for your next Microservice application.
Stars: ✭ 68 (+106.06%)
Mutual labels:  ddd, domain-driven-design, event-sourcing
Bifrost
This is the stable release of Dolittle till its out of alpha->beta stages
Stars: ✭ 111 (+236.36%)
Mutual labels:  ddd, domain-driven-design, event-sourcing

Tactical DDD Helpers

Build Status Build status

Install-Package TacticalDDD

TacticalDDD contains lightweight helpers that I find myself implementing over and over again related to DDD/Event Sourcing tactical patterns, such as Value Objects, Entities, AggregateRoots, EntityIds etc..

These helpers are mostly in the form of simple abstractions that provide help around equality and contain useful helper methods...

5.0.0 Breaking changes

Heads up. I did a major refactor and there are a lot of breaking changes plus the package now depends on .NET 5 and uses C# 9.

Version 1.0.32 is the last version that supported C# 7 and .NET Standard

Reasoning behind this package

I am a big proponent of "Little copy is better than a little dependency" mantra, but I also believe there exists a small set of facts that should always be true when implementing DDD patterns. Keeping this in mind I did (and will) try to keep this package as thin and as pragmatic as possible.

Note: I assume that you are well versed in these topics.

1. There is almost always a notion of an Entity

Entity is something that has an Identity (Id), and thus this dictates Entity equality implementation, eg. an entity is equal to another entity if their Id's are equal. This is exactly what Entity abstract class provides: An Id and equality implementations.

2. What is an id

EntityId is something that has to be serializable to string eg. it needs to implement ToString() method. I provided a helper record for you to use, named EntityId. It extends record instead of a class which means that it provides structural equality (more on value object below).

An example of Entity and an Entity Id:

public sealed record CustomerId : EntityId
{
    private Guid _guid;

    private CustomerId(string guid) => 
        Guid.Parse(guid);

    public CustomerId() =>
        _guid = Guid.NewGuid();

    // You might implement this static factory method in order to be able to
    // parse your id from string
    public static CustomerId Parse(string id) => new(id);

    // ToString implementation
    public override string ToString() => _guid.ToString();
}
public sealed class Customer : Entity<CustomerId>
{

}

This is how you would define an entity along with it's id.

What this tries to enforce is that your entities always have an id and that the id is a value object (avoiding primitive obsession). I will not go into much

details why this is useful.

3. AggregateRoots and Domain Events

Like you may already know aggregate root is an entity that sits on top of an aggregate tree. So in my implementation this is what it is. AggregateRoot extends Entity and provides same identity utilities.

One extra thing an AggregateRoot has is ability to deal with domain events, eg. it provides a public readonly collection of domain events and some protected methods to manage that collection.

In previous versions I had a separate AggregateRoot implementation that contained utility methods for an event sourced aggregate. In retrospect I think this was a bit confusing and redundant so in version 5.0.0 I decided to merge those two.

So for example if you decided that your Customer entity is in fact an aggregate, this is how you would implement it as an AggregateRoot:

public sealed class Customer : AggregateRoot<CustomerId>
{

}

Here is an example of an event sourced Customer aggregate:

public sealed class Customer : AggregateRoot<CustomerId>
{
    // We re-export constructor provided by our AggregateRoot implementation
    // which is used to rehydrate our aggregate from domain events
    public Customer(IEnumerable<DomainEvent> events) : base(events)
    {
    }

    // We want to encapsulate and thus hide parameterless constructor 
    private Customer()
    {
    }

    // Use case method
    // (newName would preferably be value object in itself instead of a primitive type
    public void ChangeNameTo(string newName)
    {
        Apply(
            new CustomerChangedName
            {
                CreatedAt = DateTime.UtcNow, // Don't do this
                CustomerId = Id, // Notice how CustomerId is implicitly convertible to string
                NewName = newName
            }
        );
    }

    // This method is automagically called when we Apply a domain event and also
    // if we instantiate our aggregate via `public Customer(IEnumerable<IDomainEvent> events)`
    public void On(CustomerChangedName @event)
    {
        // ... implement the actual mutation 
    }
}

// Our domain event
public sealed record CustomerChangedName : DomainEvent
{
    public string CustomerId { get; init; }

    public string NewName { get; init; }
}

4. Value Objects

Last but not least. Value objects imho are the most valuable pattern.

Prior to 5.0.0 this package contained ValueObject abstract class that helped with structural equality. With C# 9 this is no longer necessary so I ditched it.

Records pretty much provide you with all that is needed to create your own value objects. All you need to do is to provide your own constraints, mostly during creation / parsing.

With ValueObject being out of the picture, I did add another helper record named ConstrainedValue which provides a neat way of wrapping primitive types and adding simple constraints via built in data annotations in order to avoid primitive obsession.

An example usage of ConstrainedValue:

// We create a simple wrapper for our string that enforces
// string length. Second generic parameter enforces the type of exception
// thrown if validation fails.
public sealed record String10 : ConstrainedValue<string, DomainException>
{
    public String10(
        [MinLength(5)]
        [MaxLength(10)] string value) : base(value)
    {
    }
}

// Now our Name value object can simply be defined as:
public sealed record Name(String10 FirstName, String10 LastName);
// Value itself can simply be used as
var value = new String10("A value");

// And is implicitly assignable to it's generic type (in this case a string)
string val = value;

You can and should use ConstrainedValue in order to create simple wrappers around primitive types eg String50, PositiveInt, FutureDate etc... which contain simple constraints and which you then can compose into more complex value objects (records)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].