Domain-Driven Design

You’ve decided to use Domain-Driven Design (DDD), but aren’t sure how to implement it. Maybe you’ve seen it go wrong before and aren’t sure how to prevent that happening again. Maybe you’ve never done it and aren’t sure where to start. This post will show you how to implement a DDD domain layer, including aggregates , value objects, domain commands, and validation, and how to avoid some of the pitfalls I’ve seen. It will not discuss the why of DDD vs other competing patterns; nor, for the sake of brevity, will it discuss the infrastructure or application layers of a DDD app. To demonstrate these concepts in action, I have built a backend for a library using DDD; the most relevant sections will be shown in the post, and the full version can be found on GitHub. The tech stack I used is an ASP.NET Core API written in C# backed by a Mongo DB.

The Aggregate Root

The aggregate root is the base data entity of a data model. This entity will contain multiple properties, which may be base CLR types or value objects. Value objects can be viewed as objects that are owned by the aggregate root. Each object, whether an aggregate root or value object, is responsible for maintaining its state. We will start by defined an abstract aggregate root type with properties all our aggregate roots will have:

public abstract class AggregateRoot
{
    public string AuditInfo_CreatedBy { get; private set; } = "Library.Web";
    public DateTime AuditInfo_CreatedOn { get; private set; } = DateTime.UtcNow;

    public void SetCreatedBy(string createdBy)
    {
        AuditInfo_CreatedBy = createdBy;
    }
}

Next, we will define an implementation of this type containing a couple internal constructors, a number of data properties, and a couple methods for updating the data properties. Looking through the implementation below, you will probably note that my data properties have private setters and methods for setting them. This looks a little strange when you consider that properties allow custom setters, but the reason for this is serialization. When we deserialize an object from our DB, we don’t want to have to go through any validation we might do when setting a property; we just want to read into the property and assume the data has already been validated. When the data changes, we need to validate it, so we make the property setters private and provide public methods to set the data. Another benefit the methods provide is you can pass a domain command to them, instead of just the final expected value of the property; this allows you to provide supplemental information as necessary.

public class User : AggregateRoot
{
    /// <summary>
    /// Used for deserialization
    /// </summary>
    [BsonConstructor]
    internal User(Guid id, string name, bool isInGoodStanding, List<CheckedOutBook> books)
    {
        Id = id;
        Name = name;
        IsInGoodStanding = isInGoodStanding;
        this.books = books;
    }

    /// <summary>
    /// Used by the UserFactory; prefer creating instances with that
    /// </summary>
    internal User(string name)
    {
        Id = Guid.NewGuid();
        Name = name;
        IsInGoodStanding = true;
    }

    public Guid Id { get; private set; }
    public string Name { get; private set; }
    public bool IsInGoodStanding { get; private set; }

    [BsonElement(nameof(Books))]
    private readonly List<CheckedOutBook> books = new();
    public IReadOnlyCollection<CheckedOutBook> Books => books.AsReadOnly();

    public async Task CheckoutBook(CheckoutBookCommand command)
    {
        // validation happens in any event handler listening for this event
        // e.g. Does the library have this book, is it available, etc.
        await DomainEvents.Raise(new CheckingOutBook(command));

        var checkoutTime = DateTime.UtcNow;
        books.Add(new CheckedOutBook(command.BookId, checkoutTime, checkoutTime.Date.AddDays(21)));
        DomainEvents.Raise(new CheckedOutBook(command));
    }

    public async Task ReturnBook(ReturnBookCommand command)
    {
        // validation happens in any event handler listening for this event
        // e.g. Does the user have this book checked out, etc.
        await DomainEvents.Raise(new ReturningBook(command));

        books.RemoveAll(r => r.BookId == command.BookId);
        DomainEvents.Raise(new ReturnedBook(command));
    }
}

public class CheckedOutBook
{
    public CheckedOutBook(Guid bookId, DateTime checkedOutOn, DateTime returnBy)
    {
        BookId = bookId;
        CheckedOutOn = checkedOutOn;
        ReturnBy = returnBy;
    }

    public Guid BookId { get; private set; }
    public DateTime CheckedOutOn { get; private set; }
    public DateTime ReturnBy { get; private set; }
}

Having POCOs or dumb objects (objects that aren’t responsible for maintaining their internal state) is often one of the first mistakes people make when doing DDD. They will create a class with public getters and setters and put their logic in a service (I will go over domain services and why you don’t usually want to use them later). The problem with this is that two places might be working with the same object instance at the same time and write data that the other is reading or writing, so the object risks ending up in an inconsistent state. DDD prevents inconsistent state by only allowing the object to set its own state, so if two consecutive changes to the same object would lead to inconsistent state, the object will catch that with its internal validation, instead of relying on the caller to have validated the change.

Domain Commands

Domain commands are how you tell an aggregate to update itself. In the code above, CheckoutBook and ReturnBook are domain commands. It isn’t strictly necessary to create a command type to represent the data being passed; you could have just passed a Guid bookId instead of a command class into the method. However, I like creating a command type because you have a single object to run validation against, and you can validate parameters when creating the command instance. For example, if your domain command requires a certain value be provided, you could validate that it’s not null in the type constructor instead of in the domain command itself. The validation on the type especially helps the logic flow well; you can’t really validate a Guid without additional context; you can validate a ReturnBookCommand type that contains a Guid, and you already have the additional context around what the Guid is.

public class CheckoutBookCommand
{
    public Guid BookId { get; }
    public Guid UserId { get; }

    public CheckoutBookCommand(Guid userId, Guid bookId)
    {
        if (bookId == Guid.Empty) { throw new ArgumentException($"Argument {nameof(bookId)} cannot be an empty guid", nameof(bookId)); }
        if (userId == Guid.Empty) { throw new ArgumentException($"Argument {nameof(userId)} cannot be an empty guid", nameof(userId)); }

        BookId = bookId;
        UserId = userId;
    }
}

Validation

You probably noticed the comments I had in the domain command implementations about validation. Validation is often tricky to get right in DDD because it uses other dependencies, such as a DB. For example, to successfully check out a book, the system has to make sure both the book and user are in the system, that the book is available, that the user is in good standing, etc. To do these, we already pulled the user from the DB to get the user aggregate, so we know the user is in the system. However, we haven’t checked that the book is in the system, so we need to reference a database instance when we do our validation inside the domain command. We can’t inject a DB instance into the aggregate because we don’t resolve aggregates from the IoC container, and even if we could, it’s not the aggregate’s responsibility to connect to the DB. We could new a DB instance up in the command, but that is wrong for reasons outside the scope of this article, in addition to not being the aggregate’s responsibility to talk to the DB (research Dependency Injection and Inversion of Control if you don’t know why). This is where our command system comes into play. Notice the DomainEvents.Raise call. I have that implemented with MediatR, which is a .NET implementation of the mediator pattern; see the link at the end of this article for more detail:

public static class DomainEvents
{
    public static Func<IPublisher> Publisher { get; set; }
    public static async Task Raise<T>(T args) where T : INotification
    {
        var mediator = Publisher.Invoke();
        await mediator.Publish<T>(args);
    }
}

We register IPublisher and our notifications and commands with our IoC container so we can resolve dependencies in our handlers. We then create a method that knows how to resolve an IPublisher instance and assign it to the static Publisher property in our startup. The static Raise method then has all the information it needs to raise the event and wait for the handlers to complete. In this example, I use the FluentValidation library for validation within these handlers. We could put an error handler in our HTTP response pipeline to catch ValidationExceptions and translate them into 400 responses.

public class CheckingOutBook : INotification
{
    public CheckoutBookCommand Command { get; }

    public CheckingOutBook(CheckoutBookCommand command) => Command = command;
}

public class CheckingOutBookValidationHandler : INotificationHandler<CheckingOutBook>
{
    private readonly CheckingOutBookValidator validator;

    public CheckingOutBookValidationHandler(CheckingOutBookValidator validator) => this.validator = validator;

    public Task Handle(CheckingOutBook @event, CancellationToken cancellationToken)
    {
        validator.ValidateAndThrow(@event.Command);

        return Task.CompletedTask;
    }
}

public class CheckingOutBookValidator : AbstractValidator<CheckoutBookCommand>
{
    public CheckingOutBookValidator(ILibraryRepository repository)
    {
        RuleFor(x => x.UserId)
            .MustAsync(async (userId, _) =>
            {
                var user = await repository.GetUserAsync(userId);
                return user?.IsInGoodStanding == true;
            }).WithMessage("User is not in good standing");

        RuleFor(x => x.BookId)
            .MustAsync(async (bookId, _) => await repository.GetBookAsync(bookId) is not null)
            .WithMessage("Book does not exist")
            .DependentRules(() =>
            {
                RuleFor(x => x.BookId)
                    .MustAsync(async (bookId, _) => !await repository.IsBookCheckedOut(bookId))
                    .WithMessage("Book is already checked out");
            });
    }
}

Creating Entities

At this point you may be wondering how we ensure an aggregate root is valid on initial creation since we can’t await results in a constructor the way we do in our command handlers inside the entity. This is a prime case for the use of factories; we’ll make our constructor internal to reduce the accessibility as much as possible and create a factory that makes any infrastructure calls it needs, calls the constructor, then raises an event with the newly created entity as data that can be used to validate it. This way, we encapsulate all the logic needed to create an event, instead of relying on each place an event is created to perform the logic correctly and ensure the entity is valid.

public class UserFactory
{
    public async Task<User> CreateUserAsync(string name)
    {
        var user = new User(name);
        await DomainEvents.Raise(new CreatingUser(user));

        return user;
    }
}

Domain Services

You are probably wondering at this point why I didn’t simply use a service to perform the checkout book command. For example, I could define the service with a method CheckoutBook(User user, Guid bookId), and perform all the validation inline, instead of importing MediatR and FluentValidation and creating 3 classes to simply validate my user. Then I would inject this service into whatever place calls the domain command and call the service instead of calling the domain command. I could still have my domain command be responsible for updating the entity instance to ensure it isn’t having random values assigned in places. The problem with this is I now have some logic in the service and some in my entity; how do I determine which logic goes where? When multiple devs are working on a project, this becomes very difficult to handle, and people have to figure out where existing logic is and where to put new logic. This issue often leads to duplicated logic, which leads to bugs when one is updated and the other isn’t, among other issues. Additionally, as I mentioned above, because the validation logic occurs outside my entity, I can no longer trust that the entity is in a valid state because I don’t know if the validation was run before the command to update the entity was called. Because DDD implemented correctly only allows the entity to update itself, we can validate data changes once inside the entity just before we update it, instead of hoping the caller remembered to fully validate the changes.

References

AST’s and JavaScript: Write Code that Writes Code

The adoption of abstract syntax trees in JavaScript has led to an explosion in tooling that has changed the landscape for developers.  The usage of ASTs allows JavaScript developers to better identify potential bugs before executing their code, as well as ensuring a consistent code quality across a codebase.  Their use in build tools has changed how we write our JavaScript applications by not only letting us target future specifications of the JavaScript language but also to compile non-spec compliant syntax (e.g. JSX) to JavaScript for use in the browser.  And by leveraging this data structure, developers can have 100% confidence in updating thousands of JavaScript files using an AST-based script by leveraging codemods.

While these tools carry a ton of power and potential, the use of code modification via AST manipulation scares off many developers.  The name itself will cause your average developer to scratch his head and proclaim, “Well, I’m not a Computer Science major so I don’t think a tool like that is for me.” However, given the current tooling available, AST manipulation is very approachable. [Read more…]

Start Training on a New System by Describing the End Product

As a contractor, I am often thrown into huge code bases with just a list of instructions for environment setup and not much else.

The bummer is that for complex software systems, a list of setup instructions is of hardly any use without understanding the expected end product of the environment you are putting together.

I often wish I also had a list of things I was allowed to do as a new contractor / employee, but this is probably a discussion for another time.

When I buy a Lego set, I bought it based on what the final constructed product looked like on the front of the box.

As you are putting together the Lego set, don’t you sometimes find yourself referring to the cool picture on the front of the box as a general reference and motivator?

[Read more…]

Be Rational—Delete That Code!

computer-code-black-cup

In a previous blog post, I brought up the concept of fighting the urge to rewrite code, and instead shift to refactoring code a step at a time until it takes on the features and characteristics that the business needs. Rewriting the code should only be considered a last ditch option. All that said, you will inevitably hit scenarios where you can delete whole swaths of your hard fought code:

  • Refactoring – As you are refactoring code, you will inevitably hit the bottom of the refactoring stack and are now are able to delete whole chunks of code that are no longer needed.
  • Dead End – While coding up a feature, you have found out that the track you have taken is a dead end. There is a need to wipe out all that code and start over on a different path.
  • Fully Supported Third-Party Replacement – Whole chunks of your past work should be replaced by new frameworks and/or third party components.
  • Long Gone Business Requirements – A feature that you poured years into is just no longer needed, and the expense of supporting it is adding up, so it needs to be removed. Nobody learned this lesson more than the Microsoft Internet Explorer team when they started work on the Edge browser (nee Project Spartan)

[Read more…]

You Don’t Need to Rewrite to Move Forward

The story you are about to read is mostly true. The names have been completely omitted to protect the innocent. It is extracted from the caffeine addled brain of an old-school software engineer. Take from it what lessons you wish.

As software engineers we always seem to want to rewrite something. There is an immense sense of freedom that comes from clicking: File –> New Project…

The next time you have the rewrite urge, think instead on how you can execute an incremental improvement to the code without rewriting. I would submit that if you think that a rewrite would be just ‘one step’ and ‘super easy’, it really isn’t. Factors, actors, capital, and time on a scale you never dreamed of will enter into your rewrite effort eventually.

[Read more…]

Browser-less Unit Testing your React/Redux Code with Mocha, Chai, and Enzyme

A lot of JavaScript applications out there require having a browser available to run your unit tests.  For years it seemed like the de-facto configuration for unit testing was some combination of Karma, PhantomJS, and either QUnit or Jasmine.  While I think that there is definitely value in making sure that your application runs properly in a browser, given that that is how your users will interact with it, my personal opinion is that the majority of your test suite should be able to be run outside of a browser environment.  This article will describe what Enzyme brings to the table in terms of unit testing your React/Redux code without needing a browser.

[Read more…]

Vue.js – The Next Library for Angular 1 Developers

Angular is the most successful JavaScript framework ever. I cannot back this up with any numbers, but based on my experience as a developer over the past few years, it is everywhere. It is truly a complete framework, and it’s no wonder why it has achieved so much success in the industry. However, like all technology, it is quickly becoming dated, and new options have entered the fold.

Libraries like React and Angular 2+ have learned from their predecessors and employ strategies and optimizations that result in less code bloat and better performance.  These new-age frameworks also leverage bleeding edge development tools such as Webpack and Babel, which allow developers to utilize future standards (and non-standards) of the JavaScript language, resulting in increased productivity and cleaner code.

[Read more…]

Practical Get Started With Swift

Recently, I had to get started (fast) with Swift on a series of existing iOS projects. I would classify myself as being able to get to fourth gear in a Honda Accord with a manual transmission when it comes to using and applying Swift. I look forward to the day when my Swift knowledge is equivalent to running full out on the Nurburgring in a Bugati Veyron.

My background is C, C++, C#, Objective-C, with a side of JavaScript along the way.

I will never admit to any classic Visual Basic, or VB.NET, code ever being typed by my fingers, ever!

When it comes to learning a new language, I find myself in ‘Use it or lose it’ mode. Learning Swift comes very naturally if you have a concrete task which allows you to add a feature, or refactor an existing iOS project, with brand new Swift code.

I found that becoming proficient with Swift was very easy given the general C language progression in my career. In very short order, I was able to do almost all the tasks in Swift that I would normally do in Objective-C against the CocoaTouch / UIKit API surface. More advanced Swift language constructs exist, which I have barely touched, and hope to be able to learn and apply some day—I am looking at you, protocol extensions and generics.

[Read more…]

Using Aurelia’s Dependency Injection Library In Non-Aurelia App, Part 2

In my last post, we looked at Aurelia’s dependency injection library and how you might be able to use it as a standalone library in your vanilla JavaScript application.  Now, however, I want to take a look at how you might be able to wire it into your React application, and then finally how you might hook it into React/Redux application.

[Read more…]

Adding Amazon Alexa Voice Services to Your iOS App with Swift

Major thanks to the MacLexa project out on Github for providing motivation, source code, and a great starting place for this blog post.

secure

Amazon Echo is an always listening device which acts as an always available assistant. Thanks to the deep integrations that the Amazon Echo has to online services you can issue a wide variety of questions and commands via voice and get real world responses.

[Read more…]