Ahem... In business enterprise software. I will put forward the case that 95% of the time there is an alternative to a design involving abstract classes that will leave you with DRY, well-tested code and without the inherent risk that comes with inheritance. (That risk being a big jumbled spider web of parent-classes and subclasses that inevitable happens after x number of developers touch it.)

Back when I learned how to do OO in large codes bases.... Oh those 6 long years ago... I worked in London and was influenced by a few very awesome developers. We were doing C# and I remember this team where the leaders said 'No abstract classes.' And the code was beautiful. It might be said that we all just really cared. But, I have worked on very few teams where the majority of coders didn't care. We always care and strive for beautiful code. Anyway, today I find myself back in the US and working in the Java world, doing android development. And I find abstract class use everywhere. Everyone embracing it. And honestly, I see it lead to a tangled mess 95% of the time.

I see the appeal. You reduce duplication. If you were to use an interface instead of an abstract class, you would have several classes implementing the same interface but what about the common functionality. That's what an abstract class gets you. You can pop the common stuff in the abstract base class.

I rarely see a problematic situation at the time of initialing setting this up. It's normally beautiful. You say 'Yeah! Look at that beautiful inheritance. This is great. No duplication.' DRY, right?

The problem comes when you have to come along later and add a little functionality here or there. Often additional layers get added into the hierarchy and you sprinkle the common functionality where they belong. So maybe you started with 1 abstract class and 4 classes extending. You come along a month or 2 later and there's 1 base abstract class, two other abstract classes extending this and a slew of concrete classes extending any of these 3 abstract classes.

If this doesn't sound scary, maybe it's never happened to you. Let me just overview the pain I feel when working with this sort of thing is.

1. It's nightmare for a developer who's unfamiliar with the codebase. Who's overriding what? Who's implementing what? Who's responsibility is what?
2. It's hard to unit test. Who do you test? Really, you have to test all the concrete classes completely. This includes the functionality they implement themselves and the functionality they get from any of their parents. You could say.. well, write unit tests for the parents and then don't retest in the subclasses. The issue here is that you can't test that the subclass is specifically using the functionality from the parent through interaction based testing (mocking and stubbing). To be sure it's using the right code, you have to unit test the specific functionality for that code.. wherever it is. So, you either have duplicate tests or incomplete test coverage.
3. It's often highly brittle to change. This is because it's inevitable under tested and often not completed understood by those augmenting functionality.

I can't say that inheritance is never right. In fact it often feels right. And if you're working in a small team where you can discuss design frequently catch these things turning into issues... maybe it's worthwhile embracing it more. My feeling is that if you aren't working on a small team.. and/or you have even a minimal level of turnover among you're developers. This problem will almost certainly rear it's head.

What is the answer?? Let's turn back to the things taught by the gang of 4 and that super genius, Martin Fowler.  There must be some wisdom there! I'll dive into this next. I just want to reread a few chapters and articles first.


Swift - Child of the LLVM

Exploring what Swift achieves on LLVM that Obj-C could not. Continue reading

Understanding The LLVM - Introduction

Published on June 18, 2017

Developing for Hardware & Visibility

Published on May 24, 2017