Defective Language

The unfortunate world of boilerplate code

Redundancy is one of the biggest sources of defects in programming. Boilerplate is highly redundant. While it may be easy to implement, and often necessary, it reduces code legibility and increases maintenance costs. Boilerplate is a strong indication of a language or framework that is missing features.

Copy-and-paste in disguise

Copy-and-pasting code within a project, or even company, is a generally the undesired solution. It creates code duplication. It increase the chances of defects since the copied code has less review than original code. It then multiplies those defects as the code is copied again.

Boilerplate is a form of copy-and-paste. Even if we aren’t copying exactly, using code as a template to mindlessly produce new code is essentially the same as copy-and-paste. I’m a bit more forgiving of this practice though since often it is unavoidable.

Composition

A common occurrence of boilerplate is the composition pattern. Few languages offer a way to do this succinctly. The typical pattern looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class foo_impl : public common_interface {
    //the composed class
    common_impl core;

public:
    int common_one( int a, float b, variant c ) {
        return core.common_one( a, c, b );
    }
    int common_two( string a ) {
        return core.common_two( a );
    }
    void common_three( custom c, other q ) {
        return core.common_three( c );
    }
}

A class implements an interface and then uses a common implementation for most of the functions, or often for all of the functions. The idea is solid; I like composition in object oriented programming. The implementation however leaves a lot to be desired.

The first problem is defects. It’s quite easy to get the parameters in the wrong order when forwarding the functions. In a statically typed language the compiler will likely find most of those problems, but a dynamic language cannot. Neither language type can actually prevent us from calling the wrong function, though perhaps a statically typed one might give us warnings about unused parameters.

Did you even notice that I made three mistakes in my forwarding?

The second problem is one of clarity. Other than the comment “the composed class” I can’t quickly determine what structure this actually is. Instead of something indicating it is a “delegate”, I just see a bunch of individual functions calling other functions. It lacks significant semantic clarity.

The problem of composition is so common that many languages actually have solutions for it now. Things like traits and mixins, as well as explicit delegation extensions. I think those are all great features and it’s very unfortunate not all languages, even some very popular ones, don’t have a clean solution for this.

Skeletons in the closet

A lot of projects, or modules, are bootstrapped with standard code. We can follow a series of steps in constructing the basic code. Sometimes we get “lucky” and have a program that generates it for us. This type of skeleton code is common for web projects.

This type of activity makes me queesy. Before I can even start with the real part of our project I’m forced to work through a lot of boilerplate, redoing the work, and refixing the mistakes, that hundreds of others have already done.

I’m also left wondering whether I have to do this way, or it’s just a recommended example. I’ve been criticized before by colleagues for changing the standard setup. If the code is actually so critical then why exactly am I being forced to do it myself?

I would much prefer if library vendors figured out why they need all this code and then hide it via abstractions. An ideal platform would allow us to program just the parts interesting to our project without needing any boilerplate.

I’ve found bugs in skeleton code before; do all the projects out there thus have the same bugs in it? Even if the library author fixes the skeleton code all those projects will still have that bug in it. It’s a significant problem with boilerplate code in general: bugs in the primordial form get multiplied into every place it was used.

Hey, but “Patterns”!

This is not a criticism of patterns in general, but about how they are often implemented. Core concepts like visitors and adapters are sound. It’s often a problem of the languages we are using. They have no way to concisely express a pattern; we resort to boilerplate redundancy to workaround a language limitation.

It’s depressing that reducing redundancy is not a key focus of most programming languages. It’s perhaps the biggest source of defects and maintenance cost. Being able to wrap up a pattern, give it a name, and share it’s logic, significantly improves code legibility and quality. Anytime you can do this, please do. Anytime you can’t, then post examples to your favourite language forum. Maybe somebody can help, or maybe with enough interest a new language feature can be introduced.

We need to stop accepting boilerplate code!

7 replies »

  1. The functional world does seem to have a strong focus on removing boilerplate code. I completely agree that there should be no reason for boilerplate. E.g. for a basic CRUD interface I should be able to just declare a few record types, and (provided they’re built solely of primitives and other records) it should be one-line to serve CRUD endpoints via REST, connecting those up to a database whose table definitions I can generated directly from those same record declarations. I work in Scala and there’s no technical reason this couldn’t happen – all the pieces are there – there just doesn’t seem to be anyone putting them all together.

    (Obviously that’s a pretty useless webapp as it stands – you’d want to override/customize the behaviour of various endpoints and/or add more so that it actually /does/ something – but it would be the equivalent of the template you generate when using rails or the like).

    • Adding appropriate override points is often the challenge for a library. It’s often the reason boilerplate is chosen often well contained modules.

  2. doesn’t this approach break encapsulation?
    If I want to implement I will need to open up the common_one/two/etc functions as public for the common_impl class.
    In the particular example I would prefer global static library that handles the functions as helper sub-classes(nested and instantiated over internal factory) maintaining their instances and incorporating exception management.

    • I’m not clear on what you are saying breaks encapsulation? Using a common class to implement it?

      In general I haven’t seen that using composition, even in this ugly boilerplate way, breaks encapsulation of the outermost types.

    • the common_impl class must declare the function implementations as public so that they are accessible from the foo_impl(in the example). The point is that that the composition of the actual implementation creates additional layer of access between the instances(foo_impl and common_impl).
      It is normal for a class to declare public members, those however must be tied to the purpose of the class(baloon.inflate(T f_objGasType, int f_intVolume) for example), and not really exposed to the “global” space. In this particular example one does not actually call the common_impl functions directly but over the interface implemented by foo_impl.

    • I’m not sure I’ve ever really seen this argument before. Are you claiming that you shouldn’t create these new layers because they add functions, that while private in a higher layer, must be public in this lower layer?

      If I’ve understood that correctly then I think you’re artificiailly limiting your code design trying to achieve an ideal that I don’t know anybody else that has.

    • I try to keep the interface as clear as possible by separating the internal mechanics from the system level functionality.
      I observe a software system as a multi-dimensional structure that is be built in multiple layers/levels(system logic here) while functions(system level again) can be observed as clusters that are defined over multiple layers/levels.
      Since I always work with the full system in any dimension I am constantly pushing down the interfaces and the start/end-points they define so that I can keep the data-set that represents the system I am working on navigation-able.

      I agree that it is closer to a fiction than reality, but approaching it as coding/design convention makes my life easier, while designing/implementing. The approach has downsides, since at some moments the code can get really complex, but complex is ok for me as long as it does not suck performance from the system, or introduce exponential growth of required resources at run-time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s