I like to remind myself of these little principles that I take for granted, now and then. It’s good habit to get back to basics and really understand why you hold principles so that you can judge whether or not they are appropriate in the circumstances you are in. Today’s little nugget of principle is to write expressive code and avoid magic values in your code.
For example, I was writing some graphics code for a specialized button in Compact Framework development. I wanted to draw an outline around my box but only the left side, top and right side – leaving the bottom blank. I started with this code:
1: graphics.DrawLine(outlinePen, 0, 0, 0, ClientRectangle.Height);
2: graphics.DrawLine(outlinePen, 0, 0, ClientRectangle.Width, 0);
3: graphics.DrawLine(outlinePen, ClientRectangle.Width-1, 0, ClientRectangle.Width-1, ClientRectangle.Height);
(Note: ClientRectangle is provided by inheriting from Control in the compact framework. It’s the visible rectangle of the control.)
This code works perfectly and does what I want. In writing this code, I had to stop and think about the values that needed to go into each position as I was writing each one of these lines of code. It only took a few seconds to complete all three lines of code so it was not a big deal. However, I decided that I didn’t like this code because I found it very difficult to read. Every time I look at it (even though I wrote it) I have to remember which values are paired together to form which x/y coordinates, so that I can visualize what this will look like. Add in the object.property use and the simple math and there’s more work to read this code than I care for.
So, I fixed it. I removed the magic values (no hard coded integers) and I created variables that expressed what the math calculations represented.
1: int left = 0;
2: int right = ClientRectangle.Width - 1;
3: int top = 0;
4: int bottom = ClientRectangle.Height;
6: graphics.DrawLine(outlinePen, left, top, left, bottom);
7: graphics.DrawLine(outlinePen, left, top, right, top);
8: graphics.DrawLine(outlinePen, right, top, right, bottom);
Sure, I have 4 extra lines of code now. But look at the three lines of code that do the actual drawing compared to what was there previously. I don’t have to parse and calculate to understand where the line is being draw anymore. I can simply read “left-top to left bottom” and understand much faster “oh, this draws along the left border.”
Don’t just fulfill the technical requirements of the language syntax that you are writing. Write code that expresses your intent and an understanding of that intent that can be transferred to anyone else who reads the code.