Refactoring
As you tinker with a sketch you’ll find yourself building up lines of code, variables and functions. The risk is your understanding of the code collapses when you’re no longer sure what does what (or why).
DRY
Don’t Repeat Yourself (DRY) is a principle where you try to avoid writing code that does the same thing, or pretty much the same thing. If you ever find yourself copy and pasting code, duplicating it in a sketch, it’s a sign you might be breaking the DRY principle.
Two common ways of repeating yourself are:
- ‘Magic numbers’ sprinkled through your code. Numbers used for tuning this and that, but you’re re-using the same number in different places.
- Lines of code that perform an action or do a computation which are repeated because you want them to apply in several different places or on different inputs
Keep in mind that DRY is not just an ideal to strive for. It can make the task of understanding your sketch and iterating it further difficult — especially if you’re a beginning. So when you start losing track yourself, consider ‘editing’ your code and looking for opportunities to DRY.
A simple case
Maybe you’re computing a colour value based on a scalar (ie. 0..1 number) and we want it restricted to a narrower part of the hue range. In our case, the range is 30-60 degrees.
An input of 0 should give a colour of hsl(30, 50%, 40%)
, through to an input of 1 which should yield hsl(60, 50%, 40%)
.
If you’re repeating this snippet in different places of your code, it will be painful if you change your mind of the hue range, or that all colours should have 50% lightness instead of 40%.
Consider too if you now want to do something almost the same but for a different element. Now you’ve got two sets of almost identical code to maintain:
The first strategy is to parameterise the range:
Now we have the benefit of variables, which, when well-named, can improve code readability, especially the math on line 5.
The next step, assuming the values are constant throughout the sketch would be to put them in settings:
Now we have one place, settings
, to make tweaks to the overall behaviour of the sketch, rather than ‘magic numbers’ sprinkled - or even repeated - throughout the code. use()
pulls in those values from settings and even if lines 8-10 were repeated, we still had the benefit of central settings.
The next step is to refactor it into a function. Maybe you realise all the code cares about is the input scalar and an output colour string.
Assuming you were doing this in several places in your code, now you can delete this and have one place for it. Give generateColour()
a number 0..1, and it gives you back a colour string, ready for use:
Another benefit we gain with generateColour()
is it becomes a central place for doing checks or processing of a value before it gets converted to a hue. For example, maybe we want to ensure the input is clamped to the 0..1 scale:
There’s many other ways this function could be.
If you wanted saturation and lightness to be dynamic, these too could be parameters for the function. Or perhaps every time you generated a colour you were also assigning it to the background colour of an element. Maybe it would make sense to include that functionality:
Now it’s also trivial to set the background colour for more elements using different relative values:
If, however, sometimes you set the colour to the background and sometimes used it in a different way, maybe a better strategy is to make a composition of functions, each with narrower duties.
That way we can call generateColour()
when we just want a colour string, or call setBackground()
when we want to assign a colour based on a scalar. Because setBackground()
uses generateColour()
, we maintain the benefits of DRY. You can also see that setBackground()
becomes very readable since generateColour()
has an obvious name.
Hopefully the refactored versions we ended up with are more readable than the version we started out with. There’s not even a need to add comments, because the function names and variables do the talking. This not the case if we go back to the original, sans comments:
…at the very least the refactored versions will be more useful, reliable and easier to extend.
This is all to say there are many different ways of slicing up a problem, and what is correct in a given case will really depend on what the needs are of the sketch. Don’t make functions just for the sake of it, but as soon as you find yourself repeating things, ask whether it would be better to make a function.