Domain-Driven Design in Practice Pluralsight course

By Vladimir Khorikov

My DDD in Practice course for Pluralsight went live.

Why should you watch this course?

I’ve been consistently applying DDD principles in my projects for about 6 years now and I can’t express enough how much value Domain-Driven Design has brought to me. The blue book written by Eric Evans was the most influential book I’ve ever read in my career.

If you read this book too, you must have noticed that while it provides invaluable insights, it doesn’t tell much about how to implement them in practice. It becomes especially frustrating if you consider the progress made by the modern ORMs and programming languages. It’s clear that if you rely on a relational database in a fairly complex software project, you can’t avoid using an ORM. At the same time, it might be uncertain how to keep up with the DDD principles: how not to fall down to data-driven development with an anemic domain model and still get the benefits the big ORMs provide.

In this course, I cover such topics. You, as a viewer, will go through the full development process of a quite complex application and will see how to apply Domain-Driven Design in conjunction with other best practices: unit testing, KISS and YAGNI principles, MVVM design pattern and more. You will see how to keep the domain model clean and isolated in the face of tight constraints relational databases impose and how to prevent ORM from infiltrating into your domain classes.

Throughout the course, I show how to grow a fully-fledged application from the ground up. DDD concepts are introduced gradually, without putting a lot of pressure on the viewer.

If you read this blog in a regular manner, you might have noticed that I extol the YAGNI and KISS principles. The sample project in the course is implemented with these principles in mind. It’s interesting that DDD itself fosters application of these principles by focusing on the essential parts of the software (the core domain) and simplifying it using the tactical patterns (entities, value objects, and so on).

The course covers such topics as:

  • Onion architecture and domain model isolation
  • DDD and unit testing
  • Entities and value objects and the differences between them
  • The work with a relational database using an ORM
  • Aggregate design best practices
  • Repositories
  • Bounded contexts and subdomains
  • Domain events and two ways of handling them in code
  • DDD anti-patterns

And it is not just some theoretical explanation. All these topics are illustrated by functioning code written in the context of the software project we work on throughout the course. The knowledge gathered in this course is the essential part of what I learned about DDD during many years applying it in real-world projects. The code itself (for example, the base entity class and the code for dispatching domain events) has stood the test of time in many production systems, so you can safely use it in your own projects.

In terms of technologies, the course uses SQL Server, C# 6, NHibernate, and WPF (in conjunction with the MVVM pattern). In terms of tools, it’s Visual Studio 2015, xunit, SQL Management Studio, Resharper and NCrunch. Although the course shows a desktop application, the same principles are applicable to programming backend for server projects.

You can watch the course here: link

Also, if you want to watch it but don’t have a subscription, write me an email and I’ll send you a trial code with which you’ll have an unlimited access to the Pluralsight library during 30 days.

LinkedInRedditTumblrBufferPocketShare




  • Aleksandras

    Nice to hear about such course – I was always struggling to find end-to-end DDD example, which is not outdated and which uses modern technologies. I would definitely look at it (I have pluralsight subscription).

    Although it would be good if you mention more specifically not just principles, but also technologies you are using in your course. For example you mentioned so many times about ORM, but didn’t mention about which exactly. Or is it .NET/ASP.NET, or maybe Java?:)

    I understand you probably wanted to abstract from specific technologies, but you are speaking about real-life example.. and such details are important considering a real-life based course.:)

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good point. In terms of technologies, the course uses SQL Server, C# 6.0, NHibernate, and WPF in conjunction with the MVVM pattern (hope I didn’t forget anything). In terms of tools, it’s Visual Studio 2015, xunit, SQL Management Studio, Resharper and NCrunch.

      You are right that I try to position it as technology-agnostic and you are right that it’s impossible given the “in practice” inclination of the course :) I’ll add this info to the announcement, thanks for the remark.

      Also, a quick note: although the project uses WPF, I apply the same principles when I work on web backend projects.

      • Alexander Yevseyev

        What library do you use for MVVM pattern (like Caliburn.Micro, MVVM-Light) or none at all?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          None at all. The sample project in the course isn’t terribly complex, so I decided not to introduce additional libraries there.

  • Denis Oliva

    Hi Vladimir this is a great course. I tried to apply the event tactical implementation in a project on git hub but the reflection is not working on the unit test for the Handlers. Not sure if is a minor thing that I ma missing but is almost the same implementation that showed in the course. If you have an opportunity could you take a look at it maybe you find the issue in 5s. “https://github.com/tecsined/DddEvents”

    • Denis Oliva

      Thank you Vladimir for taking time on checking this and let me know on twiter. I found the issue. It was reflection and the kind of organization of the project classes. To triggerthe whole process on the unit test project I need to get the handlres using GetCallingAsembly instead of executing

      • http://enterprisecraftsmanship.com/ Vladimir Khorikov

        Thanks for letting me know. Reflection can indeed be quite frustrating to debug.

        • Denis Oliva

          Yes indeed. I created a nugget package based on your idea of event implementation register-dispatch. It is here https://www.nuget.org/packages/Ddd.Events/ and in its is github link. So developers can add events to domains. I think this could be useful not only for DDD architecture but also for architectures with less tactical DDD patterns but that want to use events to handler and decoupling change of object state. Feel free to contribute to the project if you have time. Thank you

  • Mark Hanson

    Hi Vladimir thank you for the great course and blog content.

    If I understand from ddd concepts, an aggregate defines a transactional boundary verses a compositional boundary. To setup for my questions, assume two concepts A and B, where A has many Bs, but we maintain A and B distinctly. The concepts of A and B are each large subdomains (with business rules) and warrant distinct bounded contexts (yes?). So there are two corresponding bounded contexts bcA and bcB. In the bounded context bcA, we would maintain the list of Bs for an A but not modify the details of a B. And in the bounded context bcB, we would show that B belongs to an A but not modify the details of the A. Each bounded context bcA and bcB have their own distinct aggregates for A and B. The bounded contexts are synchronized via domain events (and a bus).

    In the bounded context bcA, the mapping for entity A would have HasMany, I think.

    In the bounded context bcB, B has business rules that include A, but A may not have business rules (the rules for A are in the bounded context bcA). In the bounded context bcB, would the mapping for A have a HasMany? Would B have a mapping to A? The UI views may need to show DTOs for a given A and its Bs by way of Linq (from a repository), but the entity A may not need to know of B within the bounded context bcB.

    And in which bounded context are the rules for adding and removing a B from an A?

    And in bounded context bcB, the aggregate A is essentially read only from an API perspective (when talking to A); but to handle domain events from bounded context bcA that bounded context bcB subscribes to, we need to modify A within bcB and thus need an API to modify A. Do we just leave the API open for modifying A within bcB?

    Thank you

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Mark,

      First of all, the bounded context boundaries you described look reasonable. 1 thing though: I would recommend against creating cross-BC one-to-many relationships (like the link from A to Bs in bcA). It’s not always possible to avoid, so doesn’t automatically mean the model you’ve chosen is sub-optimal, just something to keep in mind.

      In the bounded context bcB, would the mapping for A have a HasMany? Would B have a mapping to A? The UI views may need to show DTOs for a given A and its Bs by way of Linq (from a repository), but the entity A may not need to know of B within the bounded context bcB.

      No need to create a collection of Bs in A in this case. The fewer high cardinality cross-BC relations (such as one-to-many and many-to-many) you have, the better. B can have a reference to A, that’s fine.

      And in which bounded context are the rules for adding and removing a B from an A?

      That’s an operation I would put into bcB. bcB is the master bounded context for B, so all modification operations related to B should reside there. bcA can still maintain a list of Bs in each A but those Bs are for read-only purposes only. Also, such a relation cannot be a composition (when A maintains the lifetime of Bs) because of its cross-boundary nature, it can only be an aggregation.

      … to handle domain events from bounded context bcA that bounded context bcB subscribes to, we need to modify A within bcB and thus need an API to modify A. Do we just leave the API open for modifying A within bcB?

      This handling is best implemented in bcB itself, not outside of it. Create a subscriber in bcB which would update As directly in bcB’s storage, bypassing any bcB’s APIs.

      Hope that helps.

      • Mark Hanson

        Thanks Vladimir for the insight

        Regarding: “I would recommend against creating cross-BC one-to-many relationships (like the link from A to Bs in bcA)”, and “bcA can still maintain a list of Bs in each A but those Bs are for read-only purposes only”

        I did not intend to have a cross-bc relationship, but can you clarify because I may be understanding the term differently or wrongly. I intended for the bcA to have its own representation of A and B, distinct from the A and B in bcB. A given A or B have the same identity, and is aggregation. And each BC has its own database. The link from A to Bs in bcA is within the same bounded context bcA. However when an A is added/removed from a B within bcB, it would syncronize with bcA via events.

        Regarding: “bcB is the master bounded context for B, so all modification operations related to B should reside there.”

        Thanks, and to expand… If A also has a say in adding a B, where do we put A’s business rules? I.e. the B in bcB has rules for adding an A, but if A has rules for adding a B (for the same association), do those rules reside in the A in bcB or in the A in bcA? If the latter, how does the B in bcB react (rollback) if the A in bcA rejects the association, since the communication is asyncronous?

        Regarding: “Create a subscriber in bcB which would update As directly in bcB’s storage, bypassing any bcB’s APIs.”

        Would I avoid the hibernate mapping for A in bcB, since the class for A is “read-only” within bcB? Do you know of an example for doing this?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          I wouldn’t add a list of Bs to A within bcB. A is only for read-only purposes, and as far as I understood from your description, bcB doesn’t need its version of A to contain that list. So, just a single reference from B to A, but not the other way around. But this one is not a “strong” rule, just make sure bcB doesn’t change As.

          A is an aggregate distinct from the aggregate B?

          To be precise, both bcA and bcB contain their own versions of aggregates A and B. Neither of the two bounded contexts should have an aggregate containing A and B as neither of these two BCs control both of these entities’ lifespans.

          And within bcB, could we add “bool CanAddB(B b)” to A? So within B.AddA(A a) we would call a.CanAddB(this).

          If that makes the code simpler, then sure. Again, the only “strong” rule here is the ownership over the master copy of the data. Only bcA can modify As.

          • Mark Hanson

            regarding: “I would recommend against creating cross-BC one-to-many relationships (like the link from A to Bs in bcA)” (at the top of this thread)

            If we wanted to show the Bs for an A, would we do that only in the UI for bcB? And using DTOs and a custom query (cqrs)? So that bcB still has a one-way relationship from B to A.

            If bcA had business rules that had to do with the Bs in an A, would we resort to including the link from A to Bs in bcA? Or if feasible, A could have properties that the business rule uses, like A.HasBsWithSomeAttribute, and when bcA subscribes to events from bcB we would manage this property.

            Do you know of any scenarios that would make it necessary to use the link from A to Bs within bcA?

          • http://enterprisecraftsmanship.com/ Vladimir Khorikov

            If we wanted to show the Bs for an A, would we do that only in the UI for bcB? And using DTOs and a custom query (cqrs)? So that bcB still has a one-way relationship from B to A.

            Yes to both questions, precisely.

            If bcA had business rules that had to do with the Bs in an A, would we resort to including the link from A to Bs in bcA? Or if feasible, A could have properties that the business rule uses, like A.HasBsWithSomeAttribute, and when bcA subscribes to events from bcB we would manage this property.

            The latter approach is more beneficial as it allows you to decouple bcA from bcB and get only the info it needs from it (`HasBsWithSomeAttribute` in your example).

            Do you know of any scenarios that would make it necessary to use the link from A to Bs within bcA?

            The only one I can think of right now is when the latter approach you described earlier is too effort-costly (so, a trade-off with consciously incurred tech debt).

  • Mark Hanson

    Hi Vladimir

    What is a typical range for the number of small aggregates within a bounded context? If it even matters. Assume a reasonably scoped subdomain. And thanks again

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Mark,

      This shouldn’t matter. The only “metric” for how big a BC should be is your ability to “fit” it into your head without problem. Meaning it should be simple enough for you to grasp its domain model relatively easy.

      On a couple of my recent projects, bounded contexts were about 10-15 aggregates each. Use is just for statistics and not as a mean for deciding whether or not to divide your BCs further (or combine them together, for that matter).

  • Mark Hanson

    Vladimir, do you lean towards NServiceBus or MassTransit? And MSMQ or RabbitMQ or ActiveMQ or other? and why? Given MS servers and an MS developer platform.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I’m not an expert in messaging platforms, so take my works with a grain of salt. Personally, I prefer as light-weight solutions as possible by default and try not to use complex messaging platforms without visible necessity. Although, nowadays all my queues are in cloud: either AWS’s SNS/SQS or Azure Queue storage.

      • Mark Hanson

        Regarding “with a grain of salt”, please take these next questions as being directed at any experience you have had with AWS SNS/SQS, and any info is very helpful.

        if i understand, with AWS SNS/SQS one configures an SQS queue to subscribe to an SNS topic, one publishes to the SNS topic, and one polls the SQS queue for messages and after processing the message, one deletes the message from the queue. With SQS long polling you would still loop and poll, with a 20 second wait per poll. Is that correct? Similar concepts in Azure Queue.

        How do you deal with these following scenarios that a service bus would cover?
        Reading the queue once per 20 seconds, it is still a million hits a year, and increases with more message volume and clients. How do you poll the queue at reasonable cost?
        How do you coordinate deleting a message from a queue when there are several clients reading the message, i.e. the last one deletes the message? And to handle one client being down for a bit, would you have to keep a table of sorts to know who still needs to read the message?
        When you read a message from a queue, do you have to write routing code that looks at the message contents, deserializes to an object and calls a call back method?
        Do you use sagas?

        What features of a service bus would warrant you moving to a service bus? I.e. at what point have you decided to use one in the past?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Do you setup one SNS topic per published domain event, and one SQS queue for a bounded context, which subscribes to multiple SNS topics?

          More or less: I usually create one SNS topic per each type of domain events, the same way you described it. As for SQS queues, I tend to create one queue per {Receiving bounded context, type of domain event}. So if there are 2 BCs listening for an SNS topic, there would be 2 SQS queues. One SQS queue subscribes to only one SNS topic.

          What do you do in your subscriber code between the polling and the message handler?

          Depends on the type of the message and the processing time. If the handler doesn’t take too much time handling the message, I invoke it synchronously. This way, if anything goes wrong (i.e. if an exception is thrown), the message will be returned to the queue and processed again later. Otherwise, I process it asynchronously. If losing a message is not a big deal (for example, when the next message of the same type will sort everything out), I just handle the message in a separate working thread. If it is important, then some sort of a temporary storage on the receiving side is needed to avoid information loss: the message is stored to that storage on the receiving thread and then processed asynchronously in another.

          How do you tie the TopicArn to a domain event?

          I don’t have any specific guidelines here.

          Do you ever need the concept of a saga?

          I tend not to use sagas, but I don’t have much experience with NServiceBus, so don’t count on me with this one.

          Have you needed to use a service bus in the past?

          The way I usually use SNS/SQS is essentially that – a service bus. I find the pub/sub concept exceptionally useful.

  • Mark Hanson

    Hi Vladimir,

    Regarding eventual consistency, have you encountered green-field scenarios where you needed a transaction that spanned aggregates? Or that necessitated a synchronous call outside of the bounded context? If so, do you explicitly start a transaction in an application service and not call the repository save method? Or what do you do in this case?

    In green-field, are there cases where two aggregates or bounded contexts have rules that cover the same concept? If you have a method that saves one aggregate and the next aggregate throws an exception, what do you do with the first aggregate that has been saved?

    In brown-field, let’s say that legacy systems have business rules that overlap. We introduce a bounded context but legacy systems will overlap with the bounded context until they are refactored. Within the bounded context, an application service tells an aggregate to do something and saves (a committed transaction), and then calls a web service to tell a system to do something. What do we do if the system rejects the request due to its business rules? I see these options: don’t call the repository save method and instead write a transaction in the application service method; copy the business rules into the bounded context.

    And, do you ever consider distributed transactions across a bus, like NServiceBus offers? Don’t do it, correct? Resort to a synchronous call instead?

    Do you have blog content that covers transactions and eventual consistency?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Regarding eventual consistency, have you encountered green-field scenarios where you needed a transaction that spanned aggregates?

      Yes, that happens quite often. An example: a requirement to check a user email uniqueness.

      Or that necessitated a synchronous call outside of the bounded context? If so, do you explicitly start a transaction in an application service and not call the repository save method? Or what do you do in this case?

      Also, yes, if the external call returns reasonably fast. One external call per business transaction usually isn’t a problem.

      If you have a method that saves one aggregate and the next aggregate throws an exception, what do you do with the first aggregate that has been saved?

      There’s only 2 possible solutions here: either wrap them in a single DB transaction or introduce a compensation logic. The former is simpler and thus preferrable but not always possible. Jimmy Bogard had a great blog post series recently where he explored compensation options: https://jimmybogard.com/refactoring-towards-resilience-a-primer/

      And, do you ever consider distributed transactions across a bus, like NServiceBus offers? Don’t do it, correct? Resort to a synchronous call instead?

      A sync call is preferrable but, again, not always possible, so there are cases where you won’t be able to avoid distributed transactions of some sort.

      Do you have blog content that covers transactions and eventual consistency?

      I don’t think I ever wrote one. The closest I can think of is this: http://enterprisecraftsmanship.com/2015/11/06/sql-vs-nosql-you-do-want-to-have-a-relational-storage-by-default/

      Great questions btw! My slow responses are due to current load only.

  • Mark Hanson

    Vladimir,

    If the subdomain has a deep tree with composition, do we tend to break it into one aggregate for each domain entity in the deep tree? How do you manage deleting or adding a large branch of the tree, or business rules that span across nodes? Most of the time a single entity per aggregate would be transactionally sound, but there may exceptions.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      do we tend to break it into one aggregate for each domain entity in the deep tree?

      Yes, the fact that they are all transactional by themselves is a good sign they should belong to their own aggragates each.

      How do you manage deleting or adding a large branch of the tree, or business rules that span across nodes?

      If something doesn’t fit a single entity’s responsibilities, I’d recommend attributing that responsibility to a service (either domain or application).

      Vaughn Vernon’s advice is sound here: I would too recommend splitting the big aggregate into several smaller ones. The only thing I disagree with him on is the use of ids. If possible, use direct references to other aggregates, not ids, that would ensure proper separation of concerns. Here I wrote in more detail about it: http://enterprisecraftsmanship.com/2016/03/08/link-to-an-aggregate-reference-or-id/