CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Matthew Podwysocki

Life of a Functional Programmer

Side Effecting Functions Are Code Smells Revisited

After talking with Greg Young for a little this morning, I realized I missed a few points that I think need to be covered as well when it comes to side effecting functions are code smells.  In the previous post, I talked about side effect free functions and Design by Contract (DbC) features in regards to Domain Driven Design.  Of course I had to throw the requisite Spec# plug as well for how it handles DbC features in C#.

Intention Revealing Interfaces

Let's step back a little bit form the discussion we had earlier.  Let's talk about good design for a second.  How many times have you seen a method and had no idea what it did or that it went ahead and called 15 other things that you didn't expect?  At that point, most people would take out .NET Reflector (a Godsend BTW) and dig through the code to see the internals.  One of the examples of the violators was the ASP.NET Page lifecycle when I first started learning it.  Init versus Load versus PreLoad wasn't really exact about what happened where, and most people have learned to hate it.

In the Domain Driven Design world, we have the Intention Revealing Interface.  What this means is that we need to name our classes, methods, properties, events, etc to describe their effect and purpose.  And as well, we should use the ubiquitous language of the domain to name them appropriately.  This allows other team members to be able to infer what that method is doing without having to dig in with such tools as Reflector to see what it is actually doing.  In our public interfaces, abstract classes and so on, we need to specify the rules and the relationships.  To me, this comes back again to DbC.  This allows us to not only specify the name in the ubiquitous language, but the behaviors as well.

Command-Query Separation (CQS)

Dr. Bertrand Meyer, the man behind Eiffel and the author of Object-oriented Software Construction, introduced a concept called Command-Query Separation.  It states that we should break our functionality into two categories:

  • Commands - Methods that perform an action or change the state of the system should not return a value.
  • Queries - Return a result and do not change the state of the system (aka side effect free)

Of course this isn't a 100% rule, but it's still a good one to follow.  Let's look at a simple code example of a good command.  This is simplified of course.  But what we're doing is side effecting the number of items in the cart. 

public class ShoppingCart
{
    public void AddItemToCart(Item item)
    {
        // Add item to cart
    }
}

Should we use Spec# to do this, we could also check our invariants as well, but also to ensure that the number of items in our cart has increased by 1.

public class ShoppingCart
{
    public void AddItemToCart(Item item)
        ensures ItemsInCart == old(ItemsInCart) + 1;
    {
        // Add item to cart
    }
}

So, once again, it's very intention revealing at this point that I'm going to side effect the system and add more items to the cart.  Like I said before, it's a simplified example, but it's a very powerful concept.  And then we could talk about queries.  Let's have a simple method on a cost calculation service that takes in a customer and the item and calculates.

public class CostCalculatorService
{
    public double CalculateCost(Customer c, Item i)
    {
        double cost = 0.0d;
       
        // Calculate cost
       
        return cost;
    }
}

What I'm not going to be doing in this example is modifying the customer, nor the item.  Therefore, if I'm using Spec#, then I could mark this method as being [Pure].  And that's a good thing.

The one thing that I would hold an exception for is fluent builders.  Martin Fowler lays out an excellent case for them here.  Not only would we be side effecting the system, but we're also returning a value (the builder itself).  So, the rule is not a hard and fast one, but always good to observe.  Let's take a look at a builder which violates this rule.

public class CustomerBuilder
{
    private string firstName;

    public static CustomerBuilder New { get { return new CustomerBuilder(); } }
   
    public CustomerBuilder WithFirstName(string firstName)
    {
        this.firstName = firstName;
        return this;
    }

    // More code goes here
}

To wrap things up, things are not always fast rules and always come with the "It Depends", but the usual rule is that you can't go wrong with CQS.

Wrapping It Up

These rules are quite simple for revealing the true intent of your application while using the domain's ubiquitous language.  As with anything in our field, it always comes with a big fat "It Depends", but applying the rules as much as you can is definitely to your advantage.  These are simple, yet often overlooked scenarios when we design our applications, yet are the fundamentals.

Published May 01 2008, 07:15 PM by Matthew.Podwysocki
Filed under: , , ,

Comments

Reflective Perspective - Chris Alcock » The Morning Brew #86 said:

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #86

# May 2, 2008 3:16 AM

Abraham Pinzur said:

Don't overlook the option of making your object builders immutable (and side-effect-free) as well. Nat Pryce alludes to this idea in his discussion of sharing "common state" between test data builders: "The safest option is to make every with method create an entirely new copy of the builder instead of returning this."

 [nat.truemesh.com/.../000724.html]

# May 2, 2008 8:56 AM

Jimmy Bogard said:

In the ShoppingCart example, why would I want to enforce this invariant at compile-time versus run-time through a unit test?

# May 2, 2008 12:12 PM

Matthew.Podwysocki said:

@ Abraham

I understand the intent, but to do copy constructors haven't been my favorite thing since my C++ days.  But yes, that way works as well.  I'll have to kick the tires a bit, but to get rid of the side effects is interesting in that respect.

Matt

# May 2, 2008 1:20 PM

Greg said:

"In the ShoppingCart example, why would I want to enforce this invariant at compile-time versus run-time through a unit test?"

I will answer that one Jimmy ...

Because its a contractual invariant. If I enforce it in this way (and its exposed on my contract) all other code consuming that contract can assume the case to be true. Let's make this an interface instead of a concrete class; I can now also insure that this case is true for ALL implementors of that interface.

If as in this case it is also a domain specific behavior there is a high likely hood that you would ALSO have a behavioral test that shows the expected behavior but perhaps you don't show every possible permutation of the behavior (i.e. all the failure cases where it is not true since you have proven that in those cases you are still in a valid state).

Cheers,

Greg

# May 2, 2008 1:24 PM

Donnie Hale said:

For folks who are new to the idea of "side-effect free" programming, it would be helpful if a precise definition were given. Taken at face value, a "side-effect" free program could do nothing - the instruction pointer couldn't change, the content of memory couldn't change, etc. I realize I'm taking it to the extreme - my point is that the whole reason that we develop software is because we *do* want side effects.

In the context of DbC or functional programming, a "side effect" has a narrow meaning. I think your Point example in the previous blog entry was a nice simple example. We need the "side effect" of a Point with a different location (the result of the Add) so we can do something with it; but we don't want the "side effect" of any other reference to the original Point having its state changed out from under it when Add is called.

FWIW...

Donnie

# May 2, 2008 3:45 PM

Matthew.Podwysocki said:

@Donnie

Right, when I'm talking about side effects, I'm talking strictly in the sense of DbC with Domain Driven Design concepts here, so maybe some clarification is needed.

Matt

# May 2, 2008 5:15 PM

Matthew Podwysocki said:

In one of my previous posts about Command-Query Separation (CQS) and side effecting functions being code

# May 6, 2008 4:58 PM

Matthew Podwysocki's Blog said:

In one of my previous posts about Command-Query Separation (CQS) and side effecting functions being code

# May 6, 2008 5:00 PM

Matthew Podwysocki said:

In one of my previous posts about Command-Query Separation (CQS) and side effecting functions being code

# May 6, 2008 6:24 PM

Matthew Podwysocki said:

I decided to stay on the Design by Contract side for just a little bit. Recently, Raymond Chen posted

# May 9, 2008 12:42 AM

Matthew Podwysocki's Blog said:

I decided to stay on the Design by Contract side for just a little bit. Recently, Raymond Chen posted

# May 9, 2008 12:45 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

This Blog

Syndication

News

Disclaimer
The views expressed on this weblog are mine and do not necessarily reflect the views of my employer.

All postings are provided "AS IS" with no warranties, and confer no rights.

Badges



I'm test-driven!

Locations of visitors to this page


Archives