Mark Needham

Thoughts on Software Development

Coding: Good Citizens

with 4 comments

I was recently reading Brad Cross’ recent post about creating objects which are Good Citizens in code and he certainly nails one aspect of this with regards to ensuring that our objects are in a usable state post construction.

In OO design, an object is considered to be a good citizen if it is in a fully composed and usable state post-construction. This means that once the constructor exits, the class is ready to use – without the need to call additional setters or init() methods.

This is the main reason I find the C# object initializer syntax such a nightmare – it gets blatantly abused and you end up with half constructed objects all around the code base and you’re never sure where your next Null Object Exception is going to come from so you pepper the code with null checks to try and avoid them.

Apart from this though I think another important aspect of an object being a good citizen is that when it makes use of other objects it does so in the way that object would expect it to.

For example I wouldn’t expect object A to call object B and pass in null as one of its parameters. When we’re not on the edges of our bounded context then I think it’s reasonable for objects to trust each other and assume that they will call each other in a non-evil way.

In a brief discussion with Dave about this he suggested that we might have different expectations of what makes a good citizen depending on the context in which we are using them.

For example, in our production code a good citizen wouldn’t try to break encapsulation of another object by using reflection – it should tell the object what to do rather than taking data our of it.

In test code though it may be perfectly acceptable for us to make use of reflection to check the state of an object after we have performed an operation on it.

Dan North and Aslak Hellesoy have written up a more stringent list of what makes a good citizen on the Pico Container website – I agree with the majority of them although I’d question whether every object should have an equals method on it unless its’ actually used and I’m still undecided about whether objects should fail on construction if passed bad data.

Either way, it’s definitely good to consider these types of things when writing code.

Written by Mark Needham

March 4th, 2009 at 11:58 pm

Posted in Coding

Tagged with

  • http://www.lovethedot.net Paul

    I think this is a good argument for dependency injection, as it squarely places responsibility for an object’s dependencies on the class-developer, rather than the class-consumer. The consumer shouldn’t need to know what a class requires to do its work, unless it’s a design-requirement that the consumer supply it.

  • Jeremy Gray

    This is a minor point, but do note that they did not suggest that every object should have equals. They said that every object that has equals() should have hashcode() (though I can see how their phrasing might have thrown you off.)

    For that matter, .NET guidelines have something quite similar in that Equals, GetHashCode, != and == (and, in my opinion, IEquatable as well) should always go together.

  • Jeremy Gray

    As for fail-fast, embattled experiences across the fail-fast spectrum have left me quite convinced that while fail-fast is not a hard rule it is by far the best default position. Anything that isn’t failing fast is either leaving your system in an unknown state or doing creative things to recover (and such creative behaviour is generally more difficult to verify, as many negative test cases often are.) It is a better use of resources human and otherwise, and a much lower risk to both, to fail fast across the board and make exceptions only where and when proven necessary. It’ll spare you the time and resources to ensure that the exceptions are correctly handled.

  • http://www.markhneedham.com Mark Needham

    @Jeremy yeh you’re right I misread that having looked at it again. Definitely for equals and hashcode being implemented together – IDE tends to do it for you these days anyway :-)