Hi Jeff,
I find your arguments well considered and cogent. Let me play devil’s avocate.
I’m not sure I can abide your assumption Jeff. In my mainframe world, programs required change for one of two reasons: (1)the business requirements changed and (2) the program(s) contained bugs and needed to be repaired. The latter was the more common.
If you have several related classes – “abc”, “efg”, and “hij” – that all need to be changed in the same way, and all inherit from parent “xyz”, then you can make the change in just one place to affect them all at once.
Again, in my mainframe world, I was able to achieve such encapsulation through invoking “paragraphs” in my code. If I needed the same activity in another program, I could (and did) package that code into a “subroutine” to be “linked” at compile time – which meant I only required the change in “just one place” (IF the program was written by a capable programmer).
Though, as you noted, when there are layers of inheritance, you may need to trace the inheritance chain to find the appropriate place to make the change.
But suppose that the appropriate place to make the change is in a higher inheritance change from where the “bug” manifests? Is it not likely that other modules inherit from this higher level (else why would it exist)? Finding the higher level is not too big a problem, but how do I assure that I’ve found all its children? If I miss one, I may correct a minor problem only to create a larger one in another part of the application?
And the functionality for any given class may feel less centralized; the functions aren’t in just one place. And that’s true. OOP encourages us to identify and separate code that is common to two or more data structures. So it’s less centralized, sure, but also more flexible and eases reuse.
Is this not a development focus? For maintenance, I have to track down all the places it’s reused before I make a change.
Interfaces especially, I believe, aid maintenance… Let’s say, hypothetically, you have some classes that implement search indexing and lookup, but now you want to change to a different search library. Seems like that would be painful. Any place where you application uses search will need to be updated. But if both libraries implemented the same interface, then the rest of your application can continue using the same method calls it always has. Interfaces make it easier to seamlessly swap one component for another, because those components have agreed to a common API.
I understand “both libraries implemented the same interface” is the idea to facilitate maintenance. Yet, how often is this likely to happen – where the children operate precisely the same way when their parent changes?
Again, I’m playing devil’s advocate from a straight maintenance viewpoint.
grNadpa