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!

Side Effecting Functions are Code Smells

I know the title might catch a few people off guard, but let me explain.  Side effecting functions, for the most part, are code smells.  This is a very important concept in Domain Driven Design (DDD) that’s often overlooked.  For those who are deep in DDD, this should sound rather familiar.  And in the end, I think Spec# and some Design by Contract (DbC) constructs can mitigate this, or you can go the functional route as well.

What Is A Side Effect?

When you think of the word side effect in most languages, you tend to think of any unintended consequence.  Instead, what we mean by it is having any effect on the system from an outside force.  What do I mean by that?  Well, think of these scenarios, reading and writing to a database, reading or writing to the console, or even modifying the state of your current object.  Haskell and other functional languages take a pretty dim view of side effects, hence why they are not allowed, unless through monads.  F# also takes this stance, as “variables” are immutable unless otherwise specified.

Why Is It A Smell?

Well, let’s look at it this way.  Most of our operations call other operations which call even more operations.  This deep nesting is then created.  From this deep nesting, it becomes quite difficult to predict the behaviors and consequences of calling all of those nested operations.  You, the developer might not have intended for all of those operations to occur because A modified B modified C modified D.  Without any safe form of abstraction, it’s pretty hard to test as well.  Imagine that any mock objects that you create would have to suddenly know in 5 levels deep that it is modified in some function.  Not necessarily the best thing to do.

Also, when it comes to multi-threaded processing, this becomes even more of an issue.  If multiple threads have a reference to the same mutable object, and one thread changes something on the reference, then all other threads were just side effected.  This may not be something that you’d want to do.  Then again, if working on shared memory applications, that might be.  But, for the most part, the unpredictability of it can be a bad thing.

Let’s take a quick example of a side effecting an object like implementation of a 2 dimensional Point.  We’re going to go ahead and allow ourselves to add another Point to the system.

public class Point2D
{
    public double X { get; set; }

    public double Y { get; set; }

    public void Add(Size2D other)
    {
        X += other.Height;
        Y += other.Width;
    }
}

public class Size2D
{
    public double Height { get; set; }

    public double Width { get; set; }
}

What’s wrong with the above sample is that I just side effected the X, and Y.  Why is this bad?  Well, like I said, most objects like these are fire and forget.  Anyone who had a reference to this Point now has a side effected one, that they might not have wanted.  Instead, I should probably focus on retrieving a new one at this point, since this is pretty much a value object.

What Can You Do About It?

Operations that return results without side effects are considered to be pure functions.   These pure functions when called any number of times will return the same result given the same parameters time and time again.  Pure functions are much easier to unit test and overall a pretty low risk.

There are several approaches to being able to fix the above samples.  First, you can keep your modifiers and queries separated.  Make sure you keep the methods that make changes to your object separate from those that return your domain data.  Perform those queries and associated calculations in methods that don’t change your object state in any way.  So, think of a method that calculates price and then another method that actually sets the price on the particular object. 

Secondly, you could also just not modify the object at all.  Instead, you could return a value object that is created as an answer to a calculation or a query.  Since value objects are immutable, you can feel free to hand them off and forget about them, unlike entities which are entirely mutable.  Let’s take the above example of the Coordinate and switch it around.  Think of the DateTime structure.  When you want to add x number of minutes, do you side effect the DateTime, or do you get a new one?  The answer is, you get a new one?  Why, well, because it’s a structure, and they are immutable, but not only that, it solves a lot of those side effecting problems.

public class Point2D
{      
    private readonly double x;
    private readonly double y;
   
    public Point2D() {}
   
    public Point2D(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public double X { get { return x; } }
   
    public double Y { get { return y; } }
   
    public Point2D Add(Size2D other)
    {
        double newX = x + other.Height;
        double newY = y + other.Width;
       
        return new Point2D(newX, newY);
    }
}

Spec# is a tool that can help in this matter.  Previously I stated why Spec# matters, well, let’s get into more detail why.  We can mark our side effect free methods as being pure with the [Pure] attribute.  This allows the system to verify that indeed we are not side-effecting the system, and any time I call that with the same parameters, I will get the same result.  It’s an extra insurance policy that makes it well known to the caller that I’m not going to side effect myself when you call me.  So, let’s go ahead and add some Spec# goodness to the equation. 

[Pure]
public Point2D Add(Size2D other)
{
    double newX = x + other.Height;
    double newY = y + other.Width;
       
    return new Point2D(newX, newY);
}

But, now Spec# will warn us that our other might be null, and that could be bad….  So, let’s fix that to add some real constraints for the preconditions.

[Pure]
public Point2D Add(Size2D other)
    requires other != null
{
    double newX = x + other.Height;
    double newY = y + other.Width;
       
    return new Point2D(newX, newY);
}

Of course I could have put some ensures as well to ensure the result will be the addition, but you get the point.

Turning To Design by Contract

Now of course we have to be a pragmatist about things.  At no point did I say that we can’t have side effects ever.  That would be Haskell and they put themselves into a nasty corner with that and the only way around it was with monads, that can be a bit clumsy.  Instead, I want to refocus where we do them and be more aware of what you’re modifying.

In our previous examples, we cut down on the number of places where we had our side effects.  But, this does not eliminate them, instead gather them in the appropriate places.  Now when we deal with entities, they are very much mutable, and so we need to be aware when and how side effects get introduced.  To really get to the heart of the matter, we need to verify the preconditions, the postconditions and mostly our invariants.  In a traditional application written in C#, we could throw all sorts of assertions into our code to make sure that we are in fact conforming to our contract.  Or we can write our unit tests to ensure that they conform to them.  This is an important point in Eric Evans’ book when talking about assertions in the Supple Design chapter.

Once again, Spec# enters again as a possible savior to our issue.  This allows us in our code, to model our preconditions and our postconditions as part of our method signature.  Invariants as well can be modeled as well into our code as well.  These ideas came from Eiffel but are very powerful when used for good.

Let’s make a quick example to show how invariants and preconditions and postconditions work.  Let’s create an inventory class, and keep in mind it’s just a sample and not anything I’d ever use, but it proves a point.  So let’s lay out the inventory class and we’ll set some constraints.  First, we’ll have the number of items remaining.  That number of course can never go below zero.  Therefore, we need an invariant that enforces that.  Also, when we remove items from the inventory, we need to make sure that we’re not going to dip below zero.  Very important things to keep in mind.

public class Inventory
{
    private int itemsRemaining;
    private int reorderPoint;
   
    invariant itemsRemaining >= 0;
   
    public Inventory()
    {
        itemsRemaining = 200;
        reorderPoint = 50;
        base();
    }
   
    public void RemoveItems(int items)
        requires items <= ItemsRemaining;
        ensures ItemsRemaining == old(ItemsRemaining) – items;
    {
        expose(this)
        {
            itemsRemaining -= items;
        }

        // Check reorder point
    }
   
    public int ItemsRemaining { get { return itemsRemaining; } }

    // More stuff here in class
}

What I was able to express is that I set up my invariants in the constructor.  You cannot continue in a Spec# program unless you set the member variable that’s included in the invariant.  Also, look at the RemoveItems method.  We set one precondition that states that number of items requested must be less than or equal to the number left.  And we set the postcondition which states that the items remaining must be the difference between the old items remaining and the items requested.  Pretty simple, yet powerful.  We had to expose our invariant while modifying it so that it could be verified, however.  But, doesn’t it feel good to get rid of unit tests that prove what I already did in my method signature?

Wrapping Things Up

So, I hope after reading this, you’ve thought more about your design, and where you are modifying state and that you have intention revealing interfaces to tell the coder what exactly you are going to do.  The Design by Contract features of Spec# also play a role in this to state in no uncertain terms what exactly the method can do with the preconditions and postconditions and through my class with my invariants.  Of course you can use your regular C#, or language of choice to model the same kind of things, yet not as intention revealing.

So, where to go from here?  Well, if you’ve found Spec# interesting, let Microsoft know about it.  Join the campaign that Greg and I are harping on and say, “I Want Spec#!”

This entry was posted in C#, DDD, F#, Spec#. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://scottic.us Scott Bellware

    Greg,

    Those problems are typical symptoms of test-last programming.

    That said, there’s value is allowing some simple forms of runtime errors to happen. These errors, as long as they’re not mission critical, lead to inquiry and understanding of ways in which clients are wishing to use code in ways that we couldn’t anticipate. This is an often critical aspect of usability design.

  • Greg

    Scott you really need to watch spec# in action…

    Why is compile time proving better than runtime + unit tests? What if I forget to write a unit test. What if I miss an edge condition…. perfect example …

    public void Foo(string s) {
    return s.SubString(0, s.Length-1);
    }

    spec# would give me 2 compile time errors there.

    1) s could be null
    2) s could have a 0 length and the call to substring would throw an exception

    Sure I could write unit tests to show these two behaviors … Of course I may not see readily that those two problems exist and realize I need to test them … spec# does!

    but let’s say I wrote that code in version 2.0 and now in 3.5 they added a NEW postcondition to string.Substring that the resulting string must have a length < 12 ... With unit tests .. my tests would still pass unless I randomly happenned to write a test for a string > 12 … With spec# when I compiled against the new framework I would get a compile time error.

    Frankly its quite simple … when it comes to CONTRACTUAL INVARIANTS it is far better to let the compiler figure things out as it doesn’t make mistakes and can handle far more complex situations than a human could.

  • http://scottic.us Scott Bellware

    Matt,

    We’re only changing the implementation details and mechanisms here and shifting the point at which verification happens. I don’t see any significant advantages over runtime verification brought about by the technology.

    I also see the syntax as excessively-declaristic, along the problematic lines of what programming in XML brings to the table.

    If the generated documentation was as good and as complete as what I get from BDD, it’d be worth considering, no doubt.

    I don’t know what it takes to completely cover all paths in Spec#, and to do so with coverage over all verification profiles unit, customer, smoke, integration, etc. I need all the documentation of all paths and profiles. I get that with BDD, and I get to apply some specifications to multiple profiles, since a given spec doesn’t have a one-to-one mapping to a profile.

    The functional code would have to still be literate – at least as literate as the code I get out of BDD practice – once all the metadata has been added to it.

    Lot’s of questions up in the air for me, and I see the strongest assertions and attestations for Spec# being made by folks who never really invested the effort to get what TDD was all about and why BDD is subsequently significant.

    This leads me at this point to worry whether Spec# is becoming a crutch for folks for whom a preference for tools over practices is at issue.

    If that’s the case, then I think Spec# is a good way to go, but in that case, I don’t think it should be hailed as anything more than a prosthetic limb.

    I’d like to do a lot more face-to-face, tangible comparisons with you over some application code to help clear up my fog over why Spec# is important.

  • http://codebetter.com/blogs/matthew.podwysocki Matthew.Podwysocki

    @Scott

    It’s not just about the readability of the code, but the static enforcement of it. That’s the important piece. I’ve enforced that I cannot call a particular piece of code with a null value because I said it can’t. That’s a lot more than documentation and the static verifier enforces that.

    But more to the point, how many assemblies do we have with no real documentation to them? Instead, these “contracts” become part of the metadata of the method itself and in turn, turn into pretty good documentation.

    Matt

  • http://codebetter.com/blogs/matthew.podwysocki Matthew.Podwysocki

    @alberto

    Agreed and it was a poor example. Instead I changed it around but the concepts still apply.

    Matt

  • http://sharpbites.blogspot.com alberto

    As a side note, your examples are not correct from the point of view of geometry. You can’t add two points, you add one point and one vector.

  • http://scottic.us Scott Bellware

    It just might be more readable, or the geektastic nature of new language constructs might be interrupting the is-it-more-readable question with a resounding “yes” that just may be generated by geekorific brain stimulation than an detached consideration of the solubility of the code.

    I’m not convinced either way.

  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Steve

    Yes, I was aware of Cobra but wasn’t sure how far along the language is as it’s trying to do quite a lot. The big win should that come to C#, we’d get that for a language that most people use and decent IDE support. I’ll give it another shot to see if I like it any more at this point.

    Matt

  • Steve Thompson

    Well, the Cobra language doesn’t have pure (yet), but it allows you to get going with DbC right now. It is definitely worth looking into.