DEV Community

Jan Van Ryswyck
Jan Van Ryswyck

Posted on • Originally published at janvanryswyck.com on

Debugability Considered Useful

Developers are lazy. There’s nothing new about that. We even pride ourselves on it. Sometimes being lazy is a good thing, but most of the time it’s not something we should brag too much about. Let’s have a look at a few examples of developer laziness in action.

public SomeViewModel Map(Something something)
{
    return new SomeViewModel
    {
        Name = something.Name,
        ListA = something.itemsA.Select(itemA => MapItemA(itemA, additionalParameter1, additionalParameter2)).ToList(),
        ListB = something.itemsB.Select(MapItemB).ToList(),
        ListC = something.itemsC.Select(itemC => MapItemC(itemC, additionalParameter3)).ToList(),
        ListD = something.itemsD.Select(itemD => MapItemD(itemD, additionalParameter4)).ToList()
    };
}

This is an example of some code that we’ve all seen before. Heck, I encounter this on a regular basis. You know, inlining code as much as possible in order to avoid declaring variables. The developer in question probably had a hard time coming up with variable names. Completely understandable. Coming up with names that express intent is one of the most difficult things that we face when writing code. But this is also where laziness becomes quite hurtful. Let’s have a look at another example.

foo.SomeMethod(new Bar(parameter1, parameter2), items.Where(item => item.Property1 == someFilterValue).Select(item => new Buzz { PropertyX = item.Property2, PropertyY = x.Property3 }).ToList());

This is a nasty one, isn’t it? While the previous example is still somewhat nicely formatted, this one is pretty bad. I’ve seen method calls like this where I had to horizontally scroll several pages in order to get to the closing semicolon. I sometimes wonder whether this is still laziness or just mere hatred towards the next person reading this code. Every time I’m horizontally scrolling in my code editor, I wonder what I did wrong to deserve such apathy. These examples communicate sloppiness and a disregard when it comes to readable code. In such cases I argue to improve the debuggability of the code.

“How difficult is it going to be in order to debug this code?” That is the question that we should ask ourselves more often. How difficult is it going to be to debug the code snippets from these two examples? It can be done, for sure. But is it going to be easy? Or is it going to be a bit more difficult than we would like?

For the first example, suppose that we want to inspect the items of the ListC property of the returned view model object. Where should we add a breakpoint? For the second example, suppose that we would like to inspect the items passed as the second argument to SomeMethod. How would we do that without any additional effort like stepping into the method to inspect the parameter or evaluating the LINQ expression itself during a debug session?

I’m definitely not advocating that we should spend more time using the debugger. In fact, debugging code is wasteful and we should avoid it as much as possible. But I do advocate for the debugability of code.

“ Debugging is worthless, but debuggability is everything.

— Some smart person

What do I mean by that? Let’s have a look at the improved versions of the two code example shown earlier.

public SomeViewModel Map(Something something)
{
    var listA = something.itemsA
        .Select(itemA => MapItemA(itemA, additionalParameter1, additionalParameter2))
        .ToList();

    var listB = something.itemsB
        .Select(MapItemB)
        .ToList();

    var listC = something.itemsC
        .Select(itemC => MapItemC(itemC, additionalParameter3))
        .ToList();

    var listD = something.itemsD
        .Select(itemD => MapItemD(itemD, additionalParameter4))
        .ToList();

    var result = new SomeViewModel
    {
        Name = something.Name,
        ListA = listA,
        ListB = listB,
        ListC = listC,
        ListD = listD
    };

    return result;
}

var bar = new Bar(parameter1, parameter2);
var filteredItems = items
    .Where(item => item.Property1 == someFilterValue)
    .Select(item => new Buzz { PropertyX = item.Property2, PropertyY = item.Property3 })
    .ToList()

foo.SomeMethod(bar, filteredItems);

This sure looks like more code compared to the initial version. That might be true. But we also immensely improved the debugability of the code. For the first example, suppose that we would like to inspect the items of the ListC property of the returned view model. At this point we even have two options. We can set a breakpoint on the line where we return the result variable. But we can also set a breakpoint earlier on in order to inspect the listC variable. The same goes for the second example where we have better options to debug the code.

But most importantly, we also improved the readability of the code. We also no longer have to horizontally scroll in order to grasp what’s going on. These days, decent code editors like Rider display a vertical line at the 120 characters mark. Whenever crossing this line while typing, a mental alarm bell should start to go off and we should consider the readability of the code.

Code that is easy to debug, is also very readable and easy to reason about. Therefore I suggest we should consider this attribute of code quality more often.

Top comments (0)