What are Rich Data models ?
Anemic data model VS Technical concerns
3 big Complaints about Anemic model
Anemic model in disguise of IOC and DI
Conclusion
Further references and reading
What are anemic data models?
Anemic in English means plain so Anemic Models means plain Models.
Plain models are classes without business logic / behaviors. For example below is a simple “Customer” model which just has the data (properties) but it does not have business logic (behavior).
class Customer { private string _CustomerName; public string CustomerName { get { return _CustomerName; } set { _CustomerName = value; } } private string _CustomerCode; public string CustomerCode { get { return _CustomerCode; } set { _CustomerCode = value; } } }
Now in real world plain models are of no use without business logic unless you are creating DTO ( data transfer objects) which are meant for different purpose. Some developers feel comfortable in pushing these actions and methods in a separate classes which are named with different vocabularies like service, façade , manager , utility etc. These plain models are then passed to these classes who run the behavior over them.
For example below is a simple service class which validates the “Customer” object and decides if the object valid or not. Putting in simple words Anemic model has behavior in separate service / utility / manager classes.
class CustomerValidationService { public bool Validate(Customer obj) { if (obj.CustomerCode.Length == 0) { return false; } if (obj.CustomerName.Length == 0) { return false; } return true; } }
What are Rich Data models ?
Rich data models have both data and behavior in the same class. Below is the RDM for the previously defined ADM. You can see the data ( CustomerCode and CustomerName) and behavior (Validate) both are part of the same model.
class Customer { private string _CustomerName; public string CustomerName { get { return _CustomerName; } set { _CustomerName = value; } } private string _CustomerCode; public string CustomerCode { get { return _CustomerCode; } set { _CustomerCode = value; } } public bool Validate() { if (CustomerCode.Length == 0) { return false; } if (CustomerName.Length == 0) { return false; } return true; } }
Anemic data model VS Technical concerns
Lot of developers confuse Technical cross cutting concerns with Anemic model. In Anemic model the behaviors in the service class is the behavior of the real world model.
Lot of developers create utility or service classes which decouple technical behavior from the model which is not anemic model. For example someone can create a “Dal” class as shown below and pass the “Customer” object to be inserted in to the database. Lot of people term this kind of approach as “Repository” pattern.
class Dal { public void InsertDb(Customer obj) { // Code of ADO.NET goes here } }
Now this kind of model is not anemic model. This is separating the technical behavior from the business behavior which perfectly makes sense. In the previous example we had “validate” method which actually belongs to the “Customer” model. So Anemic model are those models which have business behavior separated in a different class and not technical behavior. So the above “Dal” class is not an Anemic model.
Customer cust = new Customer(); cust.CustomerName = "Shiv"; Dal dal = new Dal(); dal.InsertDb(cust);
3 big Complaints about Anemic model
Lot of developers unknowingly follow Anemic model because of simplicity, but OOP community has the below concerns for ADM:-
- Anemic model disrespects OOP concepts. Objects in OOP have data and behavior. Object should model real time entity. By separating the behavior we are not following OOP. With behaviors residing in a separate class it would be difficult to inherit , apply polymorphism , abstraction and so on.
- Anemic models can have inconsistent states at any time. For example see the below code we have first created a valid customer object and the validation service logic ran over it and set the “IsValid” to true. So till step 1 everything is fine “IsValid” is true and in synch with the customer object data. Now somewhere down the line you can say in step 2 customer name property is set to nothing. In this step the customer object is not valid in reality but if you try to display in Step 3 it shows valid. In order words the data and the IsValid flag is not in synch
Customer obj = new Customer(); obj.CustomerName = "Shiv"; obj.CustomerCode = "1001"; CustomerValidationService validationService = new CustomerValidationService(); validationService.Validate(obj); Console.WriteLine(obj.IsValid); // Step 1 :- till here Valid obj.CustomerName = ""; // Step 2 :- we made the model invalid Console.WriteLine(obj.IsValid); // Step 3 :- but it says Still Valid
- Lot of people complain that this is procedural programming and so is a Anti pattern. If you see procedural programming approach we create methods and function , we pass structure to it and get the output.
Anemic model in disguise of IOC and DI
With all respect to the views of OOP developers Anemic models exists very beautifully and amicably in the disguise of DI IOC architecture today. I personally find it very cruel to say it’s an Anti-pattern.
Consider the below scenario where we have a customer class who has different kind of discount calculations. So rather than putting the discount calculation logic inside the customer class you can inject the object from the constructor as shown in the below. In case you are new to dependency injection please read this DI IOC in C#.
class Customer { private IDiscount _Discount = null; public Customer(IDiscount _Dis) { _Discount = _Dis; } private string _CustomerName; public string CustomerName { get { return _CustomerName; } set { _CustomerName = value; } } public string Region { get; set; } public double Amount { get; set; } public double CalculateDiscount() { return _Discount.Calculate(this); } }
And your discount calculation logic is in a different class all together which takes the customer object for calculating discount.
public interface IDiscount { double Calculate(Customer Cust); }
Below are two kinds of discount calculations one is a week end discount and the other is a special discount. The week end discount does calculation as per region and week day while the special discount is a 30% flat.
Now the below classes also follow anemic model because the actions are in a different class but still its perfectly decoupled, valid and OO.
public class WeekEndDiscount : IDiscount { public double Calculate(Customer Cust) { if (Cust.Region == "Asia") { if (DateTime.Today.DayOfWeek == DayOfWeek.Sunday) { return (Cust.Amount * 0.20); } } return (Cust.Amount * 0.10); } } public class SpecialDiscount : IDiscount { public double Calculate(Customer Cust) { return (Cust.Amount * 0.30); } }
Conclusion
- Anemic data model is a simple plain model class with only data and behavior resides in a separate class.
- Rich data model have both data and behavior.
- Anemic model is criticized for not been OO , extensible , inconsistent and follows procedural programming approach.
- Anemic model should be confused with cross cutting concern technical classes like Logging , Repository etc.
- DI IOC indirectly forces anemic model. So Anemic model in today world is very much present in the disguise of DI IOC.
Further references and reading
I have been writing a lot on design patterns, architecture, domain driven development and so on. So below are the link feel free to read and do give feedback.