Handled correctly, loose typing can be a powerful thing , but with great power comes great responsibility. The license to enjoy the benefits of dynamic typing comes with the responsibility to actually design with real objects. If one just strings together collections of simple types, weaker typing can lead to some very confusing code.
I was reminded of this today in an improbable way. I uplifted some old, unfamiliar code to a modern Java version, which included adding in generics: taking untyped collections toward strongly-typed ones. This meant grokking and stepping through the code to infer data types where nested collections were used, and it smoked out what the design really looked like. One commonly-used structure came to this, and there were several others like it:
HashMap<String, HashMap<String, HashMap<String, HashMap<String, HashMap<String, Vector<String>>>>>>
Wow. I wish I was joking.
This just screams, “make objects!” It reminded me of perhaps why the “everything in triplicate” crowd fears dynamic typing. If you aren’t designing with objects, then strong typing partly saves you from yourself. In this case, the addition of crazy nested generics actually made the subsequent code easier to understand and less error-prone.
But a much better approach, of course, is to create new classes to handle what these nested collections do, with the added benefit of factored behavior. In this case, the real objects exist very plainly in the problem domain; just follow the nouns. A truly object-oriented design usually doesn’t need strong typing to clarify the design.
This does require diligence and I’ve often been guilty of missing objects, too. Yet perhaps this example reveals a new code quality metric: if you need more than two adjacent angle brackets to make the “raw type” compiler warnings go away, it’s time to step back and look for objects.