My favourite bugbear. Appropriate delegation / compartmentalisation / structure in OO software. There are some excellent books concerning design patterns and anti-patterns. The general rule of thumb is: stuff in a class deals with that class, and delegates to neighbours as appropriate. So:
- The code that formats the message, is not
- The code that retrieves the data that the message needs, which is not
- The code that trawls through some structure looking for a target which might know how to deal with the message.
For those that don’t have time to read through the official textbooks, my rules of thumb:
Do one thing and one thing only in a function, examples:
- Formatting a message.
- Updating internal state on the basis of a message.
- Delegating things elsewhere.
- Performing some algorithmic calculation.
- Converting from one format to another.
OO software works well on the basis of ignorance. Yes, it’s important that the code does stuff, but really good OO code works well when each bit of code knows only about a relatively limited subset of its own class, ancestor classes, and a minimal subset of stuff around it. Code should be as ignorant as possible. i.e. Keep your design contracts simple.
That means good OO software should be generic. Yes, some bits of code have to know the knitty-gritty of how some algorithm works, or how some data is structured, but in general, if your code does not know how to do X, and X is not locally or closely related to your class, then just delegate it elsewhere.
Joel-esque rant over.