Less code matters

June 16, 2011 at 9:31 pm | Posted in Agile, C#, GIMP, Programming | 11 Comments

One of Edsger Dijkstra‘s quotes I really like is: If we wish to count lines of code, we should not regard them as “lines produced” but as “lines spent”. This hasn’t changed since those days despite of almost infinite amounts of processing power, memory and powerful IDE support. In fact I would argue that thanks to this power we are now able to build huge systems which makes carefully spending these precious lines of code even more important. The main reason still is that once you start producing code, you have to maintain it. And maintaining code will take effort and therefore will cost money.

Over the years I have worked on a lot of code, both existing (as in maintenance projects) and while building new software. My personal statement was and still is that any non-trivial amount of code can easily be reduced to half it’s size while increasing readability at the same time. There are several ways to reduce code size. As an example I will take 18 revisions (from CVS) from a small GIMP# plug-in and show what I did to gradually reduce the size.

Let’s start with looking at the graph that depicts the code size first:

This is a small plug-in that calculates the average color of all pixels in an image. Next the plug-in sets the color of all pixels in the image to this average color. This functionality is provided as the “Blur Average” filter in Photoshop and I wrote it because it didn’t exist for the GIMP yet.

I took the size in lines of code from CVS. I included all white lines and comment lines, apart from the standard 20 lines of GPL header at the start of every file. Next I used the maximum size (at revision 3) as 100 % and scaled the rest of the revision sizes relative to this maximum. Now let’s see what happened at these 18 revisions:

  1. Revision 1.1. Checked in initial code. This was mainly the boiler plate code that comes with any plug-in written in the GIMP# framework. At that moment this was 50 LOC.
  2. Revision 1.2. Plug-in now fully functional. Wrote two straightforward loops, one to calculate the average, the other one to apply it to all pixels. Code has grown to 63 LOC.
  3. Revision 1.3. A GIMP# co-developer added code for i18n. Code now at it’s maximum size of 68 LOC. Still pretty small of course. Keep in mind that a similar basic plug-in written in C (the default GIMP programming language) takes about twice as much code.
  4. Revision 1.4. Accidentally  in revision 1.3 a key (from a key/value pair) was translated. Fixed that which saved 2 lines. Nice start on my way to a smaller plug-in. 66 LOC left.
  5. Revision 1.5. The i18n initialization that happened in all plug-ins, was moved to the constructor of the base class, removing another 3 lines. 63 LOC left.
  6. Revision 1.6. Until this revision I had to handle all pixels as arrays of 3 (or 4, including alpha channel) bytes which held the RGB(A) values. I abstracted this into a Pixel class and wrote an iterator that calls a delegate for every pixel in this particular image. I added some overloading magic for Pixel objects that allows me to add pixels and easily calculate the average. Of course this added to the main GIMP# library, but my plug-in code shrunk to 55 LOC.
  7. Revision 1.7. A bit of cleaning up, code size stayed at 55 LOC
  8. Revision 1.8. Instead of returning a set of all supported procedures (needed to register a plug-in within GIMP) this same function now returns the C# yield construct, saving another 3 lines. 52 LOC left.
  9. Revision 1.9. Minor clean-up, improving readability. Code still at 52 LOC.
  10. Revision 1.10. Improved algorithm to calculate the average. In previous revisions I was updating a counter (that had to be initialized) inside the first iterator so I could later divide the sum by this counter to calculate the average. Of course the number of pixels within an image (or selection) is already known and can be asked directly from the iterator class. This allowed me to remove another 2 lines, leaving the size now at 50 LOC.
  11. Revision 1.11. The delegate to calculate the average was since the previous revision a short one-liner. No need anymore to spread that over 3 lines, including the curly braces. Inlining this delegate into the iterator call removed 3 lines. Code size at 47 LOC.
  12. Revision 1.12. Oh no! Code has grown to 48 LOC. Reason is that I tried anonymous function support in Mono, concluded that it didn’t work (yet) but left the updated line as a comment in the code.
  13. Revision 1.13.  Still 48 LOC. Only minor textual changes to code.
  14. Revision 1.14. Finally I realized that have commented out code is bad practice. Removed it, reducing the size to 47 LOC again.
  15. Revision 1.15. Mono 1.2.6 supported lambda functions. Did a bit of cheating and removed 1 empty line that divided 3 lines that logically belonged together. Size now at 46 LOC.
  16. Revision 1.16. A new C# 3.0 feature (object initializers) allowed me to remove another 2 lines. Code size at 44 LOC.
  17. Revision 1.17. Another 2 lines moved to the Plugin base class. 42 LOC left.
  18. Revision 1.18. Simplified GIMP# framework API a bit, allowing me to remove another line from almost all plug-ins. This is the most recent version which was checked in on June 10th, 2010. No changes since that time. Code size is 41 LOC.
As you can see I went from a maximum of  68 LOC to the current size of 41 LOC. I didn’t manage to remove half of the code, but 40 % still isn’t bad for such a small amount of code. At least I don’t have to maintain those 27 removed lines anymore. At the same time the readability has improved a lot. In a next blog I will categorize all the methods that can be used to reduce your code size, based on my personal experience.
For completeness the final code:
using System;
using System.Collections.Generic;

namespace Gimp.AverageBlur
{
  class AverageBlur : Plugin
  {
    static void Main(string[] args)
    {
      new AverageBlur(args);
    }

AverageBlur(string[] args) : base(args, "AverageBlur")
    {
    }

    override protected IEnumerable<Procedure> ListProcedures()
    {
      yield return new Procedure("plug_in_average_blur",
                                 _("Average blur"),
                                 _("Average blur"),
                                 "Maurits Rijk",
                                 "(C) Maurits Rijk",
                                 "2006-2009",
                                 _("Average"),
                                 "RGB*, GRAY*")
        {MenuPath = "<Image>/Filters/Blur"};
    }

    override protected void Render(Drawable drawable)
    {
      var iter = new RgnIterator(drawable, _("Average"));

      var average = drawable.CreatePixel();
      iter.IterateSrc(pixel => average.Add(pixel));
      average /= iter.Count;

      iter.IterateDest(() => average);
    }
  }
}
About these ads

11 Comments »

RSS feed for comments on this post. TrackBack URI

  1. yah you save lines of code by replacing code with anonymous functions or lambda functions whatever

    your code gets cleverer as you use more and more language features

    maybe c# is different but in c++ clever code is considered bad form

  2. @karl: I suggest you _look at the code_ to form an opinion. This is not my definition of _clever code_ by any stretch.

    You shouldn’t confuse C++ with C#; In my environment C# programmers will object more to the use of ternary ?: than to the use of a lambda in an IterateSrc action (which is explicitely designed to take an Action by the way).

    I’ve seen (and written) my share of ‘clever’ code in C# (as well as in C++ I might add) and this is not what it looked like :)

  3. Congratulations, you managed to turn every program either into a single instruction or make it a trivial piece of code. Either that, or you should be careful when to use all quantification.

    Besides that, I second karl that shorter code is often harder to read and maintain.

    • I partly agree with both your and Karl’s point but I think it should be stated like this:

      – Shorter code doesn’t imply more maintainable (cleaner) code
      – Cleaner code almost always results in shorter code (See Uncle Bob’s books for an interesting read).

      The example I gave is pretty trivial and also quite small. But even here if you compare revision 1.3 and 1.18 you will find that the latter version is both smaller and easier to read.

      My experience is based on programs ranging from a few hundred to several hundreds of thousands of LOC over the last 20 years. More information in a next upcoming blog.

  4. It’s simple.

    Bugs per line of code is a fairly constant metric. So to reduce bug count, reduce the lines of code (Actually, reducing the number of AST tokens may be a better way of putting it).

    I can think of 2 projects in the past 7 years where I’ve taken a reasonable sized chunk of (C#) code and refactored it, removing 30% of the LOC (excluding comments). This 30% figure has now become my benchmark.

  5. I guess the point is that in writing clear and maintainable code, the code ussually also get’s more compact. Just be pragmatic, short code isn’t a goal in itself and I agree with the author it’s well worth looking at unnescessary lines of code and removing them.

  6. Personally I think writing plug-ins should be possible with short terse code with an understandable API. I hope that GEGL has succeeded where the writing of plug-ins for GIMP in C is indeed verbose. Trimming comment and blank lines out of the invert plug-in in GEGL I end up with 48 lines of code http://git.gnome.org/browse/gegl/tree/operations/common/invert.c which I think is quite good. There are some conventions to pick up; but these conventions are most probably easier to pick up than a full understanding of GObject which would be the alternative to the magic chanting.

  7. I don’t really belong here but I use GIMP for scrapbooking. I was searching to see if there was a way to run PS actions in GIMP and came across this. Is it just for programmers or is there a download that will install your plug-in for us non-geeks? If so, that would be fantastic!
    Thanks.

    • I’m afraid there is no easy way to install GIMP#, especially not if you are using Windows. At the moment the Windows installer is outdated since it doesn’t have a maintainer anymore and I don’t use Windows myself.

      • Ah well, them’s the breaks. Thanks for the info.

  8. [...] got quite a few reactions on my previous blog post both positive and negative. The message of the negative comments was mostly that short code [...]


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

Blog at WordPress.com. | The Pool Theme.
Entries and comments feeds.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: