http://www.codinghelmet.com/  

Wear a helmet. Even when coding.

howto > defensive-design-an-experiment

Defensive Design: An Experiment
by Zoran Horvat @zoranh75

We can start from traditional defensive coding techniques and improve code stability significantly. Adding else branch to every if instruction, not forgetting default branch in the switch instruction, checking for null before accessing an object, to name just a few.

But in this article, I plan to oppose these techniques to the defensive design. Primary trait of defensive design is that it removes explicit defensive code. Take a look at the piece of code below. The data variable is, supposedly, some collection of integers.

void ReportSuccess(int min) { ... }
void ReportFailure() { ... }
...
if (data.Any())
{
    int min = data.Min();
    ReportSuccess(min);
}
else
{
    ReportFailure();
}

Which part is defensive in this if-else instruction? – Its else branch is the defensive part. I have no dispute with the if block. I have dispute with part under the else branch. That is what makes the whole situation special. Forgetting the else part would cause erratic behavior. Yet, if-else without else would still be perfectly correct from syntactic point of view.

If only I could make those two sequences of operations same, I would be able to merge if and else branches into one. That would render the condition irrelevant, and I could remove it entirely, together with the if-else instruction which contains them.

And, just to make it clear, condition makes perfect sense here. I could never find minimum out of no data – that operation would fail. Now that situation, that inability to find minimum out of no data, reminds me of a trick, an algorithm called Quick sequential search. Let’s cover that first.

Motivational Example: Quick Sequential Search Algorithm

Below is a straight-forward implementation of sequential search. The function is telling whether the array contains the search value or not.

bool Contains(int[] array, int searchValue)
{
    for (int i = 0; i < array.Length; i++)
    {
        if (array[i] == searchValue)
        {
            return true;
        }
    }
    return false;
}

Loop in this implementation has two branching instructions, and both execute with every iteration of the loop. Now one of these branching instructions, the one inside the loop, is coming from the fact that we don’t know whether the array contains the value at all. And then, when said that way, there comes the Quick sequential search algorithm and says – why don’t we put the search value into the array ourselves? If we do that, then the array will certainly contain the search value.

Look at the alternate implementation. Don’t let it frighten you:

bool Contains(int[] array, int searchValue)
{
    int lastIndex = array.Length – 1;

    int last = array[lastIndex];
    array[lastIndex] = searchValue;

    int index = 0;
    while (array[index] != searchValue)
    {
        index = index + 1;
    }

    array[lastIndex] = last;

    return index < lastIndex || last == searchValue;
}

This algorithm is putting the last value from the array aside, and then replacing it with the search value. The point here is that now we know for sure that the array contains the search value. Then the algorithm simply searches for the value, remembering the index at which it was found. Search will always be successful, hence entire loop boils down to one branching instruction. That is how we have simplified the loop by adding the search element to the array. After the loop, we are reconstructing the original array’s content. And then we are simply testing whether we have found our search value, or the value which was there in the original array.

That was quite a lot of code to reduce complexity of the loop. But you get the point. It is possible to tweak the execution context in such way that two execution scenarios become merged into one unified scenario which doesn’t care about differences in the original context.

That idea is greater than this example, this quick sequential search algorithm, which I doubt that anyone has ever really implemented in production. Who knows, maybe it was used somewhere.

Now back to the question of finding the minimum of an array.

Redesigning to Include Defensive Design

Here is the previous piece of code again:

void ReportSuccess(int min) { ... }
void ReportFailure() { ... }
...
if (data.Any())
{
    int min = data.Min();
    ReportSuccess(min);
}
else
{
    ReportFailure();
}

I will start redesigning the code. In the end, I hope to reach a design which is defended out of the box.

The problem is that we can’t take the minimum out of no data. This will not work when data collection is empty. But if we put something into the collection then there will never be the case with no data, right?

int potentialMin = data.DefaultIfEmpty(0).Min();

This call will never fail, and therefore I don’t have to guard it. The only problem is that from time to time it will return my arbitrarily selected value zero. I will have to keep that in mind for the next step – choosing one out of two possible functions.

Let’s put it precisely that way:

void ReportSuccess(int min) { ... }
void ReportFailure() { ... }
...
int potentialMin = data.DefaultIfEmpty(0).Min();
Action todo = data
    .Take(1).Select(_ => () => ReportSuccess(potentialMin))
    .DefaultIfEmpty(ReportFailure)
    .Single();

todo();

Here is the explanation how this code works. If there is at least one element in the collection, then I want the first function to run. If there is not even one piece of data in the collection, then I want the other function to run. And then, after selecting the function, I just need to collapse this sequence containing exactly one action into the proper action variable.

In the end, the todo variable will contain the precise operation that should be executed. That is why I am simply invoking the todo function unconditionally in the last line of code. Whatever the operation it is, I am safe to invoke it unconditionally.

Don’t judge this code yet. There are better, shorter, more readable ways to accomplish the same goal. I only wanted to show you, as a kind of a mind experiment, that it is possible to completely remove one defensive if-else instruction from code.

What have I got in the end? I have got a unified flow. There is no branching anymore and no defense. Each instruction is producing one single result. Defense has moved deeper under the skin.

The first instruction, which calculates potential minimum, acknowledges that there might be no data to take minimum of, and then it admits, through the name of the variable, that its result might not really be the minimum I needed.

The second instruction also acknowledges that there might be no data, and therefore the expected action, ReportSuccess, might disappear in the process. That asks for a corrective action, and that is to include the negative function, ReportFailure, if needed. And then I am collapsing the sequence into one single action. This leaves no doubt about what to do next, and I am simply invoking the designated action.

Improving the Defensive Design

Is this code defended better? It almost is. Its strongest point is in the middle part, determining the action. I could improve it a bit by calculating the minimum only in place where it’s already known for sure that the minimum exists:

void ReportSuccess(int min) { ... }
void ReportFailure() { ... }
...
Action todo = data
    .Take(1).Select(_ => () => ReportSuccess(data.Min()))
    .DefaultIfEmpty(ReportFailure)
    .Single();

todo();

If you forgive me the utterly ugly syntax, which obviously contradicts usual suggestion that the code should be readable, you will agree at least about one thing: About how hard it has become for me to make a mistake. This code is defended by design.

And readability can be fixed. Here is a better syntax which does the same thing:

void ReportSuccess(int min) { ... }
void ReportFailure() { ... }
...
Action todo = data
    .FirstOrNone()
    .Map(_ => () => ReportSuccess(data.Min()))
    .Reduce(ReportFailure);

todo();

This implementation is coming from a custom Option type. You can learn more about Options from Option Functional Type and Understanding the Option (Maybe) Functional Type.

The point of this experiment is that we can acknowledge existence of two execution paths and then merge them into one, so that downstream operations have no idea how they got that one execution stream coming their way. You will be better off on more than one account if you can accomplish that.

See also:

Published: Sep 26, 2017; Modified: Sep 17, 2017

ZORAN HORVAT

Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on object-oriented and functional design, design patterns, writing unit and integration tests and applying methods to improve code design and long-term maintainability.

Follow him on Twitter @zoranh75 to receive updates and links to new articles.

Watch Zoran's video courses at pluralsight.com (requires registration):

Making Your C# Code More Object-Oriented

This course will help leverage your conceptual understanding to produce proper object-oriented code, where objects will completely replace procedural code for the sake of flexibility and maintainability. More...

Advanced Defensive Programming Techniques

This course will lead you step by step through the process of developing defensive design practices, which can substitute common defensive coding, for the better of software design and implementation. More...

Tactical Design Patterns in .NET: Creating Objects

This course sheds light on issues that arise when implementing creational design patterns and then provides practical solutions that will make our code easier to write and more stable when running. More...

Tactical Design Patterns in .NET: Managing Responsibilities

Applying a design pattern to a real-world problem is not as straight-forward as literature implicitly tells us. It is a more engaged process. This course gives an insight to tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More...

Tactical Design Patterns in .NET: Control Flow

Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More...

Writing Highly Maintainable Unit Tests

This course will teach you how to develop maintainable and sustainable tests as your production code grows and develops. More...

Improving Testability Through Design

This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More...

Share this article

webmasters