In Part 1 of this post I gave you a damn good excuse to play facebook games in order to get acquainted with your Level-Up Cycle – a process of acquiring new skills where we move from awareness of a possible new behaviour, through the intention to implement that behaviour, spend some time gathering feedback in conscious practice, initially disruptive before becoming integrated, and then – the magic moment – we Level-Up and what was once the idea of a possible new behaviour is a habitual unconscious practice.
Great games – Tony Hawk Skateboarding is my favourite example – allow us to progress from novice to expert without ever really feeling like we’re ‘being skooled’. What can we emulate about how a good game stimulates learning, that we can put into practice as programmers?
Creating the (small enough) Stimulus
There are obvious macro stimuli – books, blogs, screencasts, conferences, but in many cases these are almost equivalent to a whole game. How can we create the kind of micro-stimulus that game designers use to tease out new skills that prepare us for the end-of-level boss?
I think the ideal stimulus is something tiny (and not progress blocking or bug-related because that encourages those tiger-awareness chemicals) that we can feed into the Level-Up Cycle repeatedly until we get a serious boost in our performance, or we conclude that this is not a fruitful new approach.
My current micro-stimulus is this kind of code:
So – just banal conditionals guarding against simple corner cases such
null. Sure, they work, and I’ve isolated those conditionals in helper functions, but I’ve gradually developed awareness that they can often be indicators that there’s a better way. And I’ve got an active intention to act on this situation – I don’t do it every time, but I try to make time to do it as part of regular refactoring.
So, I grabbed my first idea for a possible refactor – the
NullObject pattern – and dived into some conscious practice – very much disruptive at this stage!
The implementation here is that the player has to choose a set of options. Some options either enable or disable another option – hence these
disables values can be another option, or they can be
null. To avoid a Null Pointer Error, we don’t want to call the
enable function on
So – that’s ok, we can just create a safe
NullObject implementation of the
So I started to create my
NullBudgetGameOption, but I quickly hit a problem…
get selectedSignal and
get deselectedSignal return?
If they return
null, they risk being the cause of a difficult to diagnose Null Pointer Error – when someone tries to add a handler to the
I hate those pesky Null Pointer Errors. If something is going to throw-up in my application, I want it to puke something nice and specific so that I can instantly diagnose the problem. So my first thought was to make these getters throw a
NullObjectUseError that would make it straightforward to pick up.
I actually wrote all the code to implement this, but I could hear my complexity-dar pinging. It kept telling me that this broke the pattern. I’ve never come across this problem when using NullObjects before.
So I did the obvious thing – I asked the tweeks:
[@stray_and_ruby Jan 29 10:58am]
And because the twitter geeks are magic and generous, I got two near-instant replies:
[@DavidArno Jan 29 11:11am]
[@SlevinBE Jan 29 11:29am]
And of course they’re right. Totally right… so what does that mean? Does it mean that you can’t use a
NullObject to stand in for an
interface that has getters at all? Or only sometimes?
In the end it turns out that this is a classic case of interface overloading. I still feel that this is the weakest area of my programming – working out exactly what interfaces to build to, how to break them down, when to extend in the interface and when just to implement multiple interfaces.
The object returned by the
disables function only needs to be available to
disable. It doesn’t need to offer
Signals for selection, or even the
So we can refactor
disables getters on the
BudgetGameOptionVO to return a new simpler interface:
The original yukky conditionals can go, the
IBudgetGameOption can extend this
IDisableable interface, and the
NullObject no longer has error issues:
I also learned a truth (I think):
NullObject, it shouldn’t contain getters for complex classes unless they also deserve a
NullObjectimplementation (which is unlikely).
Now I have a new intention to ask this ‘could you be null?’ question of my classes and interfaces, and use it to try to make better decisions about how to split and compose those interfaces. One day maybe I will have forgotten how I acquired this knowledge, and it will just be ‘obvious’ to me, but I think I need a lot more conscious practice before that happens.
Achievement unlocked: interfaces level 2
I feel like I’m on my way and I definitely just raised my game on my understanding of the benefits of the ‘need to know’ interface.
I haven’t totally Levelled-Up on eliminating naughty conditionals yet, but some of my practice at removing conditionals has started to become habit – for example, using the Mario Mushroom Operator ||= for lazy instantiation inside my classes. And I’m getting enough warm and fuzzy feedback that I’m motivated to keep experimenting.
It’s an open-ended game
You probably noticed that I’m returning
Signal and not
ISignal in my getters – this is not good, though at least it meant I didn’t disappear down the path of creating
NullSignal to overcome it. The main reason for this is simply that the AS3 Signals interfaces have been in a state of flux over recent weeks and I’ve been caught out by the changes a couple of times, so using the concrete type has been more practical. Signals is still a 0.x release and the fact that the super-talented crew working on Signals have taken several shots to find the perfect interface configuration makes me feel a bit better about how tricky I find it.
Don’t forget to look backwards
Of course the really lovely thing about when we Level-Up is that often it happens without us noticing. By definition it’s a process of moving out of conscious behaviour, so it’s worth taking time every once in a while to see how far we’ve come. We can only do this by reflecting on where we’ve been – so I always take it as a good sign when the code I wrote months or years ago makes me cringe.