So, every so often, someone says something that sparks a… STORY TIME! And the ‘complex solution’ comment did. So here it is:
Back in the day, when I was in grade school and high school, I would regularly get beat on, hard. I wouldn’t fight back, couldn’t fight back, didn’t know how to fight back. Then I read Orson Scott Card’s Ender series, and realized - fight hard, fight dirty, and fight to win not just this fight, but all the ones that come after it. If I had to fight, it would be wise to completely crush and humiliate my aggressor, so that the rest of them would know better than to even start.
Still don’t like to fight, but there was a valuable lesson in that, that applies here.
End of story time…
So what’s the lesson, you may ask? When I write code, I try not to answer the question in front of me. I try to answer questions that I don’t even see coming, the ones that will pop up in six months or a year or so. I try to find the solution that will give me a better long-term bang for my buck.
The data
Object we defined? That’s pretty extensible. It is useful in many many places. Imagine a two-player game, for example, and that data
object being used to keep the score. We could then have a function that, when one user or the other does something that changes their score, updates the data
object with the new score. We could also have a few listeners to that score update:
- Update the scoreboard DOM node;
- Send the new score to a back end (firebase, or node, or whatever),
- Check if the new score is a win for either side
- … All sorts of things could happen
The strength of it is, none of the other parts need to know why or how the data object was updated, just that it happened, and triggered some callbacks. The data object doesn’t need to know about any other object, it simply runs the callbacks that have been fed to it, blindly.
I’m actually looking at this data object, and seeing it as a pretty powerful, extensible data store. I could see an interface to it going something like:
let gameDataStore = new DataStore();
// we could create properties dynamically, and create the getters and setters
// for them on the fly!
gameDataStore.watchedProperty('p1Score');
gameDataStore.watchedProperty('p2Score');
// Perhaps even allow for multiple properties to be defined at a single call?
gameDataStore.watchedProperty('p1Wins', 'p2Wins');
// We could attach listeners to specific watched properties, and attach to
// multiple properties in one call!
gameDataStore.watch('p1Score, p2Score', updateDOMScoreboard);
gameDataStore.watch('p1Score, p2Score', sendUpdatedScore);
gameDataStore.watch('p1Score, p2Score', checkForWin)
// checkForWin might update the watched p1Wins property, which would trigger the following
gameDataStore.watch('p1Wins', playFanfare)
// When we did this, it would use a setter similar to earlier implementations, with its own listeners.
gameDataStore.p1Score = gameDataStore.p1Score+1;
This is all just thinking out loud, a thought experiment, but I’m going to work on it for a little, simply because I see it as a powerful gadget.