Single responsibility ( reason to change ) of an entity should be to uniquely identify itself, in other words, its responsibility is to be findable.
Eric Evan's DDD book, pg. 93:
most basic responsibility of Entities is to establish continuity so that behavior can be clear and predictable. They do this best if they are kept spare. Rather than focusing on the attributes or even the behavior, strip the Entity object's definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it. Add only behavior that is essential to the concept and attributes that are required by that behavior.
Beyond that, look to remove behavior and attributes into other objects associated with the core Entity .Beyond identity issues, Entities tend to fulfill their responsibilities by coordinating the operations of objects they own.
1.
... strip the ENTITY object's definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it. Add only behavior that is essential to the concept ...
Once an entity is assigned a unique ID, its identity is established and so I would assume such an entity doesn't need any behavior to maintain its identity or to help it identify itself. Thus, I don't understand what kind of behavior is author referring to ( besides find
and match
operations ) with "behavior that is essential to the concept"?
2.
... strip the ENTITY object's definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it. ... Beyond that, look to remove behavior and attributes into other objects associated with the core ENTITY.
So any behavior that doesn't help identify the entity, but we'd still characterize that behavior as being an intrinsic characteristic of that entity ( i.e. barking is intrinsic to dogs, flying is intrinsic to airplanes, laying eggs is intrinsic to birds ... ), should be put into other objects associated with that entity ( example: we should put barking behavior into an object associated with a dog entity )?
3.
Beyond that, look to remove behavior and attributes into other objects associated with the core ENTITY.
a) MyEntity
delegates responsibilities A_resp
and B_resp
to objects a
and b
, respectively.
Even though most of A_resp
and B_resp
work is done by a
and b
instances, clients are still served A_resp
and B_resp
through MyEntity
, which means that from the client's perspective the two responsibilities belong to MyEntity
. Thus, doesn't that mean MyEntity
also has A_resp
and B_resp
responsibilities and as such is violating SRP?
b) Even if we assume that A_resp
and B_resp
don't belong to MyEntity
, MyEntity
still has a responsibility AB_resp
of coordinating the operations of objects a
and b
. So doesn't MyEntity
violate SRP since at minimum it has two responsibilities – to uniquely identify itself and also AB_resp
?
class MyEntity
{
private A a = ...
private B b = ...
public A GetA()
{ ... }
public B GetB()
{ ... }
/* coordinates operations of objects a and b */
public int AworkB()
{ ... }
}
/* A encapsulates a single responsibility resp_A*/
/* A is value object */
class A
{ ... }
/* B encapsulates a single responsibility resp_B*/
/* B is value object */
class B
{ ... }
UPDATE:
1.
Behavior in this context is refering to semantic behavior. For example, a Property on a class (i.e. attribute on a domain object) that is used to uniquely identify it has a behavior. While this is not represented in code directly. The expected behavior is that there will not be any duplicate values for that property.
So in code we would almost never need to actually implement a behavior ( i.e. an operation ) that would somehow maintain entity's identity, since as you explained such a behavior only exist as a concept in a domain model ( in the form of a ID attribute of an entity), but when we translate this ID attribute into code, part of its semantics is lost ( i.e. the part which implicitly makes sure the ID value is unique is lost )?
2.
Furthmore, a property such as Age has no context outside of a Person Entity, and as such, makes no sense to move into a different object ... However that information could easily be stored in a separate location that the unique identifier, hence the confusing reference to behavior. Age could be a lazy loaded value.
a) If Age
property is lazy loaded, then we may call it a behavior, even though semantically Age
is just an attribute?
3.
You could easily have operations specific to Address such as verification that it is a valid address. You may not know that at design time, but this whole concept is to break down objects into their smallest parts
While I agree that we'd lose context by moving Age
into different object, the context wouldn't be lost if we moved DateOfBirth
property into a different object, but we usually don't move it.
What is the main reason that we'd move Address
into another object, but not DateOfBirth
? Because DateOfBirth
is more intrinsic to Person
entity or because there are less chances that somewhere in the future we may need to define operations specific to DateOfBirth
?
4.
I must say I still don't know whether MyEntity
also has A_resp
and B_resp
responsibilities and why MyEntity
also having AB_resp
isn't considered a violation of SRP
EULERFX
1)
The behaviors that the author is referring to are behaviors associated with the entity. These are the behaviors that modify the state of the entity
a) If I understand you correctly, you're saying that entity should only contain those behaviors that modify its attributes ( i.e. its state )?
b) And what about the behaviors that don't necessarily modify the state of the entity, but are still considered as being an intrinsic characteristic of that entity ( example: barking would be intrinsic characteristic of a Dog
entity, even if it didn't modify Dog's state )? Should we include these behaviors in an entity or should they be moved to other objects?
2)
As far as moving behavior to other objects, the author is referring to value objects specifically.
Though my quote doesn't include it, but author does mention in the same paragraph that in some cases behaviors ( and attributes ) will also get moved into other entities ( though I understand the benefits of moving behaviors to VOs )
3) Assuming MyEntity
( see question 3. in my original post ) doesn't violate SRP, would we say that a responsibility of MyEntity
is among other things also comprised of:
a. A_resp
+ B_resp
+ AB_resp
( AB_resp
coordinates objects a
and b
)
or
b. AB_resp
+ delegating A_resp
and B_resp
to objects ( a
and b
) associated with MyEntity
?
4) Eric Evan's DDD book, pg. 94:
CustomerID is the one and only identifier of the Customer ENTITY ( figure 5.5 ), but phone number and address would often be used to find or match a Customer. The name does not define a person's identity, but it is often used as part of the means of determining it.
In this example, the phone and address attributes moved into Customer, but on a real project, that choice would depend on how the domain's customers are typically matched or distinguished. For example, if a Customer has many contact phone numbers for different purposes, then the phone number is not associated with identity and should stay with the Sales Contact.
a)
CustomerID is the one and only identifier of the Customer ENTITY ( figure 5.5 ), but phone number and address would often be used to find or match a Customer. The name does not define a person's identity, but it is often used as part of the means of determining it.
Quote states that only attributes associated with identity should stay in an entity. I assume author means that entity should contain only those attributes that are often used to find or match this entity, while ALL other attributes should be moved?
b) But how/where should other attributes be moved? For example ( assumption here is that address attribute isn't used to find or match Customer
and thus we want to move address attribute out of Customer
):
if instead of having Customer.Address
( of type string
) we create a property Customer.Address
of type Address
, did we move the address attribute into an associated VO object ( which is of type Address
) or would we say that Customer
still contains address attribute?
c)
In this example, the phone and address attributes moved into Customer, but on a real project, that choice would depend on how the domain's customers are typically matched or distinguished. For example, if a Customer has many contact phone numbers for different purposes, then the phone number is not associated with identity and should stay with the Sales Contact.
Isn't author in the wrong here, since if we assume each of the many contact phone numbers that Customer
has only belong to that particular Customer
, then I'd say these phone numbers are associated with identity just as much as when Customer
only had one phone number?
5)
The reason the author suggests stripping the entity down is that when one initially creates a Customer entity, there is a tendency to populate it with any attribute that one can think of being associated with a customer. This is a data-centric approach that overlooks behaviors ultimately leading to an anemic domain model.
Off topic, but I thought anemic domain model results from moving behavior out of an entity, while your example is populating an entity with lots of attributes, which would result in Customer
having too much behavior ( since we'd probably also include in Customer
the behaviors which modify these additional attributes ) and thus in violation of SRP?
thanks