DDD Tutorial - Modelling "Create Organization"

Written on 27 August 2016

Business functionality: Create Organization

We want to create an organization, similar to what GitHub has. An organization is a group of members who can participate in the organization’s projects. Organization name must be unique, at most 50 characters length. An organization should have at least 1 member in admin role. A user can be part of any number of organizations.

Modelling

The bounded context

First things first, we need to identify the bounded context (BC). We’re dealing with users and groups so, I’d say the proper bounded context should be something like Membership. This is not core domain functionality, but I prefer to look at the whole app as a group of bounded contexts (anything that has a model with boundaries is a BC). Some of them belong to the Domain, others are just application specific. The Membership is app specific, but that doesn’t change the fact that it has its own specific model that needs to be maintainable.

At this point we need to create the Membership BC.

create context

Click on the add icon then write the name ‘Membership’ then press the Enter key. We’ve created and switched to the new context.

Using CQS

We need to identify the type of the business case: command or query. In this case, we’re dealing with a command, since the result of the action changes the existing business state. Let’s create the command case. Click on the blue Add button (left of tabs).

create command write name

Press ‘Enter’ or click ‘Create’. The command case is created.

Identifying the event

Any business state change is represented by an event. In this case the change is that an organization has been created, so we create our OrganizationCreated event.

create event

Next, click on the Events tab, then on the Organization created event. Now, it’s time to find out the change details i.e the event structure. In this case they’re simple.

event details

Click ‘Save’ when finished.

Identifying the concepts and the aggregate

We know the command, we know the result, now it’s time to find out the what are the models involved in generating that change. It’s pretty obvious that we have the concept of Organization which is an Entity. Let’s create it.

event details

Now, we need to identify a model relevant for our business case. Click the Command Use Cases tab, then click on Create Organization. Press the ‘+’ icon in the Uses Command Model of box. It should look like below

link command to entity

Click on Organization to link the command case to the concept in charge of doing changes. Next, click on the Organization link to go to the aggregate which is specific to that command.

model link

Now, it’s time to determine the aggregate composition (relevant to this business case, only!) and business constraints. The important thing here is to understand that we’re identifying a model, we’re not designing a class with properties. In our case, we know that the organization needs a name and an admin. We start with the name, by creating a Value Object (by clicking Add-> Value Object). Once we have it, we link it with the aggregate ( click on the ‘+’ icon in the Aggregate composition box).

aggregate to value object

Now, let’s write the business rules for the organization name. Click on it to go to the Value Object’s details.

value object details

I wrote the constraints as a regex. Feel free to write things how you want them as they communicate the rules that the values must respect. Click ‘Save’ then click on Create organization link at the right to navigate back to the aggregate.

Now, we know that the organization must have an (authenticated) user in the admin role. This is a strong relationship between the Organization concept and the Member concept. We’re going to represent this relationship by making the aggregate reference the Member entity, which doesn’t exist so we have to create it first (Add -> Entity). Then, click on “+” in the Aggregate composition box to link the Member concept.

aggregate details

You see that we have that “All are required” rule, this means all the components of the aggregate must be present in valid form. When writing code, the Member reference will be implemented as a MemberId value object.

There’s no mention of the “organization name must be unique” rule. That’s because it’s not an aggregate rule, but it’s still a rule that should be enforced. At this moment, Domain Map doesn’t have any specific tools for business rules that aren’t part of an aggregate or a Domain Service but we still want to record this information.

So, we’ll create a Note , named “Other rules”.

create note

You can create notes to record anything you want, including implementation details.

note details

Close the note and scroll down a bit. You should see the Outcomes box, with a Default Outcome option. Click on it, then click on the “+” icon from the Events box. Click on the Organization created event to specify the default outcome (change) generated by the aggregate.

outcome

Since an aggregate controls change and the change is represented as an event, we always want to know which aggregate generated which change. In this case we only have one outcome, but in other cases, we can have multiple outcomes, each with their own event(s). This association also allows us to navigate to event details and back. Feel free to navigate around a bit, clicking on entities, value objects etc.

Conclusion

And that’s it! We’ve identified the relevant concepts, models, events and rules for our command business case (click here to see the result in Domain Map). This is information only, it has nothing to do with implementation. But once we have all this, it’s easier to write the code however you like it. The point is, the model stays the same regardless of programming language, framework or programming style. With Domain Map, the focus is on gathering and recording domain knowledge, not writing code.

In the next tutorial, we’re going to model the “List organization members” business case.

DDD Decoded - Domain Relationships Explained

Written on 24 August 2016

One of the most trickiest things to understand in DDD is the domain relationship between 2 concepts. Most of the time when people think relationship they use the programmer mindset and they look for: has-a or is-a or parent-child or (worse) one-to-many etc relationships. Which is valid when you write code but absolutely wrong when you do domain modelling.

What we’re looking for is a Domain Relationship i.e how the Domain sees the relationship from a business point of view or, to be more precise, what is the level of association/partnership between the concepts and what business rules are involved in maintaining the relationship. And usually there are 2 types: strong/always and weak/optional.

Strong (always) domain relationships

This one is the easiest: it simply means that in a given business case, a concept always needs the other. Examples: Customer and Order, Author and Tutorial etc. Contrary to how many devs think, it’s never “Customer has orders”, it’s always an action about an Order which might involve or not the Customer. When the customer places an order, we need to create that order and we’re going to use a specific Order aggregate. But orders don’t just appear from thin air, a customer is always involved so we can’t create a new order without mentioning the customer.

Order concept requires at its creation a Customer so, in our Order model, we need to find the representation of the Customer that will be used by the Order aggregate. In most cases, we only need the simplest model that represents the existence of the Customer, so we’ll use its id. That id is a Value Object and will be a part of the Order aggregate. We don’t care about a Customer aggregate, because we don’t need one for this business case. The Order is the main concept, Customer is secondary.

However, if we are in a “Cancel order” case, there is no Customer-Order relationship to care about (there is an Order-OrderStatus one, though). So, we can cancel the Order without involving/mentioning the Customer, but, as I’ve said, there’s a different relationship to take care of now.

Let’s say that an Order always needs to have a status. It might be tempting to include it as part of the aggregate but… if you look at it like the business does, it makes no sense for this Value Object to be part of it. What makes sense is to consider the Order Status as being a sort of metadata associated with an Order.

When the Order is created, the only place where this relationship should be represented is the resulting OrderCreated event. That’s because a status like “Pending” is implicit, we don’t need any particular input or business constraint for it. But we still need to ‘announce’ that the order has that status, because it is part of the business state change.

Now, when cancelling an order, we need to specify a different status for the order, however because we can have different outcomes based on the existing order status, we need to identify an aggregate just for that. This aggregate involves the Entity Order (via OrderId) and the Value Object OrderStatus and while being a model specific to changing the order status (representing the relationship itself) the resulting change is still associated with the Order concept.

Using Event Sourcing, this means that the OrderCanceled event is considered to be part of the Order and so, the entity’s id is the order’s id. But the aggregate is about the relationship between Order and OrderStatus, it’s not just an Order aggregate. If this sounds weird, I can only say that it will make sense with more experience.

Weak (optional) domain relationships

Basically, 2 concepts can be associated together. Think Post and Category. Both concepts are independent, but they can work together. In the business case “Assign post to category” we need to create the association between them according to business rules. The relationship aggregate will involve both concepts and we get an interesting situation, because we end up with 2 entities but we need only one to act as the aggregate root. Which will it be?

Clearly, we shouldn’t just flip a coin. We need to understand the concepts better as well as the purpose of their association. It turns out that Category exists to organize posts, while a Post really doesn’t care about categories. This relationship is more important (relevant) for the Category so, we select it to act as the aggregate root. This means that in the resulting event, the entity id would be that of the Category while PostId will be just a field.

Being a relationship, even if changes are considered to ‘belong’ to a specific concept, the aggregate is always a model for the relationship.

An interesting example is deleting something. If I soft delete a post, what I have is in fact a new relationship between the Post and Deleted status, the status is never part of the post itself (as a concept) but always some metadata associated with the post. Btw, the status is a Value Object even if its implementation is just an enum.

Another example can be “Pay invoice”. Yet again, a relationship between an Entity (Invoice) and a Value Object (InvoiceStatus) . The status is metadata for the invoice and we need a relationship aggregate to change the status. From the domain point of view, something associated with the Invoice entity has changed.

Conclusion

The hardest part about domain relationships is to properly identify them; many times, especially when an Entity and a Value Object are involved, we can think that the VO is part of the Entity’s aggregate, when in fact it’s a relationship that might need its own aggregate. But with more practice, spotting relationships will become second nature.

DDD Decoded - Modelling with CQS

Written on 22 August 2016

While CQS/CQRS are a bit newer than DDD, they work so well together, one simply has to use it. And I don’t mean CQRS from an architectural point of view, but from a modelling point of view.

Simply put, when we identify a business case we ask ourselves: “Does this case has the intention to change the business state”? We’re not talking about a particular state (objects, tables etc) but about business state as a whole (remember that in real world any change is implicitly persistent). If so, then it’s a command case else it’s a query case (this is CQS at work).

Being in a query case means that you know you won’t be changing anything and that the models will be read-only (this is CQRS, because we end up with specialised read models).

But in a command case, things are a bit different. Many concepts can be involved however, usually only one will be represented by a command model. The other concepts will be represented by read models. We apply CQS for each concept and we end up with specialised command/query models for each, basically CQRS (not to be mistaken for a CQRS architecture, which is a different thing, but based on the same CQS principle).

As an example, let’s say we have the Create invoice business case. Clearly, the business wants to retain the new invoice, so our business case will change the business state. We’ve identified a concept too, the Invoice for which we need to find a relevant representation. However, because we’re creating the invoice, it means we need a command representation i.e an Aggregate.

That’s great, but there’s more concepts involved besides the Invoice. We need to get the products and prices from an Order, we also need to calculate Tax and so on. Each of these concepts have a model as well, but because we don’t need to change the business state for which those concepts are in charge, it means we’re going to have read models representations. So, the Order model will be some read-only structure which contains all the data needed by the invoice. We always try to identify the most relevant model for that specific case, and not a generic model good for everything.

As a generic ‘rule’, consider the business case as being like a bounded context i.e it has a model which makes sense only inside it. Concepts are involved in many business cases, but we work only with their most relevant models and based on the action we need, either write or read, we end up with a command model or a query model for each concept.

So, in a command case, we can find both command and query models of different concepts while in a query case, we’re dealing only with read (query) models. Applying CQS early when modelling helps us to know upfront what types of models we’re looking for, which gives us a bit more clarity and a productivity boost.

DDD Decoded - Application Services Explained

Written on 19 August 2016

We have all those domain models, aggregates and domain services but they are just parts of business cases, floating around. We need something to put things together, to orchestrate the fulfillment of a specific business case. We need a manager of sorts and in DDD that role is performed by an Application Service.

What does an Application Service (AS) actually do?

The simplest way to look at it is as the ‘hosting environment’ of a business case. It takes care of invoking the correct domain models and services, it mediates between Domain and Infrastructure and it shields any Domain model from the outside. Basically, in a DDD app, only the Application Service interacts directly with the Domain model. The rest of the application only sees the Application Service (interesting choice of name).

Business functionality is expressed as business cases and the AS acts as a shell, encapsulating one business case (it should anyway, in practice we can host a simple process i.e more than one business case, but that’s more of a pragmatic compromise). This means the UI/API or some higher layer talks to the AS responsible for that requested functionality and the AS gets to work. At most, the calling layer receives some result which shouldn’t be nor contain a domain model i.e entities or value objects.

It’s important to note that an AS doesn’t have any business behaviour. It knows only what model to use but not how that model works. So, the AS knows which Aggregate to invoke, it knows about some Domain Services that might be required, but that’s it.

An example

Let’s continue the money transfer example. But now, we have the business rule that says the transfer can be done only if the account balance has enough money. So we’re introducing 2 Domain Services: Calculate account balance and Can account be debitted both implemented as functions of a IDomainServices abstraction. But we also need an AccountBalance Value Object.

For obvious reasons, the code is heavily simplified. Also, this is just one of the possible implementations. It’s a matter of style in the end, as long as the code is clear and respects the domain model you can go wild with the implementation.


  public class AccountBalance
    {
        
    }

    /* Domain Services implementation */
    public interface IDomainServices
    {
        AccountBalance CalculateAccountBalance(AccountNumber acc);
        bool CanAccountBeDebitted(AccountBalance balance,Debit debit);
    }

    /* abstraction representing the query model, implementation resides in Infrastructure */
    public interface IDomainQueries
    {
        AccountNumber GetAccountNumber(string number);
    }

    /* Event store abstraction, basically our 'repository' */
    public interface IEventStore
    {
        
    }

    //command object, data structure
    public class TransferMoney
    {
        public Guid Id { get; set; }
        public string AccountFrom { get; set; }
        public string AccountTo { get; set; }
        public decimal Amount { get; set; }

    }

    /* Application Service!!! */

    public class TransferManager
    {
        private readonly IEventStore _store;
        private readonly IDomainServices _svc;
        private readonly IDomainQueries _query;
        private readonly ICommandResultMediator _result;

        public TransferManager(IEventStore store, IDomainServices svc,IDomainQueries query,ICommandResultMediator result)
        {
            _store = store;
            _svc = svc;
            _query = query;
            _result = result;
        }

        public void Execute(TransferMoney cmd)
        {
            //interacting with the Infrastructure
            var accFrom = _query.GetAccountNumber(cmd.AccountFrom);

            //Setup value objects
            var debit=new Debit(cmd.Amount,accFrom);

            //invoking Domain Services
            var balance = _svc.CalculateAccountBalance(accFrom);
            if (!_svc.CanAccountBeDebitted(balance, debit))
            {
                //return some error message using a mediator
                //this approach works well inside monoliths where everything happens in the same process 
                _result.AddResult(cmd.Id, new CommandResult());
                return;
            }

            //using the Aggregate and getting the business state change expressed as an event
            var evnt = Transfer.Create(/* args */);

            //storing the event
            _store.Append(evnt);
            
            //publish event if you want
        }
    }

This particular approach uses a message driven architecture as well as Event Sourcing. We see how the AS orchestrates the business case; the domain model isn’t aware of the command object, the event store or the result mediator. One thing that might be confusing is the branching, it almost looks like the AS needs to know the domain rules of what happens when an account balance is too low, however it doesn’t :) . That’s one of the “tell me if I can continue with the business case” type of situations and the AS uses a Domain Service to get an answer for that. Again, it’s a matter of knowing who is responsible for something, not how something needs to be done. The AS never micro-manages.

If you want to keep things even simpler, you can call this service directly from the UI/API layer, and make Execute() return a CommandResult. We can implement things as complex or as simple we want, as always, it depends on many factors.

Conclusion

The Application Service is the host of a business case and acts as a mediator between the app and the domain model. As long as you keep the domain behaviour inside the dedicated patterns and none leaks into the AS, you’re good to go. Implementations vary and there’s not a recipe of how a “good” AS looks like. Just remember its role and respect the domain model, the actual code is up to you.

DDD Decoded - Domain Services Explained

Written on 16 August 2016

Domain services are a bit confusing at first, when you don’t know exactly what a an Application Service is. Also, many developers try to cram a lot of business rules in their Aggregates, when a Domain Service (DS) would be more appropriate. But let’s start with the beginning….

Why do we need Domain Services?

Some business rules don’t make sense to be part of an Aggregate. For example, you want to check an account balance before debiting an account. Or you want to see if a certain operation is allowed by the business rules (not to be mistaken for user authorization). Or you want to perform a simple calculation according to domain rules. Basically, any business rule required to move forward a business case, which doesn’t belong to an aggregate should be a Domain Service. This is the DDD term for business behaviour outside an aggregate or a value object.

How to identify a Domain Service (DS)?

The easiest way is to simply check if the rules are having to do with business constraints required to maintain an aggregate invariants, including its value objects. If they’re not, they’re a DS, even if it seems related to that aggregate somehow. Many times you need to generate a value object that will be part of the aggregate. For ex: you need a Tax Calculator behaviour which will generate a Taxes value object which is a part of the Invoice Aggregate.

In other cases, you might need to allow an operation. Remember the transfer money example? Wha if we have a rule that says that you can’t debit the account id the amount is lower than the balance? In this scenario we’re actually dealing with 2 Domain Services: one is used to calculate the AccountBalance Value Object (VO) the other encapsulates the “amount must be greater than the balance” rule.

What about the Anaemic Domain anti-pattern?

In a business case we can use multiple DS and this might look like the Anaemic Domain. But it’s not, the reason being that Aggregates should be as small as possible, not because someone said so, but because they should contain only the relevant behaviour for that model. Not every related behaviour. If something is ‘outside’ an Aggregate, then it’s probably is a Domain Service.

Implementation tips

A DS is just a name signaling business behaviour. It doesn’t mean you have to implement it in one way or another. In many cases you can implement all the domain services from that Bounded Context as (static) functions in one class, while in other cases you might want one class per DS. As with everything, it depends.

A DS should be visible and consumed inside that Bounded Context only! Yes, you can define interfaces that can be used by your application service, they’re great for testing, however their concrete implementation should be in the same BC as the business cases where it’s used.

External services

Let’s say we need to calculate tax but the domain expert says they’re using some website to do it (and luckily for you, it provides an API and a client library). We need that functionality, but it’s implementation is not part of our Domain. This is what I call an External Service. The easiest way to use it is to define an abstraction (interface part of your BC) that will act as if it’s a Domain Service, however its implementation will be part of the Infrastructure and it will act as a wrapper around the client library. This is how we keep things decoupled. If later the calculation will be performed in-house, just implement a new class inside that BC and reconfigure the DI Container. Simple stuff.

What if we need a service which is part of our app but part of another BC? For a monolith, you can cut corners and use it directly (assuming you weighted in the consequences). For a distributed app, I’d suggest the External Service approach. In the end, for the BC it’s something outside its boundaries, it doesn’t matter where the actual functionality is implemented as long as it’s not inside the boundaries. For the BC’s point of view, it’s an external service.

Conclusion

We have Domain Services simply because we want to keep a concept’s model relevant, so any behaviour which doesn’t naturally fit that model needs to be expressed somehow. Also DS shouldn’t care about state, they represent domain behaviour only (their implementation should be stateless).