4.20.2008

Can you pull that out? Thanks...

Abstracting code out to proper, generic, reusable containers is not something that the novice programmer excels at. Most often, code produced is highly specific, very static, and often, not to easy to modify and maintain over time. Early on, I devised a way to fix most of these issues, as I was writing the code. As time went on, I learned to identify the things that could be extracted out into generic containers early on, and avoided having to do multiple passes over my code to generate them.

"Where is this useful?" I've often found that data managers can, on the whole, be turned into generic functions. For example, a streaming terrain system could be abstracted to several generic containers : Generic Cache, LRU Cache, Streaming Class, Streamed Cache, Streamed Cache populator etc etc. These all could be rolled into one manager for the process, but then if you'd like to duplicate everything for streaming meshes, well, you'd almost have to re-write the entire damn thing!

In general, here's the process I hold to :

  1. Write the code as it functions and works in your head. Make sure you're including all the bells and whistles you need. As a general rule here, you want to make the interfaces as slim and generic as possible. Not just because you're planning on genericising it, but because that's just good programming. Note, this also includes allowing massive initialization parameters to be bunched up into classes so that if your function is overridden, the parameters can also be overriden to be expanded by other implementing classes.
  2. Do a quick check to see if any of the operating functionality of your class can be either replaced, or better represented with common generic containers. I'm not saying that your custom, slim, name-value hash paring isn't good, but if it can be replaced by an STL container, or another one that is used elsewhere in the code, you can bet it may be more reliable, and have more general functions. Yea, and as stupid as this sounds, you'd be amazed how many times you'll re-write basic functionality for a system that already exists in a generic form elsewhere. Don't laugh, you're guilty too!
  3. Take a look at your data and how your using it. Could there be any part of your data that could be considered abstracted? Can how you're using it be abstracted? In some cases, can your data be replaced by generic dynamic containers? (Ie can a statically allocated array be replaced by a statically templated array?)
  4. Create new containers that are 'above' your current class. Always approach your current class as the result of inheritance of several container classes; IE it's the leaf of the tree. Start with baby steps in this process. If you get hung up in an area that can't be genericied, then consider it as part of your leaf class, and not part of your generic container. Standard warnings apply about ensuring that your generic classes are memory safe, potentially thread safe, and well documented about it's differences and operations against other containers.
  5. Repeat these steps until you can get at least one generic container out of your data manager. If you can get more, even better.

Yea, it's a bit slower than you'd like, but atleast you're getting some good, reusable stuff out of it. And really, when I do code reviews, this is one of the things I look at, just how generic is your code, son?

~Main

1 comments:

Jonathan said...

hear hear!
that's cool how you have sensible steps to genericize the class- almost a 1,2,3.
i liked the mention of making init params into a class.
and the mention to make static c arrays generic containers.