It’s been a little over two weeks since I started playing around with Erlang (see for details of my earlier endeavours) and I feel I’m starting to span the “conscious incompetence” and “conscious competence” levels of mastery over the language to the point where I need to reflect again.
I’m about three major versions deep into the toy application I’ve been noodling around with and it’s evolution has broadly been:
- Make it work using the easiest possible means
- Refactor to make the patterns more idiomatic, making use of the natural benefits of the language
- Return to Step #2
Note: it’s important to progress beyond Step #1 when learning a new language (especially when a new programming paradigm is involved as well) because otherwise you end up writing “Java with Ruby syntax” or “Erlang with Python syntax”, or some other equally abhorrent hybrid.
In my case, the biggest challenge was to let go of 16 years of OO training.
The most recent big Step #2 refactor was to remove all explicit conditionals in the codebase (i.e., case and if statements) and substitute them for either guard clauses of function pattern matches to see how that felt…
It felt a little weird.
One specific example was to refactor a case statement which was checking points of the compass (which will be a dead giveaway to any of my fellow ThoughtWorkers to what problem I was trying to solve). The Step #1 version of this code looked something like:
to_atom(Orientation) -> case Orientation of "S" -> south; "N" -> north; "E" -> east; "W" -> west end.
Which was refactored to:
to_atom(Orientation) when Orientation == "S" -> south; to_atom(Orientation) when Orientation == "N" -> north; to_atom(Orientation) when Orientation == "E" -> east; to_atom(Orientation) when Orientation == "W" -> west.
Now my general thoughts on code in general is that less is better, so I strive to write less code as much as possible, hopefully stopping short of the absurd. Based on this general theory, I’ve gone from 7 lines in the first version to 4 lines in the second, but although my brain is telling me this is an improvement, my eyes are fighting against this style for a couple of reasons:
- By convention, Erlang prefers to have no blank lines between the four clauses of this function in the second example. This makes the code much denser on the screen and I find it a little harder to visually parse as a result, specifically…
- The key information to pick out of this code is the actual compass values (N, S, E, W). In the first example, they occur immediately after the leading whitespace on the left hand side of the screen. In the second example, they are some 40 characters in from the left margin and much harder to identify visually.
- Although I’ve reduced the lines of code, the actual number of characters has increased significantly, as has the amount of duplicated code.
I expect my eyes will get used to this style of code over time and more quickly ignore the boilerplate to the left of these function clauses, but for now it’s making this code much harder to comprehend.
p.s I considered using a hash lookup to do the mapping shown here, but I like the clarity of this approach better. For a larger number of values, I think the lookup approach would be preferable.