.netarchitecturedomain-driven-designdomain-modelanemic-domain-model

Domain objects - "Smart object" vs POCO


By Smart object I consider any Domain object that knows its original property value if property is altered. Smart objects usually have a base class and implement properties by using GetPropertyValue/SetPropertyValue methods. On the other hand POCO objects would commonly have no base class and implement simple properties.

public class SmartObject : BaseDomainObject
{
    public int id
    {
         get { return (int)this.GetPropertyValue("Id"); }
         set { this.SetPropertyValue("Id", value); }
    }
}

public class POCO
{
    public int id { get; set; }
}

I like Smart object because it does a lot of hard work for me. I can easily add all those useful features to BaseDomainObject and have them in all my derived Domain classes:

On the other hand POCO's are super simple and have no dependency to any base class.

Nowadays I here a lot of POCO praising because:

  1. it can be sent over the wire (usually to web browser as JSON)
  2. it is pure

On the other hand I think that reasons above are fallacy because:

  1. DTO's are for wire transfer and not domain objects. Behavior encapsulating data if lost when domain object is serialized to JSON.
  2. this chase for purity seams like chase for even more anemic domain model which doesn't have logic nor anything smart attached to it.

With all this sad, I still like that POCO and it bugs me. What is your opinion?


Solution

    • common properties (like Id, Status...)

    I wouldn't consider an object to be non-POCO if it just inherits, say, an Entity base class that defines an Id property. An entity by definition has an identity, that doesn't break SRP nor does it alter the "purity" of your object by importing third party behavior.

    Status is more debatable, depending on what you mean by that it might indeed introduce additional responsibilities in your object that makes it non-POCO.

    Most other properties you mention I think should be handled by external objects, not the domain object itself.

    • object state tracking (new, modified, unchanged)

    It would be better to have change tracking-specialized proxies of your domain objects handle this (this is typically what ORMs do).

    • all properties raise events on property changes (implementation of INotifyProperyChanged)

    I see that as mostly UI-related stuff that goes into your presentation objects but not your domain objects. You'll probably not want every property in your entities to be observable - to signal changes in an Aggregate, use Domain Events instead.

    • I can have all this other behavior that can be useful - Clone/Sync/ IsPropertyDirty...

    Clone can typically be a basic behavior of Value Objects without them being considered non-POCOs. Cloning entities seems less useful to me except your occasional domain specific need. Sync/IsPropertyDirty again seems more like versioning / change tracking and should be delegated to a specialized object.

    this chase for purity seams like chase for even more anemic domain model which doesn't have logic nor anything smart attached to it.

    The problem here is all about "attached". It's not that SRP-compliant objects aren't smart, rather that they don't include anything smart that is not their natural responsibility. Similarly, POCO's aren't dumb, they are just objects that weren't transplanted with behavior from external sources (3d party libraries, framework extenstions...)