How to avoid code duplication. Case 1.

As a Clean Code lover, I really hate duplicated code.

In his homonymous book, Robert C. Martin states

”duplication may be the root of all evil in software”

And I think he IS absolutely right.

You better keep your code away from clones… or they will come back to you in the shape of a muddy monster that, for sure, will eat you.

I personally came to a situation in which I find it difficult to avoid repeating myself. This is the case:

I have a method that makes some calculations in a 2D plane (for layout and runtime design). This method takes some lengths and some points and make the necessary modifications to a control in order to a 2D transform to it. Let’s see a real sample in C#:

  • This sample method is really random, but it demostrates the problem. Each version works with one dimension, vertical or horizontal. Essentially both methods do the same, and the structure is almost identical. How to simplify these 2 into ONE?

For horizontal values:

        public static Rect DoSomethingCoolHorizontal(Rect inputRect)
        {

            var multiplyHorzPositions = inputRect.Left * inputRect.Width;

            Rect p = new Rect();

            p.Left = multiplyHorzPositions;
            p.Top = inputRect.Top;

            p.Width = multiplyHorzPositions;
            p.Height = inputRect.Height;            

            return p;
        }

For vertical values:

        public static Rect DoSomethingCoolVertical(Rect inputRect)
        {
            var multiplyVerPositions = inputRect.Top * inputRect.Height;

            Rect p = new Rect();

            p.Left = inputRect.Left;
            p.Top = multiplyVerPositions;

            p.Width = inputRect.Width;
            p.Height = multiplyVerPositions;

            return p;
        }

You may notice those 2 methods are 95% the same. But each one calculates the values for each axis. Vertical and horizontal use different properties.

The duplication in these kind of methods, follow  this simple rule:  when in the first method it says “left”, in the second it says “top”. As expected, “width” is replaced by “height”. The same would have been applicable for x and y.

In the case above, the rest is exactly the same, except for the return, that reverses the order of the Point arguments). They are so repetitive that even a text search&replace would do the job in order to replicate the same calculations for the other axis.

To clarify the method, you have to take into account that the structs that carry the properties are Rectangles with 4 attributes, that actually are 2 (2 for each dimension).

I tried to keep it beautiful, but I failed miserably again and again. That’s why I asked myself to Uncle Bob. I hope he could shed a bit light on this.

EDIT

Attention: Robert Martin did his magic again! I asked him in Twitter and has been so considerate and kind that he rewrote the sample in Java with the duplication totally eliminated. He provided a link with the source code. Just see the comments section.

WOW.

The solution to this lies in making a method that swaps vertical / horizontal dimensions. The call to the Vertical derivative is the Horizontal one with 2 swaps (argument and result):

        public static Rect DoSomethingNonDuplicateVertical(Rect inputRect)
        {
            return DoSomethingCoolHorizontal(inputRect.Swap()).Swap();
        }

With the Swap method being:

        public Rect Swap()
        {
            return new Rect(Top, Left, Height, Width);
        }

The constructor of the Rect class is:

  public Rect(double left, double top, double width, double height)
        {
            Left = left;
            Top = top;
            Width = width;
            Height = height;
        }

Now IT REALLY DOES SOMETHING COOL.

Thanks, Uncle Bob. Great tip!

2 thoughts on “How to avoid code duplication. Case 1.

  1. Súper JMN

    Thanks a lot, Robert. I updated the post with your code. I’m really surprised by the solution you gave. “Swap of the input, swap of the output”. I would have never imagined it. By the way, I also corrected the “Vertical” (had a mistake I’m sure you fixed while recoding the sample, as your code is absolutely right :))

    Like

    Reply

Leave a reply to Robert C. Martin Cancel reply