Spelling things out can help not only with readability but also writability.
This might seem like a silly interview question but I was asked once in an interview to write a function to rotate an image 90 degrees. The source and destination are provided (you don't need to do any memory allocation) and the width and height of the source. Yes, it's an easy problem. I suggest you do it before continuing and see if you have any trouble.
.
Did you? Did you test it? Since I was asked the question in an interview I used the question in interviews as well and what I found was many programmers would get confused. They'd write code like this
void Rotate90(const Pixel* src, Pixel* dst, int width, int height)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
dst[???] = src[???];
And that's where they would get stuck. They would spend sometimes as much as 20 minutes on the whiteboard trying to figure out what goes in those ??? area. Lots of times they'd think they have the answer and write things like
dst[x * width + (height - 1 - y)] = src[y * width + x];
getting the fact that using width
with dst
is wrong. Or often they'd get the x
and y
mixed up in one side or the other.
The problem is that x
, y
, width
, and height
all swap meaning because when rotating 90 degrees the destination becomes width tall and height wide which makes referring to things confusing. I always wished a programmer would add some more variables to help make it clearer for themselves, like this
void Rotate90(const Pixel* src, Pixel* dst, int src_width, int src_height)
{
int dst_width = src_height;
int dst_height = src_width;
for (int src_y = 0; src_y < src_height; ++src_y)
{
for (int src_x = 0; src_y < src_width; ++src_x)
{
int dst_x = src_height - src_y - 1;
int dst_y = src_x;
dst[dst_y * dst_width + dst_x] = src[src_y * src_width + src_x];
}
}
}
It seemed to me breaking things out into their explicit meanings would make it far easier to write the code and far easier to avoid mistakes. I felt like if I saw a programmer do this I'd think of them as wise and rate them higher.
Yes there are a few optimizations you can make. That's not the point. Yes, the math inside the last statement could also be broken out into separate lines. That would be fine as well. The point is, adding more lines made it easier to understand for the person writing the code, not just a person reading it later. In this case because the meaning of x
, y
, width
and height
are different in relation to dst
vs src
making separate variables for each makes the code far clearer to read AND write.
Continuing...similarly it's often useful to be able to inspect values before a function is called, especially if it's a function in a library or the system that you can't step into. If you write code like this
ctx.lineTo(x + Math.cos(angle) * radius, y + Math.sin(angle) * radius);
vs this
var circleX = x + Math.cos(angle) * radius;
var circleY = y + Math.sin(angle) * radius;
ctx.lineTo(circleX, circleY);
In the second style you can now stop the debugger at the ctx.lineTo
line and inspect circleX
and circleY
. You might find they are NaN
which would probably get you to check that x
, angle
, and radius
are actually the correct names, something you wouldn't be able to do in the debugger. ("strict" mode probably catches that). It also allows you to easy log the values
console.log("cx: " + circleX = ", cy: " + circleY);
The point of this post is that more lines is often not only good for readability. It's also often good for writability and for debugging.