I guess I'm really just writing this for me.
In one of my current projects, I have a case where two contributors on separate occasions have moved a class from one module to another (to increase reuse). In each case I provided an explanation of why it was in its original location and requested that it be put back there again. (I'm considering sticking a remark on the class to prevent further tampering...)
The explanation is a little long-winded. Essentially it boils down to the fact that any apparent reusable potential of this particular class is illusory. It declares the command-line options accepted by a tool along with help text and whatnot. This is true despite the fact that several tools may offer similar options. The problem is that the options aren't really identical. The actual parsing code has been factored out to a common utility class and is reused.
Thinking...
Anyways, this got me thinking. How could two very smart guys independently make the same mistake. I think it has to do with modular design considerations that aren't always so obvious.
When new modules are created, it always happens that some things must reside inside the module and others must reside outside. So module boundaries do constrain reuse and for good reason: it's to protect the encapsulation. Opportunity for sharing the insides of modules should be viewed with suspicion until proven worthwhile lest they introduce undesirable coupling. Perhaps more subtle is the case where the sharing opportunity exists only because of accidentally and rather arbitrary circumstances. Watch out for those.
It's worth keeping in mind that redundancy in the small scale is often not very relevant to the overall architecture. Outright duplication can exist across and within modules due to such diverse reasons as: isolated development groups, greatly varying rate of change or maturity of modules, historical carry-overs, inefficient cross-team communication, licensing constraints, conformance requirements, political tension, inexperience, carelessness.
Respecting my promise...
I had prepared a longer diatribe on this topic entitled DRY is not DAMP (Don't Repeat Yourself is not Disregard All Modular design Principles). But I remember my promise to try not to be antagonistic...
Just the same, I'd like to point out one pet peeve of mine that recurs frequently in UI toolkits. It's common for the Check Box and Radio Button controls to be represented by classes derived from a common ancestor like CheckBoxOrRadioButton. After all, both controls essentially consist of a toggle-button and a label. Right?
No, wrong. I believe the sharing in this case is illusory.
At best, I believe the shared implementation concerns should be captured by delegation rather than inheritance so they don't clutter up the API. After all, Check Boxes and Radio Buttons have widely varying semantics. The controls are not really substitutable anyways. This is part of why I feel the common strategy of using inheritance to express composition of UI components is generally misguided. (Or maybe I just like SWT more than WinForms.)
Interfaces should not leak implementation details to the surface simply by virtue of having exploited some opportunity to reuse a little code. Each module should be considered a cohesive unit with a clear relationship to the whole and unburdened by inherited concerns that are of no relevance to its users.
In fact, sometimes there are very good reasons for skipping over an apparent opportunity to reuse code because it would do more harm than good.
No comments:
Post a Comment