Presenter Logic || Domain Service Logic || Repository Logic?
Obviously the answer to the titular question is yes.
I have recently found myself questioning whether the logic I am coding belongs in a domain service or in the presenter. I actually found the same logic in the presenter residing the base repository. Something definitely smells wrong, almost like the putrid smell of death, lol, nah just a DRY smell and a hint of mixed responsibility odor. The presenter was calling the Repository directly which was kinda of an indicator, but it is valid to do so, depending on the scenario.
The application that I am currently working in is a web application. That being said, I feel it is valid to consider the web limitations part of the current domain, not just a concern of the presentation. If we need to move to a windows app or something else, it will take a lot of refactoring, so why not just view the web’s issues as part of what affects the domain. Besides, is the purpose of the domain to be abstract enough to support multiple platforms or to dimish complexity? Anyway, that’s another discussion altogether, and I’m digressing.
Here’s the skinny, that’s a valid colloquialism isn’t it. I found string to integer conversion happening in two different places. Once in the presenter, grabbing a string Id from the view, converting it, calling an overloaded GetById method from the repository or throwing an exception if the Id was invalid. The overloaded GetById method was in the base repository, it either accepted a string Id or integer Id, if the string Id was invalid it was throwing an exception. Yikes, this is scary, and to think I was the one that coded all this, frightening, I know. I am recovering so don’t you worry yourself. Now to the current code (all code below is pseudo code, simplified for example purposes):
Code to be Refactored:
Presenter
public virtual void InitializeView()
{
if(TreatmentIdIsValid())
LoadTreatment();
else
throw new ApplicationException(string.Format("A Record of Waste cannot be completed because of the invalid treatment id: {0}", View.TreatmentId));
}
private bool TreatmentIdIsValid()
{
int validTreatmentId;
bool treatmentIdIsValid = int.TryParse(View.TreatmentId, out validTreatmentId);
if(treatmentIdIsValid)
CurrentTreatmentId = id;
return treatmentIdIsValid;
}
protected virtual void LoadTreatment()
{
try
{
CurrentTreatment = Repository<ITreatmentRepository>.GetById(CurrentTreatmentId);
}
catch
{
throw new ApplicationException("Could not retrieve the specified treatment");
}
}
Base Repository
public virtual Entity GetById(string id)
{
int parsedId;
if (!int.TryParse(id, out parsedId))
throw new ApplicationException("Could not convert the given id: " + id + " into an integer");
return GetById(parsedId);
}
public virtual Entity GetById(int id)
{
return Session.Get<Entity>(id);
}
I think that there is no place for logic in the repository it should be left to the domain service. You could even argue that this functionality is common and can be moved to a domain utility. For ease I am going to move it to a domain service. Now, lettuce see the refactoring to the code above:
Refactored Code:
Presenter
public virtual void InitializeView()
{
LoadTreatment();
}
protected virtual void LoadTreatment()
{
CurrentTreatment = RecordOfWasteService.GetParentTreatmentById(CurrentTreatmentId);
}
Domain Service
public virtual Treatment GetParentTreatmentById(string id)
{
int validTreatmentId;
if (!int.TryParse(id, out validTreatmentId))
throw new ApplicationException("Could not convert the given treatment id: " + id + " into an integer");
return GetParentTreatmentById(validTreatmentId);
}
protected virtual Treatment GetParentTreatmentById(int treatmentId)
{
try
{
CurrentTreatment = Repository<ITreatmentRepository>.GetById(treatmentId);
}
catch
{
throw new ApplicationException("Could not retrieve the specified treatment");
}
}
Base Repository
public virtual Entity GetById(int id)
{
return Session.Get<Entity>(id);
}
Alrighty then, we got any logic out of the repository, I’m feeling better already, my face has gone from grimace to grin, and no not the McDonlad’s character Grimace. Super serial, a la Al Gore about ManBearPig, what was Grimace, was he what you turn in to if you only eat McDonalds and nothing else?
The responsibility of the repository should be to read and write to persistence/web services/messages etc. The string validation logic is in the domain service, I may pull it out to a base service or utility service. Our presenter is so much simpler now, and not worried about logic that it shouldn’t have to worry about. Hmm, the cleanliness is delightful. There is no more duplication of logic in the presenter and repository, w00t! Now let me know your thoughts, comments, opinions etc. of dissent or agreement, it will help me and hopefully others learn and grow. I’m off to watch the some Teenage Mutant Ninja Turtle original series, wow, I’m a nerd.