-1

So for e.x I have an entity Payment and a config Payment settings.

class Payment 
{ 
    public Payment(PaymentSetting setting, ....other fields){}
    internal Payment() /*strictly for the ORM**/ 
    //Other properties and behaviour
} 
class PaymentSettings 
{ 
    public Timespan TransactionTimeout {get; private set;} 
    //Other properties and behaviour
} 
class Order /AggregateRoot*/ 
{ 
    List<Payment> payments {get; private set;} 
    //Other properties and behaviour
}

There is no problem when I am going to create Payment object as I can inject the setting to constructor. But How do we inject config when the Order is loaded from DB?

I understand in the current example, Config is needed while creating the appointment only, and we can store the exact value as part of Payment object and revive it when needed. But what happens, if we need to know the latest config? Should add Methods to inject it from outside? Is it considered an acceptable practice wrt. DDD

8
  • Is TransactionTimeout really a part of the domain, or is it ancillary to the implementation of a given repository?
    – Kain0_0
    Nov 6, 2020 at 7:18
  • TransactionTimeout can be used Payment method to decide whether a Payment should be abandoned after certain period of time. Nov 6, 2020 at 7:21
  • 1
    Your Payment domain object doesn't have to be the same as the entity you store in the database. You can have your repository return Payment domain objects that wrap the database entity, or if that's slow, you could perhaps reuse the same wrapper as you iterate. Nov 6, 2020 at 7:51
  • 2
    @CodeNameJack not suggesting that it should. My initial query was because timeout is often an implementation detail. My follow up suggestion is that there might be two domain objects here that are being conflated as one. Namely the state of a given transaction, and the rules behind transaction state changes. those are by no means the same domain concept.
    – Kain0_0
    Nov 6, 2020 at 9:10
  • 1
    @Kain0_0 Yes, but even in that case the Transaction State will take some dependency on config. Now if each of them have a full dependency on either config server or Db it is ok. But if one of the classes has some parts coming from Db and some from config, this kind of trouble comes. However as I describe my problem in detail, I am getting a feeling that this is actually a persistence concern and should be handled separately in Repository object. But still I wanted to know what if other practices exist. Nov 6, 2020 at 9:20

2 Answers 2

3

Business rule configuration belongs in the domain itself. Something like

public class PaymentSettings
{
    private static readonly TimeSpan DefaultTransactionTimeout = TimeSpan.FromHours(24);

    public TimeSpan TransactionTimeout => DefaultTransactionTimeout;
}

If you have a use case that certain rules should be editable at runtime, you should create a UI for it, at which point it makes sense to store the value in the database.

1

I mostly agree with Rik D's answer, but I would make one modification: allow the transaction timeout to be set from the public context. Then you just need a little glue code closer to the composition root of the application to read the values from the config file and set the static property.

Payment.TransactionTimeout = // read from configs

Configuration data remains constant over many separate invocations of use cases. It teeters on the line between unchanging data and application state. You have correctly identified this PaymentSettings object as a little difficult to deal with. If the data only changes when the config changes, your application will likely need to be restarted or re-initialized.

Encapsulate this in your domain as static properties on certain classes using simple built-in types or enums. You could keep the PaymentSettings as a class and set that on a public static property if this info is too complex:

Payment.Settings = new PaymentSettings (/* read from configs */);

The main goal here is to decouple domain configuration from application configuration.

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.