I’ve been noticing that since I started doing the testing thing in anger my objects tend to be smaller and I have more of them. The pressure that testing puts on you to design in such a way that each object can be used as independently as possible so that you can write tests seems to break chunks of functionality far better than other design methods I’ve tried. As I’ve said before, the problem then becomes one of managing the obvious complexity; looking at this kind of code for the first time can be a little daunting.
In the past I’d start out with good intentions but my objects always ended up doing too much. I’d end up with several fat objects that plugged together via large chunky interfaces. When you looked at the code for the first time you’d see some fairly obvious and fairly big concepts connected together. Take The Server Framework code for example; the older releases had a single large class called CSocketServer that managed the connections, async IO threads, buffer pooling, socket pooling, etc, etc, etc. I eventually decided that this was crap, and refactored my way to a collection of smaller objects. These smaller objects are easier to test, easier to understand and easier to reuse; win, win, win. Of course there’s a downside with lots of small objects; you have to connect them all together at some point.
I’ve said it before, but, well, I’ll say it again, I prefer my complexity to be on show. I’d rather have to write an object that simply wires together a handful of smaller objects than find that my lumpy objects are hard to test and almost impossible to reuse. I’d rather give an object an interface to a service provider than have that object ‘know’ where to go and grab the service provider from; singleton’s are fine, but you shouldn’t know or care that they’re a singleton, you should just get passed an object and deal with it; none of this
COneTrueWay &obj = COneTrueWay::GetTheOneTrueWay() malarky.
Given all these objects need to be composable into something more useful and given that they’re upfront about their complexity I find that they seem to resemble Lego, in a funny kind of way. Every object has an interface, the lumps and holes that allow you to plug the objects together. When you get near the ’top’ of your creation you sometimes want to hide these connections, so you find yourself using special pieces that don’t have the usual lumps on, they just connect to the structure below, make sure everything holds together and smooth it all out so it looks nice… Ok, I’ll stop ;)
My recent projects have all shared this composable complexity theme. I like it and I don’t feel daunted by those first impressions of complexity, but then I know that once you accept the initial complexity you’ll start to find that as you dig deeper things become simpler. Individually they’re pretty simple things, it’s just when you see the ’top’ and see them all staring at you from one interconnected whole that it seems messy. I’ve yet to work out a way to help others get up to speed; often people take a look and decide that they don’t want to spend time thinking about what’s going on. I think good documentation helps; high level, overview stuff rather than blow by blow source file commenting. But sometimes clients dont want to pay for that. It’s a tough one. I think, perhaps, that it’s just that I skip a layer sometimes; if you have ten objects that you need to wire together then it’s best to do it in chunks of functionality rather than all at once… More thought needed.