0

In many cases, there are different kind of forms in an application's user interface, and these forms are use to collect all the data - that is needed to update (or create of course) domain object (e.g. Person entity in Person Register application).

When the entire Person entity's data is transferred as DTO to backend softaware, so how to save the changes in DDD way? I have read several blog posts, where is guided that the every single way to change or fix data, should handle as an own business operation - such like changeAddress() or amplifyDescription(). But now I have all the changes in one DTO object, so what's next? Can I contemplate the DTO as a set of business operations and now I have to only transform those "commands" to real business operation calls? The fact is that it's quite usual that there are many operations put together in UIs and in some way, I have to handle it in backend.

I think that mapping dtos to domain objects using some kind of automapper or by hand, is wrong and anemic way to get things work, and it'd consist a lot of boilerplate and meaningless code.

  • If all your changes are in one DTO and your form is called "Edit Entity" whatever the entity is, you are not doing DDD, you are doing CRUD. The fact of using DDD tactical patterns like aggregate root and repository, does not make your application anyhow related to DDD. How Vaughn Vernon states - DDD is defining ubiquitous language within the bounded context. But CRUD applications have nothing like this anyway. – Alexey Zimarev Feb 26 '16 at 13:06
4

You might want to have a look at the concept of Task-Based UI.

Under that paradigm, not only do the back-end layers reflect your domain processes, but the front end is also built with the end user's ultimate business goal in mind. There might not be a 1-to-1 mapping between user tasks and domain operations 100% of the time, but this is in any case a big help to force you to think outside the CRUD box including at the UI level.

1

This is not all too different from what you would get in a web application: a big form that is logically split up could be sent to the server in one go so you would get all the data in a single 'DTO' (the request itself). The best way to go about this is indeed split the data from the DTO into commands that have a logical grouping of the data. For example, let's assume that your screen has both the address for a person, information on the bank account refunds should go to AND alternative contact information. Your DTO will contain all of this information.

The code that gets this DTO now needs to transform this into 'commands' to send to the domain. These 'commands' will have a logical grouping of your data. The command to send to your domain to change the address will only contain the information that is useful to that command (street and number, postal code, town, etc...) The command to change refund information will only require you to send that information. In that regard, the domain does not know (and does not care) about the UI. It only cares about receiving all the information it needs to perform the requested action(s).

Now, you should probably think about the UI of your application in general as well. If you are applying DDD, think about your UI with DDD glasses. Does it really make sense to have one big screen where a user can change everything? Or is it better to have your UI reflect the real world a bit more, where a user would either 'change address' because he's moved, or 'change refund information' because he's switched banks?

  • Thank you for you answering. Like I said "It's quite usual that there are many operations put together in UIs" means that in our company, I don't supervise front end developing, only the back end, so I can't (so much) affect, what is happening in that side. But what is your opinion, should the application service provide these atomic business commands in its interface or should the interface be more coarse-grained and handle the whole updating ie. which layer is responsible for that orchestrating? – Toni Feb 9 '16 at 13:23
  • What do you mean by 'application service', exactly? – JDT Feb 9 '16 at 15:26
  • I mean component wrapper around domain layer, which provides public interfaces to other components and rest-endpoint layer (ie. Spring Web MVC Controllers) and inside the wrapper it implements those services (which interfaces expose) using domain objects, domain services, factories and repositories etc.. – Toni Feb 9 '16 at 15:39
  • Expose small interfaces with clear, well-defined responsibilities. Just because the design of the UI is sub-optimal doesn't mean your code should be. And having no control over it means that when the UI changes you want to avoid large, sweeping changes throughout the code you have control over. – JDT Feb 9 '16 at 18:14
  • Yeah, I arrived at same conclusion. Thank you for your help. – Toni Feb 9 '16 at 18:23
-2

The way you're describing the changes as business operations is often employed with event sourcing, but of course you don't need to do event sourcing to follow the advice. The question then is why you want to use it - do you just intend to store an audit trail? Or do you just don't like the Object->DTO->DB approach and would prefer Changed object->[operations]->DB?

My experience with that concept is that while it sounds really nice and clean, in practice it's really hard to do in a meaningful way.

  1. Either you need a whole host of "edit buttons" (you'd arrange your ui slightly different and name things in another way, but the concept is the same) for all kinds of ways you might change data. For anything other than smallest object, you will not get that right. If you do this, then just store the (possibly compressed) sequence of operations.
  2. Or you need to guess what change was made, and that won't work if you want to map it to business operations. Was the address change due to misspelling or to the person moving?

Now, for me, this means that the most common interface type, namely "I want to change any of the values for this object", is a bad fit. The one thing you can extract is the diff of two objects. This is cumbersome in most OO languages, but can be done.

One suggestion if you go that path, would be to use the way svn or git does it. Keep track of what version the user started working with, check what version it is at the time of commit, and then compare these with the changed version. If the user wasn't up to date, you have multiple options; stop the commit, or allow the commit under certain conditions (needs to be chosen with domain expert).

Then take the minimal diff and use it; apply it in the database, store it in the audit log. (This is of course roughly what ORMs are doing on the original object.) You get an (in theory) replayable log, you don't have to come up with a large set of operations and you don't force users to use foreign user interfaces.

(Personally I've started to abandon "DDD techniques" for a more data/value oriented approach. The burdens and rigidity of "pure DDD techniques" weighs down much of the code, often with little gain other than the feeling of doing something right. I say "DDD techniques", DDD as an agnostic design idea is still good.)

  • For the love of Greg Young, don't go around doing Event Sourcing everywhere. This example by no means gives any indication for the need to do Event Sourcing. Event Sourcing and DDD are very different things. – JDT Feb 9 '16 at 12:55
  • I didn't think I was advocating Event sourcing? I merely said that treating business operations as concepts in code rarely have much point outside of event sourcing. I wouldn't call an audit trail event sourcing, if that's what you're meaning. – NiklasJ Feb 9 '16 at 13:16
  • If you have a person.changeHomeAddressTo(...insert home address object here...), that to me feels like a business operation that is also a concept in the code. Neither that, nor something like an audit trail for that matter, has anything to do with Event Sourcing. – JDT Feb 9 '16 at 13:26
  • Yes, I agree. And I think that the specific example, "changeHomeAddressTo" is representative of the vast majority of problems, and is not a useful concept. I'm suggesting that almost always, this is an overworked solution and that OPs request of saving the object in a "DDDish way" by adding the concept of a business operation right before persistance is a waste of time. – NiklasJ Feb 9 '16 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.