On the Taxenomy of Ducks:
Using Object Inrospection and Reflection to Manage Systems Integrity
When I was 12, my brother and sister and I spent a week in Seatle, visiting my grandparents during winter breaker. On the Tuesday of our visit, my grandmother had her bridge club over, and my grandfather was out taking care of some holiday shopping, so my siblings and I were left to entertain ourselves for a few hours. It was was raining outside, so my sister decided she would read a book. My brother wanted to play a game (I was hoping we would play chess). So, he went to grandmothers game closet, and pulled out a box, handed it to me and asked me to set it up, so we could play a game. The box was labelled Chess, and had pictures of a chess board and chess pieces on the outside, so I was excited to play a game of chess. I opened up the box, and began to set up the board pieces, and I found that a few pawns were missing. I could have just told my brother we could not play, as there were pieces missing. I could have gone and interrupted grandmother’s bridge game, to ask her if she knew where the missing pieces were. But I found some dice laying on the table, so I substituted the dice for the missing pawns, so we could play a game, and asked my brother “Okay, white or black?”
The roles and responsibilities and expectations of objects in software systems are subject to the requirements, methods and organization of the system architect, and the engineering team lead. How objects handle their input objects is an age old problem, and with the introduction of distributed systems, the shapes and sizes of input objects can suffer from their own contraints. An object needs to have a way of behaving when it is handed an object for processing, and the first thing it needs to do is inspect the input. If the input is not what it requires, then it needs to either handle that somehow, or throw an error. Or maybe he doesn’t want to deal with it at all and “fixes” it by making the error message go away….
//do nothing - let someone else deal with it.
This principle of software development has become topical because of the fairly recent adoption of a practice dubbed “Duck Typing” by some, popular in ColdFusion and Ruby development circles. So, what is “Duck Typing” and why does it raise discussion around object behavior?
In software languages like C++ and Java, objects are classified by types, which define specifically what properties they have, and what methods are available. When the C++ or Java code is compiled, the compiler checks to ensure that the inputs to object methods are of the expected types, and if not, a compiler error is thrown. In interpreted systems, like Ruby, or JIT compiled systems like ColdFusion, the types are checked at runtime JIT compile time. If the objects are strongly typed, an error is thrown. This is much like my brother handing me the box from the game closet. If the box was not labelled Chess, I could have objected and handed it back to my brother.
The practice of “Duck Typing” is to abandon this practice, and let the called object deal with whatever object it is handed. I have heard it told to me that "If it looks like a Duck, and it Quacks like a Duck, then it is probably a Duck" So, in other words, if it is the object has a radius parameter, then it is probably a circle. In practical terms, this is a shift of responsibilities from the caller, software environment or compiler, to the called object. The objection to “Duck Typing” is that often this means a shift of responsibility to quality control, the bug tracking team, customer service and the project manager who is left explaining why their enterprise web system is crashing, and the development team is having difficulty tracking the bugs. What has not been clarified in some team development environments, is that there has been a shift in responsibility. Someone has to pick up the slack. It is left to the called object to be more diligent in checking it’s input, and more flexible in how it handles the input. Like, when I discovered there were pieces missing from the chess set, and I made a couple of pawns out of dice, the team needs to be clear on what the object has the authority to do, to perform its function.
Communication needs to be of the highest order in cases like this, where repsonsibility is shifted to the worker classes. Once it is clear what the developers are being handed, t
here are a few strategies which need to be embraced when the protective tools of compile and runtime type checking are no longer there, because in the end, the software needs to work. There is ad hoc internal type checking, which can be set up with a simple tag, or an extra parameter on an object, which signifies the class. There is an inventory process which an object can run on acceptance or rejection of a call. The inventory is a matter of running through an object’s properties, like a checklist, to see if this is here, if that is there, etc., to make sure its properties match to what is expected. The reflection API can accomodate this, as well. If you are using Duck typing in a project, make sure to build type variance into your unit tests. Better that the unit tests blow up than your codeline… or the customer. What is the reason for this interest in a methodology? Where’d the Ducks come from? Well, when the girls start screaming, look for the rock star. Quiz Time: Is it David Hasselhoff or David Heinemeier Hannson? Well, the DRY principal employeed in Ruby on Rails, says that the interface (required behavior) leads to repetition. (DRY = Don’t repeat yourself… so repeating, bad). Dave Thomas and Andy Hunt (Pragmatic Programmers) These guys are incredible. They advocate pushing Ruby on your business, with the tactics of Scientologists on a three day weekend. Well, that was then. Now, they are pushing Erlang (saying it’s today’s Ruby). Give me a break.
There is some merit, however, in the argument that the behavior of an object should in some cases define what it was, and so, having a type would be redundant. And, given suffiently compelling context, I’d give it a whirl. However, the situations a contractor is placed in are often a little less predictable than the cozy intellectual Oasis of Object Orient land. There is a large installed base of non OO scripting methodologies, and relational databases, which aren’t going to step aside and make way for new practices. Same goes for the installed base of employees.
So, while not denouncing the practice of Duck Typing completely, I would question the argument for its adoption simply on the basis that it has one aspect of DRY, so it will lead to some future benefit. In every single case, where a change is made, I have to ask myself How much is this going to cost? and What business benefit are we going to derive? You *cannot* simply remove a solution from its context, and then advise for it. If you remove it so far as to remove it from the problem, then the solution looks for a problem, any problem, to take its place.
Sean Corfield expressed concern that people seemed to miss the point of his talk, when they talked only of the performance boost of using Duck Typing. Removed from even a contrived context, how would anyone think any differently? You can lead a duck to water but you can’t make him…. (okay, a metaphor mix in was called for)
As a quick disclaimer, I should say that I am passionate about patterns, enthusiastic about object oriented methodologies and applications which can really drive efficiency and creativity. While this is so, I witness many people who simply do not understand the underlying pricipals, but think they do. It’s okay to not understand. The concepts are not at all down to earth… they are abstract. But for the people who think they understand the principals and try to drive an implementation with complete disregard to tried and true principals and practices of Unit testing, communication, and so on, … and without any support from a return on investment standpoint, let me say, these people are dangerous to software projects.
I will continue this (rant?) and tell how the chess game turned out in a later post (continued….)