Less code matters
June 16, 2011 at 9:31 pm | Posted in Agile, C#, GIMP, Programming | 11 CommentsOne 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:
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- Revision 1.7. A bit of cleaning up, code size stayed at 55 LOC
- 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.
- Revision 1.9. Minor clean-up, improving readability. Code still at 52 LOC.
- 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.
- 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.
- 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.
- Revision 1.13. Still 48 LOC. Only minor textual changes to code.
- Revision 1.14. Finally I realized that have commented out code is bad practice. Removed it, reducing the size to 47 LOC again.
- 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.
- Revision 1.16. A new C# 3.0 feature (object initializers) allowed me to remove another 2 lines. Code size at 44 LOC.
- Revision 1.17. Another 2 lines moved to the Plugin base class. 42 LOC left.
- 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.
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);
}
}
}
11 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a Reply
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.


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
Comment by karl— June 17, 2011 #
@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
Comment by Seth— June 17, 2011 #
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.
Comment by h0uz— June 17, 2011 #
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.
Comment by maurits— June 17, 2011 #
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.
Comment by RichB— June 17, 2011 #
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.
Comment by Menno Jongerius— June 17, 2011 #
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.
Comment by Øyvind Kolås— June 21, 2011 #
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.
Comment by Robin— June 25, 2011 #
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.
Comment by maurits— June 27, 2011 #
Ah well, them’s the breaks. Thanks for the info.
Comment by Robin— June 28, 2011 #
[...] 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 [...]
Pingback by Less code matters: don’t repeat yourself « Maurits thinks aloud— June 27, 2011 #