4

I am reading about DDD and in the examples it is common to see how the domain gets the data from database, do the business logic and then persist the data. For example to update a field:

class MyDomainClass()
{
    //Dependency injection of the repository
    public MyDomainClass(IRepository paramRepository)
    {
        _repository = paramRespository;
    }


    public static DoWork(Type1 paramData1, Type2 paramData2)
    {
        var myDomainInstance = _repository.GetEntity(entityID);
        
        //do work

        _repository.Persist();
    }
}

But my doubt is, if the domain model only has to do the business logic, why does it has to load the data from the database and persists the updates in the database? wouldn't it be this responsability in a upper layer that load the data, call the methods of the domain classes and then persist the data? Perhaps this upper layer could be a service layer or application layer.

Somthing like that:

class MyDomainServiceDoWork
{
    public MyDomainServiceDoWork(IRepository paramRepository)
    {
        _repository = paramRepository;
    }


    public void DoWork(Type1 paramData1, Type2 paramData2)
    {
        var myDomainEntity = _repository.GetEntity(entityID);
        myDmainEntity.DoWork(paramData1, paramData2);
        _repository.Persist();
    }
}


    class MyDomainClass()
        {
            //No dependy injection in this case.
            public MyDomainClass()
            {
            }
        
        
            //Now the method doesn't need to be static
            public DoWork(Type1 paramData1, Type2 paramData2)
            {
                //No get the instance from database.
                
                //do work
    
                //No persist data here, it is responsible of the service
            }
        }

Also someone comments that the domain should to be implemented thinking that the classes are in memory. According to that, then persist the data seems not have sense, because it works only in memory.

Another point that is related is that sometimes I have read that if the domain classes can be used in the UI, it is an option. I like this idea, because I can create instances locally and use the business logic of them and no persist the data. I think it is interesting because I can validate the data, and if it is correct, then call the service or application layer methods that I know that it will pesist the data. here de UI has to know that the services persist data and the domain model just do business logic.

One example in the UI could be this:

var myDomainInstance = new MyDomainClass();

//this no persist data, just I use it to have a local instance for validating and to use locally if the action is OK.
var myAction result = myDomainInstance.DoAction(userData1, userData2);

if(myActionResult != null)
{
    //notify user which data is incorrect and the problem.
}
else
{
    //This persist the data
    MyService.DoAction(userData1, userData2);
}

//Here I can use myDomain instace as local variable to work with it. If I could persist the data in database, then I get the same state in myDomainInstance than in database.

Well, in the example I don't want to detail the way to handle the errors, there are many options for that. My objetive it is to show the idea to use in the UI the domain model or the service according to the needs.

In sumary, I would like to know why it is so common to get the data from database and persists the changes in the domain classes. I guess it is more flexible to have a domain to only do the work of the domain and let to another the responsability to persist the data. So a consumer (the UI or user) can decide when persist the data, using the service or only want to do a work in the instance of a domain that it has locally.

Thanks.

3 Answers 3

3

But my doubt is, if the domain model only has to do the business logic, why does it has to load the data from the database and persists the updates in the database?

It doesn't load the data, nor does it persist the updates. It tells someone else (i.e. the repository) to load the data and to persist the updates.

Don't confusing doing a job with instructing someone else to do a job, because these are very different when you are considering a class' responsibilities.

At the end of the day, it is the repository which decides how to load data and how to persist it. The only thing the domain does (other than the business logic) is connect itself to the repository.

So a consumer (the UI or user) can decide when persist the data, using the service or only want to do a work in the instance of a domain that it has locally.

Keep in mind that you're asking a question about domain-driven design. It is the domain who calls the shots here. It doesn't do the legwork (that's what the repository is for), but it does make the final call on whether the repository gets instructed to do something or not.

I guess it is more flexible to have a domain to only do the work of the domain and let to another the responsability to persist the data.

If you do this, then you effectively demote the domain. It is now no longer the big boss calling the shots, because "another" is now telling the domain to execute a specific job, rather than let the domain define the job that needs to be done.

The core of DDD is that the Domain is the big boss of the logic, and the other layers exist mostly to shoulder the burden of minor tasks (such as persistence or mapping), so that the Domain can focus solely on the business logic itself. It's about delegation: the domain calls the play and the surrounding layers execute it. This ensures that the domain logic remains as simple, readable and change-friendly as possible.

The inability to easily adapt or adjust the core bsuiness logic is a very common cause for software applications to hit a very difficult, slow and/or expensive maintenance phase. DDD tries to avoid this as best as possible by keeping the domain logic light and undistracted by technical implementation details such as which DB server to connect to or how to map to DTOs.

9
  • Well, supose that I have orders and lines and I want to add a new line to an order. The domain validate data, ensure the line can be added and do it. For my first understanding, this is the business logic, and the domain do this work. But for me it is more confuse why the domain has to decide to persist the data or not. It did its job, add the line and ensure a coherence data. Perhaps I want only work in memory, if the domain persists data, I couldn't do that. Commented Aug 8, 2022 at 10:43
  • @ÁlvaroGarcía: The domain is able to decide for itself whether it wants to (a) enforce that data will be persisted, no question about it (= private implementation) or (b) allow external consumers to decide to persist the data or not (= exposing its own public save method which links to the persistence save method). By routing this via the domain, it is the domain who decides how things work, which is exactly what DDD tells you to do. But one of those possible decisions can be to give the consumer the ability to indicate a save, if the domain consents to this possibility.
    – Flater
    Commented Aug 8, 2022 at 11:24
  • @ÁlvaroGarcía: Think of the domain like a monarch who has the power to allow/disallow anything they please. If you let the BLL directly call the DAL's save method, then you are bypassing the domain and preventing it from disallowing this from happening under certain circumstances. To continue the analogy, bypassing the monarch's authority is treason and punishable by death penalty in DDD-land.
    – Flater
    Commented Aug 8, 2022 at 11:27
  • Then in the second option where domain exposes a public save to allow consumers to decdie when to save. In this case, whold the domain have two public methods, one for Dowork() and another Save() and the cousmer, UI, calls both, Dowrk() and then Save()? So in the UI the consumer can decide when it only wants to run the core business logic and when to save the results? Commented Aug 8, 2022 at 11:48
  • Or perhaps I could have 2 methods in the domain classes? DoWork() and DoWorkWithPersistance()? Commented Aug 8, 2022 at 12:01
3

As you show in your examples, something has to interact with the datalayer it's really a question of naming and how much you split things up.

Its always good practice to have some, in memory only, operation to deal with any complex logic because it makes things easy to test. But if you have a Domain object for a business operation of some kind, you want its naming and use to match the business definition of the process, which will involve saving to a database.

No one says you can't split a domain operation into multiple sub domain objects though eg.

CashRegister
   Buy(string[] items)
   {
     //create orders
     //save to db
     //work out price
     //create invoice
     //save invoice
     //charge customer
     //save payment
   }
      
SummerSalePriceCalculator
    public Invoice PriceOrder(order o)
    {
       //in memory price calculation, returns a invoice object
    }

VisaPaymentProcessor
    public bool ChargeCard(...)
    {
       //connect to third party and take a payment
    }

etc etc

All these are Domain objects of one kind or another, only the top level one talks to the data layer.

I could take the save stuff out of the CashRegister, but then I would A. Need some other object to to it and what am i calling that and B. If I'm doing DDD I've had some meeting with the Sales team where they have told me they have a process where "a [Customer] [Buy]s [items] using a [Cash Register]" and that "[Buying] means the [order] [invoice] and [payment] are saved to a database".

I have identified these are "domain terms" and I am making my objects names and code match them so that the code matches the way the business talks and thinks

2
  • Perhaps depends on the sales team, but in this example the sales team stablishes when to save the data or where. Is this responsability of the sales team? Or the sales team just should to tell a customer buy items and a cash register is used for that and it will be needed to create an order and invoice and do the payment after the order is finished. And other details of the process of the sell. Does sales team to decide where, how or where to save that? In my case, when I ask, they told me the process but they don't concern about technics aspects, like where, how or when to save data. Commented Aug 8, 2022 at 11:19
  • My point is "the business" whatever dept you are getting your requirements from will definitely have persisting the order somewhere as part of the "Buy" process. If you are doing DDD that means you have a "Buy" method which persists the "Order"
    – Ewan
    Commented Aug 8, 2022 at 19:43
1

I don't think there's a rule of thumb for this question. You will find reasons to make the domain model agnostic to persistence. One good reason can be testing. No integration to mock or stubb.

If you consider the Business to be a layer (where you make the core valuable by how you manage it), I would dare to say that it's here where the need for persistence arises. So it's here where you define the ports for repositories, load and process the data with the core and persist the results.

This, indeed, increases the levels of abstractions of the application hence, increases the overall complexity.

You have to weigh the pros and cons of segregating responsibilities like this, the same way you weigh the tradeoffs when decoupling components in the source code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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