In the meantime, I've got a random programming tip: Tell a story with your code.
When you're working on shared code I actually don't recommend this. But if you're working alone, you can waste a lot of time grappling with those chunks of code you don't touch for months at a time - you know, the buried artifacts from your own past that you dust off and hold it up to the light and wonder whether you wrote them while blackout drunk.
So when code starts getting gnarly, I try to figure out a way to make it about a character trying to accomplish a specific goal, and either succeeding or failing. It's a great memory aid.
One class I just revisited this morning is supposed to update chunks of voxels using some weird proximity rules. It's complicated and huge. When I initially created it I called it a NodeProximityUpdater, and when I cracked it open a few weeks later I felt like I'd had a stroke. So I created this base class:
public class InfectorScript : NodeScript
public virtual void TryToReawaken ( )
public virtual void GoDormant ( )
public virtual void SpreadTo (Node targetNode)
public virtual bool FindPotentialHost (out Node targetNode)
public virtual void AttemptToAlterHost ( )
public virtual bool IsNodeSucceptible (Node targetNode)
public virtual bool HasNodeSuccumbed (Node targetNode)
public virtual bool IsNodeInfected (Node targetNode)
public virtual void Die ( )
Flash forward another month - this time when I opened it up, I felt up to speed right away. Infector, okay - an infector infects things like a virus, altering hosts until they succumb to changes, then spreading to another potential host. When it can't find a host it goes dormant, then tries to reawaken once in a while. If it's without a host for too long, it dies. Got it.
All the gnarly complexity is still buried in there, but when you're reading the highlights of a story, you only need broad strokes to summon a complete memory, even if the particulars are complicated.