Dave Laribee

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Super Models, Part 2: Avoid Mutators

A quick disclaimer: we're entering religious territory here. I feel strongly about this issue, but it's certainly my opinion. If you want to get the full sense of how passionate people are about this issue, check out this article at JavaWorld.

I've come to the point of view that Entities should not use set mutators ("setters"). Anything you represent as a setter can usually be better represented as a plain old method. Why?

Let's remember one of the fundamental guidelines of DDD: intention revealing interfaces. Which is more intention revealing?

Customer c = new Customers().Find(42);

// This...
c.Address = aNewAddressValueObject;

// or this?
c.ChangeAddress(aNewAddressValueObject);

That's a subtle point and it's admittedly open for debate. To firm up my argument let's consider the situation where I'm crunching knowledge into model and address change becomes a temporal concept. I now need to track what an address is of a certain date and time. Surely a setter will do the trick, but I think the command "change an address" is better expressed with a method. I can fiddle with the internals of that method and, because we're practicing command-query separation, accept that commands change the state of aggregate roots and entities.

For me, the biggest argument for avoiding setters is that it promotes thinking in terms of data in a paradigm (DDD) where data-first can be harmful and counter productive. I cannot stress enough: entities are behavioral objects and, for my money, Action<T> where T is some value object fits the notion of command rather elegantly.


Posted Tue, Jul 8 2008 10:11 PM by Dave Laribee
Filed under: , , ,

[Advertisement]

Comments

John O'Brien wrote re: Super Models, Part 2: Avoid Mutators
on Tue, Jul 8 2008 11:06 PM

Oh yeah, religious territory for some.

In your example, is the 'intent' really that obscured when we change (set) the 'Value' of a 'Value Object'

I am wondering if you're overthinking it a little.

Keep going and we may realize we don't identify why a person's address changes. So we go into the territory of ...

Customer.MovedTo()  

just my opinion too. DDD is good but still needs some balance.

Object Bigot wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 12:20 AM

It all depends on where you draw the line at data abstraction. Abstract to a high enough level too soon and you create unflexible classes.

I would prefer to use getters and setters early on in design when the level of abstraction required is unclear and then refactor to common methods when the design becomes stable.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 12:27 AM

@Object Bigot (really?) - I prefer to think behaviorally from the get go. In working with a team, allowing setters creates a crutch that can create weird orchestrations _outside_ of your model. DDD is a hard thing to employ with collective code ownership, and by creating a rule of no setters we end up a time where we stop and think "what really needs to change here."

Object Bigot wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:38 AM

In an ideal world I would abolish all getters and setters, or use a language such as Eiffel if I wanted OO purity.

In the real world this is just too hardcore for some, as most people still think procedurally. As long as the Domain Model doesn't become too 'Anemic', I would allow getters and setters for the sake of getting work done.

Scott Bellware wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:08 AM

Personally, I don't think the issue is whether to not use getters and setters, but that each bit of client code using a getter or setter is creating a coupling point.

Any approach early on in a solution where there isn't much implementation done yet is going to appear flexible.  

Behavioral programming typically reduces the amount of coupling points, and this leaves the design more supple.

Scott Bellware wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:09 AM

John,

If Customer.MovedTo() is appropriate to the ubiquitous language of the domain and closer to the intent, then it's a good name.

Reflective Perspective - Chris Alcock » The Morning Brew #132 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #132
on Wed, Jul 9 2008 3:25 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #132

Gabriel Lozano-Moran wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:53 AM

Not using NHibernate, are you?

josh wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 7:18 AM

wow... why stop there. why not make the whole entity immutable. whenever you want to change anything just mark the old one as inactive and create a new replacement. or better yet, just tell the customer they aren't allowed to move.

karl wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 8:48 AM

The point I take from this post is that developers should give more thought to this than automatically using setters - which is probably the norm, especially when you consider how easy this is with automatic properties or via resharper.

Frequently a setter doesn't covey the intent nearly as well as as a method would. As Scott points out, setters and getters also introduce coupling.

Now, do I think we should completely stop using setters? No. But people really need to start thinking about what they are trying to do.

If I was building a billing system (say for a telephone company or something), you bet your ass that I'd use:

customer.MovedTo(newAddress);

rather than

custome.Address = newAddress;

Even if MoveTo did nothing more than set a private field.

@Gabriel:

What does NHibernate have to do with the discussion? I map to private fields all the time.

Joe wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 9:43 AM

I noticed you said "Entities should not use set mutators" so Value objects still would use setters. I mean, you have to "set" the city, state, zip, etc. of an Address object right?

A question though about when you need to change the first name of the customer for example.

Is customer.ChangeFirstName("John") more descriptive than customer.FirstName = "John"? How would you handle the simple changes, things that don't involve other Entities or Value objects?

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 9:56 AM

@Karl - Good points. I would say that by default, when considering design decisions, I like our team to say "is this better expressed with a method." Usually the answer is "yes" when we're in the model.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 9:57 AM

@Gabriel - As Karl pointed out, you can map to private fields while still using the getter name in your HQL by changing the mapping strategy.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 10:04 AM

@Joe - Value objects are always immutable. I declare private fields in value objects as readonly and require everything be supplied in a constructor or possibly a static factory method. When designing entities I always ask "what about this is immutable" or "what, if changed, would result in a new entity anyway and therefore can be made immutable as I'd delete the entity?"

As far as the customer.ChangeFirstName("John") example goes it's likely that there isn't a whole extra lot of expression versus the mutator. I would say that we often make our behavior methods a little larger grained, so:

customer.ChangeName(first, last, prefix, suffix, middle);

- or, if you'd like to introduce a parameter objects -

customer.ChangeName(personNameValueObject);

Then we'll surface getters on the customer such as:

customer.FullName // "Dr. Jane A. Doe"

- and -

customer.FileAs // "Doe, John A."

This flexibility does, in fact, lead to better expression. I'm not trying to win an argument here so much as I'm trying to get at a few points: a default heuristic (avoiding setters) can lead to a more supple (what @Scott hinted at) and intention-revealing design that brings our model closer to the domain's nature.

Bryan Watts wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 10:57 AM

I'm not sure I see the distinction - "ChangeAddress" mutates the object just as the setter does.

All you've done is introduce a different way of saying the same thing - "change an internal value of this already-constructed object".

The subtle difference is that you don't allow the reader to leverage their existing knowledge of the meaning of "="; instead, you choose an arbitrary name for that concept (why not "Update" or "Alter" or even "Mutate"?)

What if the C# compiler team had chosen "change_" instead of "set_" and called them changers? Either the concept behind "=" then becomes palatable, or you pick another redundant term for it (maybe "Set"?)

I am not arguing against convenience methods like ChangeName(first, last, prefix, suffix). They add value. Redefining "=" just increases the mental flotsam/jetsam that the readers of your code must harbor.

To avoid being labeled "religious", I'd like to point out that Occam's razor clearly puts your approach on the losing side of "postulates the fewest entities".

JH wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 11:03 AM

This seems fine within a single application boundary.

Serializing an object requires you have both a setter and getter for each property. Method behavior doesn't serialize unless you control both the caller and callee where they can both reference the same assembly.

Bryan Watts wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 11:05 AM

Also, I forgot to mention that I understand your position on the semantic difference of an Action<T> versus a setter in a behavioral object - it is perceived as "more explicit".

The "act of setting" is the command, not the structural element representing its invocation. If you can set a value on an object, that is as much impetus as is needed to infer work may be done.

And just to be pedantic, a setter is an Action<T> :-)

Dew Drop - July 9, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - July 9, 2008 | Alvin Ashcraft's Morning Dew
on Wed, Jul 9 2008 11:08 AM

Pingback from  Dew Drop - July 9, 2008 | Alvin Ashcraft's Morning Dew

Colin Jack wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 11:08 AM

Great stuff, another good discussion on the general topic:

peripateticaxiom.blogspot.com/.../tdd-mocks-and-design.html

@Dave

"c.ChangeAddress(aNewAddressValueObject);"

Temporal aspect is a good argument, for sure, but it can be handled to some extent even if you use setters. Having said that I might well use "c.ChangeAddress(aNewAddressValueObject);" but you'd probably have an associated getter (or getter method) so it's not really changing the design that much (though I get you about intention revealing interfaces).

Actually though I wouldn't necessarily put this sort of member directly on Customer. VERY debatable but often I find its better if (for example) a Customer exposed a custom collection (AddressCollection) with the extra methods on it. Why, well because a key entity like Customer probably has a relationships to a few other VALUE OBJECTS/ENTITIES and if you put all the methods for those other entities on the Customer then it's interface gets a little confused (GetCurrentName, GetCurrentAddres, FindAddressAt(Date),...).

"In working with a team, allowing setters creates a crutch that can create weird orchestrations _outside_ of your model."

Agreed, but then even when we have setters/getters I've found good developers will write good code inside the domain and bad developers...you get the idea :)

"I cannot stress enough: entities are behavioral objects and, for my money, Action<T> where T is some value object fits the notion of command rather elegantly."

Huh :)

Jeremy D. Miller wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 11:11 AM

It's not an either/or decision on setters.  You could keep the setters on the entities to make test automation scenarios and NHibernate usage easy.  Then apply the Interface Segregation Principle.  Lift an interface off of the entity that ONLY contains the methods that change state in a coarse grained manner like Dave is talking about.  Have the service layer only consume the interfaces sans setters.

Udi Dahan does something like this when he writes services over the top of a domain model.

Joe wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 1:18 PM

After reading this (and some comments) I'm sure glad i don't work on your projects.

I think this is going too far, are these measures really saving time/effort/maintenance?

"All entities should be immutable" - have you considered what that would do to performance?  Everytime you required to change any field you would need a new allocation.  Existing references would be invalidated - so all references would need to go through an indirection.  

Why is ChangeXXXX better than XXX = value?  What if one project uses Change and another uses Set and another uses Modify?  

I can see the value of providing a method to wrap up an atomic operation - but then you hit the issue of dealing with large parameter lists.  It's much less readable and there are lots of issues with optional fields, breaking changes over time etc.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 1:35 PM

Wow, @Joe. What about my post makes you think this is an iron fist rule? It's a design heuristic. Perhaps I should have put the disclaimer in BOLD RED?

@Jeremy - No doubt. I'm talking model layer here, too. When you find yourself doing an orchestration of setting things from the outside or you find setters with logic in them? Switch to a method. I doubt you disagree with that...

JH wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 1:46 PM

@Jeremy & @ Dave

I like that. Nothing says you have to only have a single interface implemented on an object.

Cross-boundary uses properties with both accessors, internal uses an interface with a more ubiquitous language. Heuristic works for me.

Scott Hanselman wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:13 PM

Interesting discussion, although, I'm having trouble getting past the fact that you're really comparing:

c.ChangeAddress(aNewAddressValueObject);

and (under the covers)

c.set_Address(aNewAddressValueObject);

This seems like a sugar thing to me.

Colin Jack wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:29 PM

@Jeremy @Dave

Do either of you have a good example of the approach where you extract an interface at a higher level of abstraction. I get the idea but am having trouble working out how you would go about it in practice.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:33 PM

@Scott - Sugar matters in English. We want to pick the right word for the right job. Synonyms carry nuance and if we accept the value proposition of ubiquitous language and DDD then I think we're compelled to reach for the sugar bowl.

Derick Bailey wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:43 PM

100% agree with avoiding mutating setters.

I just did some training for my current team, and we got to the point where we were assigning managers to departments in the org chart that we were writing for the class. I immediately created a "Department.AssignManager()" method, and the internals of the method did nothing more than call a private setter on the .Manager property.

You're post here does a much better job of describing why I did that, and I've forwarded the link to my team.

Jeremy D. Miller wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:50 PM

@Dave,

I completely agree with you about changing state with methods like that.  Part of the fallout from the EF controversy last week has been some discussions about what goes into setters.  I've found that putting any nontrivial logic into setters is problematic.  

@Colin,

I don't really think it's a higher abstraction level.  It's just the role that the domain object plays in a particular context.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 2:59 PM

@Colin - Check out Udi's blog (I think that's what Jeremy is siting) for an example:

udidahan.weblogs.us/.../better-domain-driven-design-implementation

I actually found this linked (through a chain) to your blog.

Colin Jack wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:27 PM

@Dave

Excellent thanks, I thought it might be that one but I wasn't 100% sure. Have to say I find these sorts of topics very interesting, which probably says nothing good about me.

@Jeremy

Ta for replying.

I've definitely done what you suggest in places, but I'm just thinking if you apply that approach quite widely (so upper layers don't really see the setters) then it might expand the interface of your entities quite rapidly and you'd end up with quite a lot of overlap between getters/setters and related coarse grained methods.

DotNetKicks.com wrote Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:34 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Will wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:57 PM

Say goodbye to serialization and databinding (well, two way at least)!

schneider wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 3:58 PM

I Feel c.Address is for the initial setting of the state from the DB.

while

c.ChangeAddress(aNewAddressValueObject)

better supports adding new requirements in the future (Audit trails), and is more descriptive of the action performed.

And I don't think this is in religious territory, I think ChangeAddress is the best approach.

Greg wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 4:32 PM

I go a step further and claim getters are just as bad as setters ... Getting rid of them is quite a bit more difficult though :-)

We have talked about this in the past ... will try to put a post with some diagrams of how to do it.

markwriter wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 6:26 PM

Curious about a term Scott used: "sounds like a sugar thing"

What is a 'sugar thing'?  I've not heard that term used before.

Thanks

Chris Ammerman wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 6:55 PM

@markwriter

Scott is talking about "sugar" in a similar way we use the term "syntax sugar" when talking about language features.

Syntax sugar is a feature added to a language to make it possible to do something that was already possible in a way that is more pleasant / intuitive / concise / elegant / whatever to certain developers' sensibilities.

In this case, I think maybe we're talking about "code standards sugar".  The effect achieved is the same: in Dave's own words, using an explicit method rather than a property setter is more intuitive and transparent of purpose, coming from a Domain-Driven Development (DDD) mindset.

For what it's worth, I agree with Scott.  It's sugar.  That doesn't mean it's pointless....  Just that it probably shouldn't be a blanket rule, or even a "best practice".  But it may make great sense in a Dave's DDD context.  He noted himself, he's talking in particular about the "model" layer, which generally is the portion of your app that most closely models the domain regardless what your driving development philosophy is.

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 7:13 PM

@Chris - Well said! This is a heuristic in the model layer (for me).

Dave Laribee wrote re: Super Models, Part 2: Avoid Mutators
on Wed, Jul 9 2008 7:14 PM

@Greg - Yes, show us what you're talking about. Maybe double dispatch? (I'm guessing.)

@Will - Have an upcoming post on that. Again, we're talking about the model layer, data-binding and serialization have zero reason to be there. Hopefully I'll stir up the pot some more with that assertion! ;)

Shawn wrote re: Super Models, Part 2: Avoid Mutators
on Thu, Jul 10 2008 12:11 AM

Wow look at all these comments, now I *know * this is religious topic.

Sometimes using a property setter is completely appropriate, like when a class has a sensible default value but you can override it using a simple setter.  I prefer to use methods like in your example when there's a verb involved, some action, not just simple data assignment (although under the covers maybe that's all that is happening).  

If you're doing something other than a simple assignment I tend to lean towards methods.  I think the FCL has guidance for this, at least for getters?

This seems to go hand in hand with some guidance I read regarding immutable objects, prefer readonly fields/properties and objects over mutable ones.  I can't remember where I read this...

Anyway, I'm glad I'm not the only one who worries about intent and naming.

markwriter wrote re: Super Models, Part 2: Avoid Mutators
on Thu, Jul 10 2008 11:51 AM

Thanks for the clarification, Chris! For whatever reason, I hadn't come across that term before.

Andrei Butnaru's blog wrote Programming links 07.11.2008
on Fri, Jul 11 2008 2:31 PM

Programming links 07.11.2008

Evan wrote re: Super Models, Part 2: Avoid Mutators
on Mon, Jul 14 2008 2:45 PM

@Dave

I'm right there with ya..this helps keep the LOC in the service layer (controllers, etc) from becoming huge..

And it doesn't add a smell if the aggregate root needs to add additional behavior when "changing addresses".  This is doubly true if the logic may throw an exception.  Catching an exception from a setter just feels icky.

NHibernate « Beautiful code wrote NHibernate &laquo; Beautiful code
on Wed, Aug 6 2008 2:51 AM

Pingback from  NHibernate &laquo; Beautiful code

Bil Simser wrote re: Super Models, Part 2: Avoid Mutators
on Tue, Aug 12 2008 11:54 PM

I would be a happy person if my guys wrote code like c.ChangeAddress(newAddress) rather than c.Address = newAddress;

For me, it's all about intent revealing code. You may argue it's sugar, but without the sugar we're dealing with raw materials and frankly who codes in assembler or p-code anymore?

We've been debating BDD syntax for months now, and it's all about readability. I agree that when you go down the evil path of logic in setters, you're just setting yourself up for failure later. Hiding code behind a setter because there are curly brackets is no different than writing SQL in your webpage codebehind. You're hiding the intent and while it might come out in a peer review, it's something that could be buried deep in the system.

I'm all for using auto-properties in 3.5 for this sole purpose. Give them a single responsibiity. Set a value and that's it. Don't do any rounding, don't do any null checks or lookups or whatever. Let it do what it was designed for. Leave a method like ChangeAddress() to handle logic which can be tested (and might change) and let setters set and getters get.

For a DDD perspective I would rather see methods on models that mean something rather than properties that I have to interpret what might happen if I set that value to something. Let field access control NH and you're done. Later this won't come back to bite you and say "Aha, I'm a setter but I also do 'other' things, but you didn't know that did you?". When the intent of the domain changes (ChangeAddress becomes more than just changing an address but auto-routing mail to the new address) then update the method and rename it (maybe introducing new properties to handle it).

It’s my blog and I’ll OCD if I want to « I Built His Cage wrote It&#8217;s my blog and I&#8217;ll OCD if I want to &laquo; I Built His Cage
on Wed, Oct 8 2008 7:55 PM

Pingback from  It&#8217;s my blog and I&#8217;ll OCD if I want to &laquo; I Built His Cage

Jimmy Bogard wrote Encapsulation and thinking behaviorally
on Tue, Oct 21 2008 8:59 AM

I’ve been reading quite a bit lately about setters and encapsulation , but for whatever reason, it never

Axe.writesSmellyCode() == true « I Built His Cage wrote Axe.writesSmellyCode() == true &laquo; I Built His Cage
on Sat, Jan 31 2009 10:25 PM

Pingback from  Axe.writesSmellyCode() == true &laquo; I Built His Cage

Wim Hollebrandse wrote re: Super Models, Part 2: Avoid Mutators
on Mon, Nov 16 2009 3:15 PM

I have an idea.

Why don't we get rid of the syntactic sugar and use set_Address and get_Address methods? ;-)

I mean set_Address() is far closer semantically to your ChangeAddress method.

uberVU - social comments wrote Social comments and analytics for this post
on Fri, Dec 18 2009 3:50 PM

This post was mentioned on Twitter by lazycoder: Why entities shouldn't have setters. (by @laribee ) http://bit.ly/CGgSL

Add a Comment

(required)  
(optional)
(required)  
Remember Me?