Reputation: 185
Using DDD and following the clean architecture pattern and I'm a bit confused on where the ideal location is for configuring display properties for specific domain model ID's. That sounds confusing, I think I can best explain it with an example:
Here the domain model's business logic is simple: calculates a "scaled" value from an input, gain, and offset.
//Domain Model
public class Transducer
{
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
We have a use case that coordinates user actions with the domain models and manages persistence. The details here an unimportant so I've only included an example interface:
//implementation of execution of business logic and persistance would go in the implentation, details left out for this example
public interface ITransducerUseCase
{
IEnumerable<string> GetAllTransducerNames();
void AddNewTransducer(string Name, double Gain, double Offset);
void SetGain(string Name, double Gain);
void SetOffset(string Name, double Offset);
void SetRawValue(string Name, double Raw);
double GetScaledValue(string Name);
}
The use case is used by the controller to coordinate the use cases with a view or other controller. This specific controller allows the viewing of all the transducer names and can change their Gain property.
public class Controller
{
ITransducerUseCase _TransducerUseCase;
//these are sent to the view to be displayed
public Dictionary<string, double> _transducerScaledValues = new Dictionary<string, double>();
public Controller(ITransducerUseCase TransducerUseCase)
{
_TransducerUseCase = TransducerUseCase;
//Get all the names and populate the dictionary to display.
foreach (var transducerName in _TransducerUseCase.GetAllTransducerNames())
_transducerScaledValues.Add(transducerName, _TransducerUseCase.GetScaledValue(transducerName));
}
//bound to the view
public string SelectedName { get; set; }
//bound to the view, a property for setting a new gain value
public double Gain { get; set; }
public void OnButtonClick()
{
//update the gain
_TransducerUseCase.ChangeGain(SelectedName, Gain);
//get the new scaled value
_transducerScaledValues[SelectedName] = _TransducerUseCase.GetScaledValue("PumpPressure");
}
}
That's the scaffolding for this question. Here is the new requirement:
We want to have an application level configuration setting for the
"number of decimal places" that is displayed for the ScaledValue
of
Transducer
on an identity basis. So a transducer with Id
"PumpPressure" could have a different value of DisplayRounding
than
the transducer with the name "PumpTemperature".
This setting must be application wide (any time the value is
displayed, use this setting). This setting could also be used if the
ScaledValue
was ever logged to a file, so it's a cross cutting
business need.
The solutions I've thought of:
Placing a property in the Domain Model and returning it through the layers to the view. This does not seem like a logical place because the DisplayRounding
property does not have any relevance to the business logic.
public class Transducer
{
//This seems like an SRP violation
public int DisplayRounding { get; set; }
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
Could we put it in a separate Domain Model without any business logic? Persistence could be managed by the same Use Case class or a separate one.
public class TransducerDisplaySettings
{
public int Rounding { get; set; }
//plus other related properties
}
Pros: It separates out the concerns better than having one combined model.
Cons: The model does not have any business logic, is this okay?
We've also considered managing these settings completley on the outer layers with some sort of service.
Pros: No domain models without business logic
Cons: Would probably be tied to a specific framework?
Are are there more pros/cons I'm missing? Is one approach obviously better than the other? Is there an approach that I completely missed? Thanks!
Upvotes: 1
Views: 100
Reputation: 3573
The central decision you would have to make is whether the display rounding is an aspect of your applications business logic or "just an aspect of display".
In case you consider it as important for your business logic it should be modeled with your entities.
In case you consider it just as an aspect of "presenting values to the user" (so not relevant for business rules) it should be stored in a separate repository or service and then applied by the "presenter".
Upvotes: 1
Reputation: 1
[table("NameTable")]
public class Transducer
{
//Name is the ID
[Key] //is Key from table
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
Upvotes: 0