Implementing Domain-Driven Design

Category: Programming
Author: Vaughn Vernon
4.2
All Stack Overflow 13
This Year Stack Overflow 3
This Month Stack Overflow 16

Comments

by humanfromearth9   2022-11-09
Hello,

Apart from my family and some minor health issues, I currently am focused on 2 things: learning Luxembourgish/Luxembourgian and develop a deep understanding of functional programming.

About the former one: that should help me find a job in some Luxembourgish administration (I really wish I'll be able to find one soon).Luxembourg might be a small country, but I think it's managed well, CTIE (Luxembourgish administration that manages most of the IT infrastructure and software used by the state) has quite smart and competent people (also some dumb ones, but where's that not the case?), and I think I like the culture, which is almost my own, as I grew up close to Luxembourg and even went to a german-speaking school, while speaking family-native French (I'm as fluent speaking German as French, no accent).

Regarding the latter one, I started applying functional programming principles early this year, almost as obstinately as I can (and as much as possible using Java 8 then now 17) (I've got more than 16 years of professional experience using Java, both as a developer and software architect).

This was just the beginning of a more insightful journey into new coding practices, which result from one principle I discovered this year: source code should never lie. This became an evidence once I implemented and started to use my self-made "Maybe" type (a better Optional - Optional is quite weak if you want to avoid procedural programming). While using Maybe, it struck me that what I did was just explicitly forcing my code to say the truth. So I started to dig into types and have types represent various states (this may be seen as a better use of object orientation - this is not relevant, what's relevant is the improvement in the quality of my code). Using the multiple types (usually sub-classes) and combining with "fold" methods make a lot of if-else unnecessary and force the developer to handle each case: one can't just forget one case. What one may do is not handle a case, but it remains explicitly visible in the source code, with as much importance as the other cases. Then, the removal of the if-else usually means that the logic is much simpler to read and reason about. Using adequate types also means that only functions of the actual type are available, so we also reap the benefits of OO design. Also, while it is stated that Optional was not made to be serialized, I made my Maybe type so that it may be used in serialized objects and thus accurately reflect the state of affairs.

I'm still discovering FP patterns (for example, I still have to read about how to properly manage IO/side-effects/state. Once I've learned FP patterns, I'll focus on the synthesis of my knowledge of Java, DDD and FP in order to find out how to best apply FP and DDD principles to professional Java projectes, given the constraints of the language, it's modularity (Java 9 modules, Maven modules) and the JVM. I already have the intuition that the Spring framework (which is the de facto standard in Luxembourg businesses) might not be a good fit to serious FP programming - at least not without appropriate abstractions on top of it. This probably already starts with the dependency injection/inversion of control, which, I think (to be confirmed, though), does not make sense if a purely functional approach.

Regarding a Maybe type (I'm picky about naming - remember, code shouldn't lie): I firmly believe that Optional and Option are bad names for this type. As the user of an API/function that may return something or nothing, I don't get a choice about what I receive. Maybe I receive something, maybe I receive nothing. It's not like I receive some option from which to choose. As the one who implements the API, I have indeed the choice to provide something or nothing, so yes, I have some option, but what I'll return may be something or may be null. Thus I strongly recommend to stick with the name Maybe. Option/Optional is just lying to the user of the API/function.

It might just be an anecdote, my own, but I think that using lambdas and a few other FP principles with Java >= 8 for more than 9 months really opened doors in my mind about functional programming and types (way more than following Martin Oderski's FP courses on Coursera), to the point that I now really feel comfortable reading and understanding more advanced literature about FP, even stuff in Haskell. I'm not saying it's easy/simple. But if I focus, I think I'm now able to understand, which might not have been the case just last year. So Java provides, I think, a good enough environment to learn more than the rudiments of FP.

The most important lesson learned this year about programming is: source code must not lie. Replace nullable stuff with Maybe, when a Boolean may be null, don't just use a Boolean, but (for example) reimplement a NullableBool interface that has three types: TrueBool, FalseBool and UndefinedBool/NullBool. To represent two-valued booleans, I have Bool with subclasses TrueBool and FalseBool. Don't hesitate to use multi-valued booleans in cases where you have to represent probabilities (I, for example, have used a TetraValuedBool, which has the types False-Improbable-Probable-True). All these Bool types come with various static functions ('of()' to get/construct an instance) and non-static functions ('fold()'). To allow functions to return results that may represent anomalies, don't hesitate to use a Result type, which has two sub-types, one wrapping anomalies and one wrapping the actual legit result, and, again work with a "fold" function to handle both cases explicitly. Use strong types whenever possible, even if it's just some wrap around a String. Nothing is just a String.

This takes some time to implement, but once you have, it just makes your code easy to read and understand, nothing is hidden anymore: no implicit consequences. Once your code does not lie anymore, it becomes self-documenting, especially given FP is rather declarative (one does rather state what one wants than how to do it). This is rather cool, as you won't have to maintain separate documentation (at least not for developers).

Now, I'm not sure I recommend you do the same: my client will stop my contract by the end of this year because they don't understand the benefits of this higher code quality. They'd have preferred 'simple' procedural code, with which they believe I would have been able to deliver more features faster. Even my developer colleagues don't recognize the beauty of it. This, of course, is utter BS, because their problem is scope creep and they need to designate some responsible for being late. They just decided it's me. I'll be sacrificed on the altar of bad project management. I'm still making up my mind about defending myself and telling my point of view to their superiors: Luxembourg is small, it's not a place where one wants open conflicts, but at the same time, do I have to allow being made responsible for bad PM choices?

The intellectual challenge of combining FP, DDD and Java is absolutely great and quite huge. I couldn't do it just after-work (my wife and I are raising two little boys), because the deeper understanding of these needs regular, almost daily practice and reading about these topics. Doing this at work clearly made me vulnerable in a way I didn't see coming when I began this path, so I definitely can't recommend it to everyone. But I can't wait reaping the results of my deeper understanding of these topics, and I'm really happy to still be a programmer instead of doing some management (that is also an option - I have both experience and university degrees in engineering and in management), it's been a long time since I've had so many interesting intellectual opportunities.

Some references I used this year to improve my programming skills or just enjoyed reading (I consider these to be a good intro into FP and DDD):

- [0] Pragmatic Functional Java: https://www.amazon.fr/Implementing-Domain-Driven-Design-Vaug...

- [7] https://www.amazon.com/Functional-Programming-Java-Harnessin...

by anonymous   2019-07-21

You pretty much answered your own question -- this model is impractical, and will be slow as you need to load tens of thousands of items each time you rehydrate an aggregate root from the database (unless resorting to complex lazy loading).

The "can't exist without" rule is rarely applicable. I suggest you read the aggregate design recommendations here : http://dddcommunity.org/library/vernon_2011/ http://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577

by anonymous   2019-07-21

The question is a bit abstract so here is a general answer:

I would suggest to look at the differences between rich and anemic models. Spring and Hibernate encourage using anemic model which is considered an anti pattern from Object Oriented Design point of view and makes it hard to apply SOLID principles.

More on this topic you can find in excellent book by Vaughn Vernon: https://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577

Domain Driven Design described in the book may be also of interest for you.

by anonymous   2019-07-21

You sound a little confused about what a 'model' is.

A model is usually thought of as the related set of objects that describe your business domain. In your case you have a customer that has orders -- it could be said that your model has a 1-many relationship between customer and order, and that the relationship itself is called 'Orders'. If you view things this way, then the methods you describe probably belong on the owner of the relationship -- in this case, customer.

You may also have a need to represent all the orders for your company, not just for one customer. You could achieve this through navigation (loop through all customers and retrieve all orders for the customer), or you could model it as your Company has a 1-many relationship with Order -- in this case, again, you would put the methods you're describing on the Company object.

If you think about it, only a customer, or your company, can view and change orders. If you have an external 'thing' doing something with the orders you should find out what that thing is and represent it in your model. Every read or write to your data should go through your model.

Edit

You mention that 'the user can import orders', and assuming that 'user' is synonymous with 'customer', then the import method should be on the customer interface.

Now, you talk in your edit about performance issues -- the validate method being very slow -- so you want to optimise it by validating many orders simultaneously. This is actually an implementation detail, not an interface detail (at least, not in your public interface).

You point out that you have an Orders object, which sounds ok to me, but this probably shouldn't be published via your customer interface (your user doesn't need to know about it). The Orders object should be the holder of the orders collection and it should belong to a customer (customer has orders) -- and the customer implementation should delegate the validate command to the Orders object which can optimize this any way it needs to.

This means that a customer doesn't know how to validate an order (which makes sense), but that Orders (your object) does. If it weren't for your performance constraint you could implement validate on orders in the simplest of ways (iterate through orders calling validate), however you do have the constraint so you'll probably have to build some sort of validation object populated with info from the collection of orders, pass it off to your validation service, and react to the response by setting a valid flag on the individual orders.

References

I'd take a look at the book, 'Implementing Domain Driven Design' by Vaughn Vernon, which can be found on amazon.

by anonymous   2019-07-21

When choosing an aggregate root you choose between Transactional Consistency and Eventual Consistency. When your business rules allow you would rather favour Eventual Consistency.

Let's look at Employee and Department. Check against your use cases: is it ok to use eventual consistency for department/employee changes (would users agree to see an outdated orhanizational structure sometimes?)

If yes treat Department and Employee as seperate aggregates. Make Employee reference Department through its id.

If it's not ok (e.g. user would not tolerate wrong deparment for employee in timesheet report) then make Department an aggregate holding a collection of Employee entities.

More on this topic you can find in IDDD book by Vaughn Vernon: https://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577

by anonymous   2019-07-21

You have posed some interesting questions here.

To start with I do not quite agree with

By DDD you define domain events to decouple the domain model from the persistence details.

I think you might be confusing Event Sourcing ES with DDD, ES can be used with DDD but its very much optional in fact you should give it a lot of thought before choosing it as your persistence mechanism.

Now to the bulk of your question, of whether REST and DDD get along if yes how ?

My take on it, yes they do get along, however generally you do not want to expose your domain model via a REST interface, you want to build a abstraction over it and then expose that.

You can refer to this answer here, for a little more detail.

However i cannot recommend enough the Implementing Domain-Driven Design book, Chapter 14 Application deals with your concern to a fair degree.

I could not have explained it more thoroughly than the book and hence referring you there :)

by anonymous   2019-01-13

A summary of Martin Fowler’s definition of the Repository pattern:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

So if we have both add and update methods I could claim it’s not quite a collection-like interface, right? I shouldn’t need to bother checking if an object’s already there when adding to a set-like collection.

There are two common approaches about add/update:

  • Collection-oriented repositories really try to mimic an in-memory collection, so you shouldn’t need to re-add an object if it has been updated but already existed in the collection. The repository (or layers hidden below it, such as an ORM) should take care that changes to an entity are tracked. You just add an object when you first create it and then no more methods are needed after the entity is changed.

  • Persistence-oriented repositories are aware that an object needs to be explicitly “saved” after changes are made, so you call save with an entity when it is created or when it is changed.

(Those are my interpretations of the definitions by Vaughn Vernon in Implementing Domain-Driven Design.)

delete is fine, but perhaps remove would be a better name.

by anonymous   2018-03-19

Domain events express facts that happen in the domain and thus are first class citizens of the domain so there are very very important from the DDD point of view.

Even more, when interfacing with another bounded context, they could represent the contract between the two bounded contexts.

P.S. they are covered by the "red DDD book" in chapter 8.

by anonymous   2018-03-19

Pre-note: there are domains where an address should be an entity, like a mail service; we do not talk about those domains

From my experience, people tend to implement an address as an entity because of the persistence: it is easier to persist an address as a sub-entity to a relational database than to persist a value object because of the entities ID that act as primary keys in the storage table.

However, there are tactics that permit storing a value object as an database entity but still using it just as a value object, as it should be. Vaughn Vernon shows how to do this in his book, Chapter 6, sub-chapter Persisting Value Objects.

by anonymous   2017-08-20

Highly recommend to get through the original source of the Process Manager design pattern as well as @Vaughn Vernon treatment of the topic in his great book Implementing Domain-Driven Design

In a nutshell, Process Manager deals with multiple processes concurrently via Process instances that it creates when a specific process is initiated. Id of a Process instance is your Correlation Identifier that is part of the payload of every communication (commands/events) in the duration of the process. There is another term for Process instance, that is Process Tracker. The idea is the same.

So in this approach, there is a clear separation of concerns. Every Process Instance is responsible for its own process in terms of its current state, retries, finishing etc. It is a Process Instance that is responsible for emitting ProcessFinished event since it is the "brain".

Another name for Process Manager is Long Running Process. So by definition, it is better be asynchronous.

~ Sergiy

<><

by anonymous   2017-08-20

If you are looking for deeper insights in how to layer real software and what proper names they should have you should read about Domain Driven Design

First and classic book (be aware that it's very general). As for something practical you can check out this book or just google for some online examples.

by anonymous   2017-08-20

As mentioned by @inf3rno in Access Control in Domain Driven Design, Vaughn Vernon briefly touches upon this in his book Implementing Domain-Driven Design.

Security and permissions should be centralized in its own bounded context, which is then used by other bounded contexts. Have a look at the Identity Access bounded context for inspiration, but I recommend following Schneier's Law, which states that you should not build your own security system.

by anonymous   2017-08-20

So where should I put the access control logic?

According to this: https://softwareengineering.stackexchange.com/a/71883/65755 the policy enforcement point should be right before the call of the UserService.editProfile().

I came to the same conclusion: it cannot be in the UI because by multiple UIs we would have code repetition. It should be before the creation of domain events, because they indicated that we have already done something in the system. So we can restrict the access to domain objects or to services which use those domain objects. By CQRS we don't necessary have domain objects by the read model, just services, so we have to restrict access to the services if we want a general solution. We could put the access decisions at the beginning of every service operation, but that would be grant all, deny x security anti pattern.

How should I implement it?

This depends on which access control model fits to the domain, so it depends on the user story. By an access decision we usually send an access request and wait a permission in return. The access request usually has the following parts: subject, resource, operation, environment. So the subject requires permission to perform an operation on the resource in an environment. First we identify the subject, then we authenticate it, and after that comes the authorization, where we check whether the access request fits to our access policy. Every access control model works in a similar way. Ofc. they can lack of some of these steps, but that does not matter...

I created a short list of access control models. I put the rules, policies into annotations, but normally we should store them in a database probably in XACML format if we want to have a well maintainable system...

  • By identity based access control (IBAC) we have an identity - permission storage (access control list, capability list, access control matrix). So for example by an access control list, we store the list of the users or groups whose can have permissions.

    UserService
        @AccessControlList[inf3rno]
        editProfile(EditUserProfileCommand command)
    
  • By lattice based access control (LBAC) the subject has a clearance level, the resource has a required clearance level, and we check which level is higher...

    @posseses[level=5]
    inf3rno
    
    UserService
        @requires(level>=3)
        editProfile(EditUserProfileCommand command)
    
  • By role based access control (RBAC) we define subject roles and we grant permissions to subjects whose act the actual role.

    @roles[admin]
    inf3rno
    
    UserService
        @requires(role=admin)
        editProfile(EditUserProfileCommand command)
    
  • By attribute based access control (ABAC) we define subject, resource and environment attributes and we write our policies based on them.

    @attributes[roles=[admin]]
    inf3rno
    
    UserService
        @policy(subject.role=admin or resource.owner.id = subject.id)
        editProfile(EditUserProfileCommand command)
        @attribute(owner)
        Subject getOwner(EditUserProfileCommand command)
    
  • By policy based access control (PBAC) we don't assign our policies to anything else, they are standalone.

    @attributes[roles=[admin]]
    inf3rno
    
    UserService
        editProfile(EditUserProfileCommand command)
        deleteProfile(DeleteUserProfileCommand command)
        @attribute(owner)
        Subject getOwner(EditUserProfileCommand command)
    
    @permission(UserService.editProfile, UserService.deleteProfile)
    @criteria(subject.role=admin or resource.owner.id = subject.id)
    WriteUserServicePolicy
    
  • By risk-adaptive access control (RAdAC) we base our decision on the relative risk profile of the subject and the risk level of the operation. This cannot be described with rules I think. I am unsure of the implementation, maybe this is what stackoverflow uses by its point system.

  • By authorization based access control (ZBAC) we don't do identification and authentication, instead we assign permissions to identification factors. For example if somebody sends a token, then she can have access to a service. Everything else is similar to the previous solutions. For example with ABAC:

    @attributes[roles=[editor]]
    token:2683fraicfv8a2zuisbkcaac
    
    ArticleService
        @policy(subject.role=editor)
        editArticle(EditArticleCommand command)
    

    So everybody who knows the 2683fraicfv8a2zuisbkcaac token can use the service.

and so on...

There are many other models, and the best fit always depends on the needs of your customer.

So to summarize

- "security concerns should be handled outside the domain"
- "access control requirements are domain specific"

both can be right, because security is not part of the domain model, but its implementation depends on the domain model and the application logic.

edit after 2 years 2016-09-05

Since I answered my own question as a DDD newbie, I have read Implementing Domain-Driven Design from Vaughn Vernon. It was an interesting book in the topic. Here is a quote from it:

This constitutes a new Bounded Context - the Identity and Access Context - and will be used by other Bounded Contexts through standard DDD integration techniques. To the consuming contexts the Identity and Access Context is a Generic Subdomain. The product will be named IdOvation.

So according to Vernon probably the best solution to move the access control to a generic subdomain.

by anonymous   2017-08-20

a) This is not a strict constraint, but offers certain advantages. The idea behind the rule is that domain services contain functionality that supplements existing entities and value objects. Another non-strict constraint is closure of operations where both the argument and the return value of domain service methods are of the same type. Both of these constraints promote immutability and a functional style thereby reducing side-effects and making it easier to reason about the code, refactor the code, etc.

It is possible to have a domain service method that accepts a primitive type which is neither an entity or value object. However, extensive use of primitive types can result in primitive obsession.

b) This constraint can be applied at the entity and value object level to an extent. Entities and value objects compose more primitive types to form complex types and some behaviors may depend on a primitive parameter. This primitive parameter can itself be turned into a value object.

UPDATE

Just returned from DDD meetup where I had a chance to talk this over with Vaughn Vernon author of Implementing Domain-Driven Design. He agrees that the specified constraint is not strict. In other words, there are scenarios where it is perfectly acceptable for a domain service method to be parameterized by primitive types.

How do the two constraints promote immutability?

The idea is that a domain service does not mutate state and all state changes are made explicit through parameters. This is the essence of a pure function. Given that domain services complement entities, their methods should be expressed in those terms.

What is functional style?

I'm referring to functional programming. Programming in a functional style usually entails immutability and pure functions. Another trait of a functional approach is a declarative style contrasted with imperative.

So we should try ( since it may not always be possible to use force ) to force the Service to use domain objects as parameters and return values

No. If a primitive type suffices for an operation there is no reason to coerce it into something else. The use of entities and value objects is only a guideline and some prefer to be more strict than others. Some, for instance, use an explicit type to represent identities for each entity. So instead of using int you'd create a value object called OrderId to represent an identity of an order.

So is it due to some sort of intrinsic characteristic of Domain Entities/Value objects that in most cases their behaviors ( ie their operations ) operate on primitive types ( ie use primitive types as parameters )?

I wouldn't say it is intrinsic to DDD. I was referring to the more general idea of composition - complex entities (non-DDD) are composed out of simpler ones. By this token, it makes sense that operations on complex entities would be expressed in terms of constituent parts.

UPDATE 2

a) A domain service can avoid state mutation by returning new instances of objects instead of modifying the objects that were passed in. In this way, the signature of the method fully describes what it does because there are no side-effects.

b) A domain service can mutate state of an object passed to it, in which case the return type would likely be full. This however is less desirable - it would be better for a DO to mutate its own state.

c) Yes that is part of it. Immutability and purity allow you to refactor code much like you would factor an algebraic equation with substitution. Another reason is that it makes reasoning about the code easier since if you look at a piece of immutable data you can be certain it doesn't change for the remainder of its scope.

d) Yes, although in that case it would be better for the domain object to mutate itself. This mutation would be invoked by a surrounding application service. A lot of times I pass domain services to entity behavior methods to provide them functionality they don't have access to directly.

e) The notion of closure of operations does not in and of itself promote immutability but it is a characteristic of immutable code. The reason is that a if a domain service method accepts a value of type T and returns a value of type T it can indicate that it returns a new value of T resulting from the encapsulated operation. This is a characteristic of immutability because the change resulting from the operation is made explicit as a new object.

UPDATE 3

a) This has more to do with traditional OOP than it does with DDD. OOP tries to hide the moving parts behind objects - encapsulation. FP tries to minimize the moving parts - immutability. Immutability can be seen as more "natural" in some scenarios. For example, in event-centric scenarios, events are immutable because they are a record of what has happened. You don't change what has happened, but you can create compensating actions.

b) Again, this has more to do with OOP than DDD and is based on the information expert pattern which essentially states that behaviors on data should be as close as possible to that data. In DDD, this means that an entity should encapsulate the contained data as much as possible so that it can ensure its own integrity.

by anonymous   2017-08-20

The whole Chapter 6 of Eric Evans book is devoted to the problems you are describing.

First of all, Factory in DDD doesn't have to be a standalone service -

Evans DDD, p. 139:

There are many ways to design FACTORIES. Several special-purpose creation patterns - FACTORY METHOD, ABSTRACT FACTORY, and BUILDER - were thoroughly treated in Gamma et. al 1995. <...> The point here is not to delve deeply into designing factories, but rather to show the place of factories as important components of a domain design.

Each creation method in Evans FACTORY enforces all invariants of the created object, however, object reconstitution is a special case

Evans DDD, p. 145:

A FACTORY reconstituting an object will handle violation of an invariant differently. During creation of a new object, a FACTORY should simply balk when invariant isn't met, but a more flexible response may be necessary in reconstitution.

This is important, because it leads us to creating separate FACTORIES for creation and reconstitution. (in the diagram on page 155 TradeRepository uses a specialized SQL TradeOrderFactory, not a general general purpose TradeOrderFactory )

So you need to implement a separate logic for reconstitution, and there are several ways to do it (You can find the full theory in Martin J Fowler Patterns Of Enterprise Application Architecture, on page 169 there's a subheading Mapping Data to Domain Fields, but not all of methods described look suitable(for example making the object fields package-private in java is seems to be too intrusive) so I'd prefer only one of the following two options

  • You can create a separate FACTORY and document it so that developers should only use it only for persistence or testing.
  • You can set the private field values with reflection, as for example Hibernate does.

Regarding the anemic domain model with setters/and getters, the upcoming Vaughn Vernon book criticizes this approach a lot so I dare say it is an antipattern in DDD.

by anonymous   2017-08-20

Usually DTOs have no logic (or very simple transformation logic, such as returning a person's age from a date of birth).

You can use the pattern you have there... definitely, it's just that the objects are not really DTOs but more rich objects (that's usually good). You're not adding a 'DTO' suffix to you class names, so I would say that you're doing fine, because a Request object could have some behaviour.

Edit

I see what you're trying to do. It's possible to do using Dependency Injection + AOP, but I think there are other patterns that might have a more clear distinction and a lot less black magic.

With the approach you want to use, your Request is the entry point to your application (to the core of your domain) and represents the use case you want to run.

The approach I usually use, which is based on Domain-Driven Design (DDD) and Hexagonal Architecture, is to have DTOs which might some kind of binding to the transport technology (for example xml/json annotations). And I use a layer of Application Services which serve as a façade into the domain logic. The Application Service is just responsible for orchestration, not for business logic.

As part of the orchestration, the Application Service needs to get a reference to an object that does have the business logic. In DDD these objects are usually Aggregates.

I think I would write a lot more about this, but there are already quite a few really good resources explaining how to design good applications, and the explanation there is way better than what I can do here :).

If you are interested in this, and don't mind spending a bit more time (and maybe a few bucks). I strongly suggest you to get a copy of Growing Object-Oriented Software and Implementing Domain-Driven Design. Both are excellent books, very easy to read, and luckily all the examples are in Java.

by galeaspablo   2017-08-19
> If you aren’t familiar with the database pattern known as event sourcing (don’t worry — it’s relatively new),

It's not relatively new. That “transaction file” thing in your database? Event Sourcing.

https://www.amazon.co.uk/Domain-driven-Design-Tackling-Compl... https://www.amazon.co.uk/Implementing-Domain-Driven-Design-V...

-----------------

If that doesn't do it for you, please just remember the good old CAP theorem.

https://en.wikipedia.org/wiki/CAP_theorem