Over this weekend there was a sensei in my presence. Even more interesting was that he watched from the shadows without my knowledge. A full night into developing a major component of Project OGUR and he sprang to begin a battle that I didn’t want to fight.
A challenge was being held. SimplePathXna never had support for text display, but it was always planned as an addition to the (soon to be) library. Project OGUR finally reached the point of development where I needed to show some fonts, so I did what I’ve done with everything else thus far. And that was my fatal mistake.
SimplePathXna makes use of both a handful of singletons and a number of classes which are effectively useless without their publicly available static methods. As soon as text wanted to join in on the fun, I wrote a TextManager class. Just like there existed a GameplayObjectManager class, an XnaManager class, etc etc.
But something was different about adding this Manager. As if a weighty gaze was keeping my normally dexterous hands from doing the deed. It was here that the teacher came for my lesson. It was time to truly understand the reasons why my usages of the static keyword throughout my implementation of Text wrappers was a terrible, crippling design.
A crux of the mechanics within Project OGUR is local multiplayer with up to four gamers on one screen, with live drop-in and drop-out. While trying to manage text from a single location seemed like a great idea, it was really a lazy solution to a complex problem.
Text was needed not only for each player, but also for numerous properties about each player. By making the TextManager a chunky singleton, each player’s HUD was stored in the same location. This made managing a single player nearly impossible without stomping on the data of another player.
An entire day of programming was not lost however. One of the principles I’ve learned from Beautiful Code is that bad, procedurally focused code can be transformed. Key applications of OOD will turn a pile of wet sawdust into a mighty oak, ready to grow new branches and withstand the changes of time.
This experience with multiplayer is the first concrete example I’ve experienced where throwing tons of logic into “Manager” classes failed miserably. On the other hand, refactoring that barely functioning code was a great mental exercise, and much of my labor was able to stay. Without too much referencing Fowler’s great book on refactoring, the deed was done. An hours and a half led to a much more OO friendly design that provided any given player with its own TextHandler object, wherein the existence of a player meant the TextHandler existed, so many many technical hurdles were lessened.
More explicitly, the issue was that keeping everyone’s data in a singleton meant that the HUD of every player was flushed when any one player changed their display, resulting in a lot of overhead processing. By splitting management into a more cohesive handler that each object could contain as a member, the difficulty in tracking various properties within the management class went away without much hassle.
Above all the programming experience was the way in which stepping back from the raw code enlightened the entire design process. Drawing out the basic flow of data between different classes, and redrawing a handful of times, on a white board lead to a very fluid workflow where each class had a minimal amount of responsibility. It wasn’t a legitimate UML diagram, just enough detail to help me visualize what needed to be changed.
There are still going to be some singleton’s in the first full release of the SimplePathXna library (which won’t be until Project OGUR is finished as a project to use as a library’s proof of concept). For example, TextManager still exists. However, the first iteration of the class handled multiple operations. It allowed any logic to add text to be shown on the screen at any location using any font. It could also get a static resource that cached the Font information. That second piece, the caching, will still be the core purpose of retaining the TextManager class. TextHandler steals the other functionality as a means of scoping the text data. When a player issues a command, that command can trickle down through some object logic and manipulate the state of that command’s related text in a place where no damage can be done to other players.
I think a good rule of thumb to come out of this is that for most logic, anything that is more than a simple accessor should not a statically available resource. By that I mean something which should be singly available to any other given piece of logic. Say, the sprite used by an object to represent itself. Why duplicate that memory heavy piece of information more than once if it can be avoided?
This is certainly not anything new to the world of OO, but I like documenting the exact way in which the principle of singleton’s not being the silver bullet became clear to me. Perhaps it will help someone else understand the great disasters singletons will cause when misused.