Composition over inheritance

Wednesday, September 14, 2016

I’ve heard this phrase a lot. Said it a couple of times too. Most of the discussions about that subject: I’ve lost. I’ll keep trying though. Let’s compose, shall we.

I had a problem and decided to attack with Command Query Responsibility Separation (CQRS) and Event sourcing. Because CQRS is simpler than pure DDD and we can still use many of the great advantages of DDD for dealing with complex business logic…And I think it’s quite simple once you get the grip of it.

My over-engineered solution

Yes!!! I know: I should never, but instead of fighting the bull for real straight from the beginning, I prefer rehearsing, as much as possible, before going out to the arena.

enter image description here

My command stack contains one method per write operation. Each is very very simple, the actual business logic is implemented in entities (POCOs). Every persistence call is asynchronous.

class ProductCommands {
    private readonly IWriter<Product> writer;
    private readonly Func<CreateProductCommand, Product> createProduct;

    public ProductCommands(IWriter<Product> writer, 
        Func<ProductCreatedCommand, Product> createProduct) {
        this.writer = writer;
        this.createProduct = createProduct;
    }

    public async Task Handle(CreateProductCommand cmd) {
        var product = createProduct(cmd);

        await writer.Save(product);
    }
}

Simple, right? Product are aggregate roots that hold an internal list of modification events. These events are the key for Event sourcing. There are many implementations (look here, here and here):

abstract class AggregateRoot {
    private readonly List<DomainEventBase> uncommittedEvents = 
        new List<DomainEventBase>();
    public IEnumerable<DomainEventBase> UncommittedEvents => 
        uncommittedEvents.AsReadOnly();

    public void ClearUncommittedEvents() {
        uncommittedEvents.Clear();
    }
    //...
}

The aggregates keep events for all changes they have suffered until the events are committed and cleared.

Composition Root

At some point in my application there should be a place where all the instances are created. There, we will do something like:

var productCommands = new ProductCommands(
    NewProductWriter(),
    ProductFactory.Create);

From this point forward we’ll just need to change the way we create writer instances and the whole application will change it’s behavior.

private IWriter<Product> NewProductWriter() => 
    new DocumentStoreWriter<Product>();

For the time being let’s say we have this magical DocumentStoreWriter<T> that takes care of my persistence.

Dealing with events

Every time I save a product, I must also save it’s uncommitted events. This will be my first piece, a Decorator.

enter image description here

In real life this process will be asynchronous. The flow though is not very different.

class WriterEventCommittingDecorator<TEntity>: IWriter<TEntity> {
    private readonly IWriter<TEntity> inner;
    private readonly IEventStorage eventStorage;

    public WriterEventCommittingDecorator(
        IWriter<TEntity> inner, 
        IEventStorage eventStorage) {
        this.inner = inner;
        this.eventStorage = eventStorage;
    }

    public async Task Save(IEnumerable<TEntity> entities) {
        var eagerlyIteratedEntities = entities.ToList();

        var committingTasks = eagerlyIteratedEntities
            .Select(async t => {
                await eventStorage.Save(t.UncommittedEvents);
                t.ClearUncommittedEvents();
            });
        await Task.WhenAll(committingTasks);

        await inner.Save(eagerlyIteratedEntities);
    }
}

My new writer is:

private IWriter<Product> NewProductWriter() => 
    new WriterEventCommittingDecorator<Product>(
        new DocumentStoreWriter<Product>(/*...*/),
        new StandardEventStorage(/*...*/)
    );

Query Dbs

I don’t want (for this particular case) eventual consistency for my query databases, I prefer saving to all of them at once.

enter image description here

Programming this on the ProductCommands will be too cumbersome, not to mention it will not be an extensible solution, and we are very liklely to change the databases very often. This is work for a Composite.

enter image description here

Again, it will be asynchronous.

class CompositeWriter<TEntity>: IWriter<TEntity> {
    private readonly List<IWriter<TEntity>> innerWriters;

    public CompositeWriter(IEnumerable<TEntity> innerWriters) {
        this.innerWriters = innerWriters.ToList();
    }

    public Task Save(IEnumerable<TEntity> entities) {
        var innerSavingTasks = innerWriters.Select(t => t.Save(entities));

        return Task.WhenAll(innerSavingTasks);
    } 
}

My new writer is:

private IWriter<Product> NewProductWriter() => 
    new WriterEventCommittingDecorator<Product>(
        new CompositeWriter<Product>(
            new InitialStateWriter<Product>(/*...*/),
            new CurrentStateWriter<Product>(/*...*/),
            new ProductSearchDbWriter(/*...*/),
            new ProductReportsDbWriter(/*...*/)
        ),
        new StandardEventStorage(/*...*/)
    );

I have also replaced the magic DocumentStoreWriter<T> by the actual writers that will take care of the job.

I am getting close…

One of my use cases is a standalone import that will take lots (hundreds of thousands) of products and save them all, one time each. It’s a batch text book use case. Another decorator will do the trick.

enter image description here

Once more…asynchronous. I will use TPL’s Dataflow for building this one.

class WriterBatchDecorator<TEntity>: IWriter<TEntity> {
    private readonly IWriter<TEntity> inner;
    private readonly BatchBlock<TEntity> batch;

    public WriterBatchDecorator(IWriter<TEntity> inner, int batchSize = 100) {
        this.inner = inner;

        batch = CreateBatchBlock(batchSize);
    }

    private static BatchBlock<TEntity> CreateBatchBlock(int size) {
        var save = new ActionBlock<TEntity[]>(
            entities => inner.Save(entities));

        var batch = new BatchBlock<TEntity>(batchSize);
        batch.LinkTo(save);

        return batch;
    }

    public Task Save(IEnumerable<TEntity> entities) {
        var saveTasks = entities
            .Select(e => batch.SendAsync(e));

        return Task.WhenAll(saveTasks);
    }
}

My new writer is:

private IWriter<Product> NewProductWriter() => 
    new WriterEventCommittingDecorator<Product>(
        new WriterBatchDecorator<Product>(
            new CompositeWriter<Product>(
                new InitialStateWriter<Product>(/*...*/),
                new CurrentStateWriter<Product>(/*...*/),
                new ProductSearchDbWriter(/*...*/),
                new ProductReportsDbWriter(/*...*/)
            ),
            BatchSize
        ),
        new StandardEventStorage(/*...*/)
    );

I have put the batch inside the event committing decorator because I want the events to be committed as soon as possible. I could use a similar decorator for the event storage. For the actual user interactive solution we might just leave outside the batch, which is just having a different composition root there.

Next thing could be adding some explanatory variables to avoid dizziness.

private IWriter<Product> NewProductWriter() {
    var composite = new CompositeWriter<Product>(
        new InitialStateWriter<Product>(/*...*/),
        new CurrentStateWriter<Product>(/*...*/),
        new ProductSearchDbWriter(/*...*/),
        new ProductReportsDbWriter(/*...*/)
    );

    var batch = new WriterBatchDecorator<Product>(
        composite,
        BatchSize
    );

    var eventStorage = new StandardEventStorage(/*...*/);
    var eventCommitting = new WriterEventCommittingDecorator<Product>(
        batch,
        eventStorage
    );

    return eventCommitting;
}

Now I have all the things the user needs. Let’s put another one, one for us programmers: Logs. By now you might guess, it will be yet another decorator:

class WriterLoggingDecorator<TEntity>: IWriter<TEntity> {
    private readonly IWriter<TEntity> inner;
    private readonly ILogger logger;

    public WriterLoggingDecorator(
        IWriter<TEntity> inner,
        ILogger logger) {
        this.inner = inner;
        this.logger = logger;
    }

    public async Task Save(IEnumerable<TEntity> entities) {
        var eagerlyIteratedEntities = entities.ToList();

        var count = eagerlyIteratedEntities.Count;
        logger.Trace($"{typeof(TEntity)} writing {count}");

        try {
            logger.Trace("Begining actual save");

            inner.Save(eagerlyIteratedEntities);

            logger.Trace("Done with actual save");
        } catch (Exception ex) {
            logger.Error(ex);
        }
    }
}

Activating the logger will be as simple as including it in the composition root.

    // ...
    var composite = new CompositeWriter<Product>(
        new InitialStateWriter<Product>(/*...*/),
        new CurrentStateWriter<Product>(/*...*/),
        new ProductSearchDbWriter(/*...*/),
        new ProductReportsDbWriter(/*...*/)
    );

    var logging = new WriterLogDecorator(
        composite, 
        logger);

    var batch = new WriterBatchDecorator<Product>(
        logging,
        BatchSize
    );

The logger has been placed inside the batch, so entities getting into the batch will not be logged, instead, only those getting out of it. Different setups can serve different purposes. We might want several loggers around, in many places.

Outro

With a set of very small components it was easy to compose an application with desired behavior. Each component has a very simple and well defined responsibility. Once in place the whole application can be tweeked to improved performance and traceability. It’s simpler to tweek just one place than many (shotgun surgery). That one place is the composition root. Many new behaviors can be implemented in form of reusable decorators.

Now…let’s mentally imagine how would that look with inheritance.