Strengthening your domain: Avoiding setters

Previous posts in this series:

As we start to move our domain model from an anemic existence towards one with richer behavior, we start to see the aggregate root boundary become very well defined.  Instead of throwing a bunch of data at an entity, we start interacting with it, issuing commands through closed, well-defined operations.  The surface of our domain model becomes shaped by the actual operations available in our application, instead of exposing a dumb data object that lets anyone do anything, and consistency and validity are a pipe dream.

With more and more of a behavioral model in place, something begins to look out of place. We locked down behavioral entry points into our domain model, yet left open back doors that would render all of our effort completely moot.  We forgot to address that last vestige of domain anemia in our model: property setters.

Encapsulation Violated (Again)

In our Fee, Customer and Payment example, we ended with an operation on Fee that allowed us to record a payment.  Part of the operation of recording a payment is to update the Fee’s balance.  In the last post, we added the double dispatch pattern, creating a separate BalanceCalculator to contain the responsibility of calculating a Fee’s balance:

public Payment RecordPayment(decimal paymentAmount, IBalanceCalculator balanceCalculator)
{
    var payment = new Payment(paymentAmount, this);

    _payments.Add(payment);

    Balance = balanceCalculator.Calculate(this);

    return payment;
}

As an aside, I think some were thrown off in the last post that I pass in an interface, rather than a concrete class, making this a bit of a Strategy pattern.  I don’t like getting bogged down in names, but the whole “double dispatch” piece comes into play here because the Fee’s RecordPayment method passes itself into the BalanceCalculator.  The implementation then inspects the Fee object (and whatever else it needs) to perform the calculation.

If we zoom out a bit on our Fee object, we can see that we’ve encapsulated the Payments collection:

public class Fee
{
    private readonly Customer _customer;
    private readonly IList<Payment> _payments = new List<Payment>();

    public Fee(decimal amount, Customer customer)
    {
        Amount = amount;
        _customer = customer;
    }

    public decimal Amount { get; set; }
    public decimal Balance { get; set; }

    public IEnumerable<Payment> GetPayments()
    {
        return _payments;
    }

And the BalanceCalculator then uses the Fee object to do its calculation:

public class BalanceCalculator : IBalanceCalculator
{
    public decimal Calculate(Fee fee)
    {
        var payments = fee.GetPayments();

        var totalApplied = payments.Sum(payment => payment.Amount);

        return fee.Amount - totalApplied;
    }
}

So what does the BalanceCalculator need to do its job properly?  From the Fee object, it needs:

  • List of payments
  • Fee amount

And from each Payment object, the Amount.  But because we’ve exposed Amount and Balance with public setters, we can do completely nonsensical, non-supported operations such as this:

[Test]
public void Should_be_able_to_modify_a_fee_and_payment_amount()
{
    var customer = new Customer();

    var fee = customer.ChargeFee(100m);

    var payment = fee.RecordPayment(25m, new BalanceCalculator());

    fee.Amount = 50m;
    payment.Amount = 10m;

    fee.Balance.ShouldEqual(40m); // Do we even support this?!?
}

I have these nice operations in ChargeFee and RecordPayment, yet I can just go in and straight up modify the Amount of the Fee and Payment.  The Balance is no longer correct at this point, because I’ve exposed a back door around my aggregate root boundary.  We have again violated the encapsulation of our domain model by exposing the ability to modify state directly, instead of allowing modifications through commands.  But this is an easy fix for us!

Ditching the mutators

The simplest fix here is to hide the setters for Balance and Amount on our Fee and Payment objects:

public Fee(decimal amount, Customer customer)
{
    Amount = amount;
    _customer = customer;
}

public decimal Amount { get; private set; }
public decimal Balance { get; private set; }

Our RecordPayment method still compiles just fine, as it has access to this private setter for updating the balance.  Because we only want to allow modification of Balance through the Fee maintaining its own consistency, there’s no reason to expose Balance’s setter publicly.  The only place we’ll run into potential issues is in our persistence tests, and only then if we decide that we want to start with the database first when building features.  We’ll also modify the Payment object accordingly:

public class Payment
{
    public Payment(decimal amount, Fee fee)
    {
        Amount = amount;
        Fee = fee;
    }

    public decimal Amount { get; private set; }
    public Fee Fee { get; private set; }
}

Payment had an even bigger issue earlier – it exposed the Fee property setter.  That would lead to extremely bizarre behavior, where I could switch the Payment’s associated Fee at any time.  Not exactly desirable behavior, nor behavior we ever, ever want to think about if it’s not a supported operation.

If our application does not contain a single screen where we can change a Fee’s or Payment’s Amount, then why do we allow this ability in our domain model?  We shouldn’t.  We should only expose the operations, data and behavior supported by our application, and nothing more.

Suppose there is a screen that allows modification of a Payment’s Amount.  In that case, we’ll want to design an encapsulated operation on Fee (most likely) that allows us to keep the Balance correct and our aggregate root boundary intact.

Finding the balance

In many applications I work with, operations can be generally divided into two categories: data operations and behavioral operations.  For data operations, where Fee has a Comments property, there’s no inherent need to encapsulate changing the Comments behind a method, simply because there’s no behavior there.  Anyone can change the Fee’s comments at any time, and it won’t affect the consistency of the Fee aggregate root.  For data operations, I personally leave the setters in place.  The trick is to find what operations are behavioral in nature, and what operations are data-centric in nature.

If we start from the UI/interaction perspective, we’ll find that the design of our model pretty much imitates the design of the UI. If we have a data-centric interaction, we’ll have a data-centric model.  If we have a task-based, behavioral interaction, the domain model will follow.  What I’ve found is that not many applications are entirely in one camp or the other, and often have pockets and areas where it falls more into one camp or the other.  If you get rid of ALL your setters, but have data-centric screens, you’ll run into friction.  And if you have behavioral screens but an anemic, data-centric model, you’ll also run into friction.

In any case, the clues to where the design lies often come from conversations with the domain experts.  While our domain experts might talk about charging fees and recording payments, they’ll also talk about editing comments.  Behavioral in the former, data-centric in the latter.

Wrapping it up

Aggregate root boundaries are fun to talk about in theory, but many domain models you might look at only have boundaries in name only.  If a domain model exposes operations and commands only to also expose bypassing these operations by going straight to property setters, then there really isn’t a boundary at all.  Through crafting intention-revealing interfaces that allow only the operations and behavior we support through interaction of our application, we can avoid wonky half-baked scenarios and confusion later.  This confusion arises where our domain models expose one set of behaviors that our UI needs, and another set of behaviors that are not supported, nonsensical and lead to an invalid state in our model.

The justification for leaving public setters in place is often expressed in terms of “easier testing”.  From experience, invalid domain objects are more confusing and harder to test, simply because you can’t know that you’ve set up a context that is actually valid when using your application.

We can avoid this confusion and likely extra defensive coding by removing public setters for data that should only be changed through operations and commands executed on our domain model.  Once again, this is what encapsulation is all about.  Our model only exposes what is supported, and disallows what is not.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Domain-Driven Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Lance Harper

    Great tips. Thanks for the insight.

  • http://realfiction.net Frank Quednau

    Hi,
    in what way would you support updates that come from a UI? Say, when you construct some customer/address/contact object from several screens?

  • http://kozmic.pl Krzysztof Kozmic

    On a technical note, could you make the font size of your code samples a tad bigger?

    k2

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Frank

    Typically, these pieces form commands that are then executed against the domain. It might take several to get to the finish line.

    @k2

    Yeah, np

  • AJZ

    I have been reading about this type of approach and CQRS and I see that these are definitely good ideas. The question that I’ve been having is with initial object creation.

    For example, in an Accounts Payable application a user will need to enter an invoice. This involves filling out a whole bunch of fields, saving the invoice, and possibly editing some of these fields and saving again before some state change occurs which says that the invoice is now “processed” or “verified” or something like that.

    Once the invoice has made it to this new state it becomes more behavioral. The user can void it and perform a handful of other operations on it. At this point the approach you’re recommending becomes applicable.

    What am I missing? In my example would there be two domain objects: “invoice under construction” which is basically a CRUD getter/setter object and then it would become a “completed invoice” which would primarily have behavioral methods?

    I’m sure that there is a solution for this, but in all the CQRS and other documents I’ve read it hasn’t been mentioned. What am I missing?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @AJZ

    I’ve had situations like these, where in your example the user actually creates an “InvoiceRequest”. Eventually they can create a regular invoice from the invoice request, and it goes on from there. This helps especially if partial invoices aren’t invoices at all, and shouldn’t be treated as such.

  • AJZ

    Thanks for your response. That definitely makes sense to me.

    In the type of CQRS which Greg Young is promoting the transactional database only stores a running compilation of the actual commands. I wonder for the “InvoiceRequest” objects how this would be handled. Maybe they would be stored in a CRUD manner in a “domain object staging” data store and then transition to the transactional data store once complete. I guess it depends upon whether or not it is important to preserve the history of the “XxxRequest” objects.

  • http://realfiction.net Frank Quednau

    @bogardj
    Yes, I can see making commands from the stuff entered in the UI, but will you allow commands to change stuff on a domain object (via e.g. setters), or will you make domain objects accept commands and extract vital information form them to change values (thereby avoiding setters)?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Frank

    It depends. If it’s a data-specific command, I tend to just leave the setters there. If it’s a behavioral command, I go the method route (although I still don’t have the object accept a command message, but go with explicit args).

    I haven’t tried going command-only, so I’m not sure how that would work out in the long run.

  • http://clem-it.blogspot.com Clément Bouillier

    Thanks a lot for this series, I try to apply most of your suggestions. In fact, i would like to write on same subjects, you were faster ;)

    Nevertheless, I have some questions.
    1) the first is about persistence. I see two options for now :
    – classic ORM : setters are very useful for rehydration, even setters on collections…or you have to rely on introspection (like NHibernate do with private access).
    – event sourcing that prone Greg Young with CQRS…but I haven’t dig enough to detail…
    What is your position ?
    2) The second is about an argument I often heard from pro anemic DM people : you say you encapsulate but you broke encapsulation with your persistence…I haven’t found a better answer than “I prefer business encapsulation than no encapsulation…and persistence is pure technical consideration, that’s why I allow breaking encapsulation…”
    3) do you plan to talk about law of demeter ?

    As an aside remark, could you tag all your series items with a special series tag, it would allow to make a link to the whole series (from delicious or blog for example…) ?

    Thanks again.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Clement

    1) NHibernate deals with encapsulated collections and private setters very, very easily. Private setters don’t need any extra configuration. Encapsulated collections can be taken care of with Fluent NHibernate conventions. There really aren’t any hurdles there.

    I haven’t done any event sourcing, but it definitely looks intriguing. I have a very difficult time projecting what that architecture would look like on the systems I develop.

    2) How do I break encapsulation with persistence? No one outside my bounded context will have access to my persistence storage mechanism (DB or otherwise).

    3) Probably not, LoD doesn’t really play a large part in my own domain modeling style.

    And yeah, I can tag the posts :)

  • Jan Ove Olsen

    About the testing part of this.. You’re basically saying that you shouldn’t need public property setters to setup for unit testing because any unit tests for the entity should only have to test scenarios that you can build with the commands of the entity?

    That makes sense, but also leads to more complex setup for scenarios where the required state of the entity you want to test is the result of several commands performed on the entity.

    I still expose setters for this very reason, but I feel dirty everytime I do it.. :)

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Jan

    Yeah, it’s definitely a trade-off. Walking through commands in the test does tend to reinforce the Ub. Language tho. One approach to take is a fluent fixture:

    http://blog.eleutian.com/2007/09/29/FluentFixtures.aspx

  • Threadstatic

    JImmy, how are you persisting the domain classes without public setters?

    • jbogard

      NHibernate doesn’t require public setters, it can work with private.