November 12, 2009

...Learn TDD with Codemanship

Our Goal Is To Minimise Coupling Between Classes. Not To Eliminate Getters And Setters.

As I'm sure Jesus and Marx would attest, publish and be damned.

There's always a danger when you make a point that's in any way nuanced or open to interpretation that the huddled masses will switch their brains off and choose not to think about what you've said, but to cut it down to a set of pithy, out-of-context, oversimplified truisms - often completely missing the point you were trying to make.

We're very guilty of that in software design. Why go to all the trouble of agonising about the many and complex design tradeoffs that need to be made to create high quality software when we can just learn a handful of soundbites which we can mindlessly apply regardless of the reality of the situation?

From the eponymous "GOTO considered harmful" to more recent design-isms like "singletons are bad" or "use dependency injection", there's no shortage of easy-to-learn rules and formulae we can follow that will exhonorate us from having to actually think about the code in front of us and what would be best for that.

Now I'm hearing a new design-ism: don't use getters and setters. I've watched discussions unfold on the Interwaste which display an alarming lack of insight or even a vague interest in why we shouldn't be using getters and setters.

And, let's be frank, just as with GOTO, singletons and dependency injection, it completely misses the point. Our goal is to minimise dependencies between classes and to maximise the internal cohesion of classes. We want to put the behaviour where the data is, and we want to avoid wherever possible sharing data between classes.

But, just like income tax, we can't avoid it altogether. If we can't share data between classes, then we'd have to put everything - data and behaviour - in one big class. You cannot have modularity and reuse without sharing something. So there's a trade-off that must be made.

The "tell, don't ask" school of design requires us to favour interactions between objects where A tells B to do X, and B has everything it needs to do X. As opposed to A asking B for all the data needed to do X, and then having A do it.

A simple example would be to have a Java servlet use getters on a Customer object to retrieve the customer's first name, last name and title (Mr, Mrs, Dr etc) and then concatenate them together to give the full name for display. Since Customer owns that data, such behaviour arguably belongs in Customer, not in the servlet.

But if the same servlet wants to format an HTML table containing the customer's first name, last name and title then that might be a different situation. I would argue that this is a clearly seperate responsibility relating to what the servlet knows about, and doesn't belong in the Customer class. So how does the servlet get hold of these bits of data without using getters?

Does it pass in a TableFormatter object with an InsertData() method that the Customer object can call with first name, last name and title? That seems like quite a wanky solution to me.

There are times when getters are needed. You may come up with some clever method names to try and disguise your getters. But they'll be in there somewhere. End of.

That we seek to minimise those occasions is important. But our goal here is not to eliminate getters, and it's vitally important that we remember that.

Posted 11 years, 2 months ago on November 12, 2009