Writing Better Go: Code or Data?
A Journey...
I've been on a bit of an odyssey trying out various languages in case there is something out there that might suit me better than Go. After considering many others - and actually trying out C#, F#, and Kotlin - my feeling is that I will not be abandoning Go in the short-to-medium term (although I may well delve deeper into Kotlin).However, as with many journeys, much of the benefit comes from the travelling itself rather than achieving a destination. For the purposes of this exercise I ported a little utility of mine which unpacks a legacy file storage format to each of the aforementioned languages and tried hard to write idiomatically in each one. Doing this inevitably leads one to question the structure of the original code and also any ingrained habits that might have passed their use-by date.
...and An Outcome
If I am sticking with Go, I really ought to think about trying to write 'better' Go.A Case in Point
One of my pet peeves about Go is its lack of enumerated types. As I was researching idiomatic enum-like patterns in the three candidate languages I came across several opinions that over-use of enums was a 'bad smell' in code. Some of the people who hold this opinion this seem to me to be worth listening to so, even though I could find very little by way of justification for this assertion, I thought maybe it was time to reconsider some old habits.Old Dogs
[Cue the violins, you can skip this bit]At school we accessed the county mainframe via a teletype, in my first year of Comp.Sci. at university we used punched cards, only in the second year did we get access to VDUs and personal computers. We thought about memory in terms of kilobytes (or even kilowords) and processing speed in terms of Dhrystones, Whetstones and Transactions Per Second. Whilst we were aware of the dire consequences of premature optimisation, we regarded them as primarily a warning against excessively 'tricksy' code that would be hard to read and maintain. We naturally wrote code that was conservative in its use of run-time resources (but not at the expense of readability). I still do.
Old Tricks
For years I have used constants and enums wherever practical to try to make my code safer and to help compilers produce efficient code. By and large this has worked well for me.Here is a some of the code I had before starting this project:
It's a very familiar pattern; basically, a list of
consts
followed by a big switch
statement to handle each case as defined by the consts
. This pattern is highly prevalent in C systems programming code and APIs - a lot of my Go coding involves using or porting such software.(Not so) New Tricks
Here is a new version of the code:I would contend that this is both shorter and better code.
What Have I done?
Nothing clever, it's not rocket science. In a nutshell I have replaced an abstract list ofconsts
with a meaningful map
describing each entry type and its attributes, then used that map
to conflate the switch
statement to a simple if... else...
dealing with known and unknown cases explicitly.A lot of the case-handling has moved from procedural code into the data itself.
Why Is It Better?
Do you need to ask? The logic is so much clearer and adding new types (which will happen) now means adding a single line of code/data for each type, rather than at least three for the old approach.Also, there is a kind of 'completeness' about the handling now that Go cannot provide with switches and constants. (Some other languages can provide this kind of assurance with rich enumerated types and switches.)
Any Downsides?
The main question in my mind was performance (see above); I remember when associative arrays (i.e. maps) came with quite a performance penalty. Fortunately, others have already investigatedswitch
vs. map
behaviour in Go, and it turns out that there is a small penalty in trivial cases, but the map
approach actually wins (and is almost constant) for randomly accessed maps
over a certain size. See Jack Christensen's write-up for more details, but note that the Go compiler has improved since then and the break-even point has improved somewhat.
Comments
Post a Comment