Having seen Jimmy Bogard's excellent video on crafting wicked domains, I tried to apply the same principles to one of my existing projects to evaluate how well i have grasped the concept. I have my queries and doubts listed below.
Domain Background: Admin can view a list of companies. He then approves a company. The database is supposed to update a Boolean field to true and store the id of the user who approved the company.
Initially, I had the following code written in my service layer. It passes the request to the repository which updates the appropriate fields in db and then sends a mail notification.
public void ApproveCompany(int companyId, int userId)
{
_companyRep.ApproveCompany(companyId, userId);
//send mail to company representatives on successful approval.
}
Re factoring to create rich domains and encapsulate logic within the domain class, I created the below.
public void ApproveCompany(int companyId, int userId)
{
var user = _userRep.GetById(userId);
var company = _companyRep.GetById(companyId);
user.Approve(company);
_companyRep.Insert(c);
//send mail to company representatives on successful approval.
}
public class AdminUser
{
public string Name { get; set; }
public void Approve(MyApprovedCompany c)
{
c.SetIsApproved(this);
}
}
public class Company
{
public bool IsApproved { get; private set; }
public AdminUser ApprovedBy { get; private set; }
public void SetIsApproved(AdminUser user)
{
if (this.IsApproved)
throw new Exception("This company has already been approved by user: " + user.Name);
this.IsApproved = true;
this.ApprovedBy = user;
}
}
Queries:
- Is what I have done completely correct/partially correct?
- From a performance viewpoint is fetching the two objects just to create the proper class instances going to be a problem in the future?
- Does the mail notification belong to the service layer?
- How would my company repository look like to handle the property related to the user who approves the company? Should my company repository have a reference to the user repository (i think that is wrong).
Alternatively, I could write the service layer as below, but I don't think that is correct either.
public void ApproveCompany(int companyId, int userId)
{
var user = _userRep.GetById(userId);
var company = _companyRep.GetById(companyId);
if(company.IsApproved)
{
throw new Exception("This company has already been approved by user: " + _userRep.GetById(company.ApprovedUserId).Name);
}
else
{
user.Approve(company);
_companyRep.Insert(c);
}
}