Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

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.

This entry was posted in code, DDD, oo, opinion. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

40 Responses to Super Models, Part 2: Avoid Mutators

  1. Wim Hollebrandse says:

    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.

  2. Bil Simser says:

    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).

  3. Evan says:

    @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.

  4. markwriter says:

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

  5. Shawn says:

    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.

  6. Dave Laribee says:

    @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! 😉

  7. Dave Laribee says:

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

  8. @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.

  9. markwriter says:

    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

  10. Greg says:

    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.

  11. schneider says:

    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.

  12. Will says:

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

  13. Colin Jack says:

    @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.

  14. Dave Laribee says:

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

    http://udidahan.weblogs.us/2007/03/06/better-domain-driven-design-implementation/

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

  15. @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.

  16. 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.

  17. Dave Laribee says:

    @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.

  18. Colin Jack says:

    @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.

  19. 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.

  20. JH says:

    @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.

  21. Dave Laribee says:

    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…

  22. Joe says:

    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.

  23. 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.

  24. Colin Jack says:

    Great stuff, another good discussion on the general topic:

    http://peripateticaxiom.blogspot.com/2008/06/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 where T is some value object fits the notion of command rather elegantly.”

    Huh :)

  25. Bryan Watts says:

    Also, I forgot to mention that I understand your position on the semantic difference of an Action 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 :-)

  26. JH says:

    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.

  27. Bryan Watts says:

    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”.

  28. Dave Laribee says:

    @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.

  29. Dave Laribee says:

    @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.

  30. Dave Laribee says:

    @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.

  31. Joe says:

    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?

  32. karl says:

    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.

  33. josh says:

    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.

  34. Not using NHibernate, are you?

  35. John,

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

  36. 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.

  37. Object Bigot says:

    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.

  38. Dave Laribee says:

    @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.”

  39. Object Bigot says:

    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.

  40. John O'Brien says:

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>