I watched a bunch of lectures on Clojure and functional programming by Rich Hickey as well as some of the SICP lectures, and I am sold on many concepts of functional programming. I incorporated some of them into my C# code at a previous job, and luckily it was easy to write C# code in a more functional style.
At my new job we use Python and multiple inheritance is all the rage. My co-workers are very smart but they have to produce code fast given the nature of the company. I am learning both the tools and the codebase, but the architecture itself slows me down as well. I have not written the existing class hierarchy (neither would I be able to remember everything about it), and so, when I started adding a fairly small feature, I realized that I had to read a lot of code in the process. At the surface the code is neatly organized and split into small functions/methods and not copy-paste-repetitive, but the flip side of being not repetitive is that there is some magic functionality hidden somewhere in the hierarchy chain that magically glues things together and does work on my behalf, but it is very hard to find and follow. I had to fire up a profiler and run it through several examples and plot the execution graph as well as step through a debugger a few times, search the code for some substring and just read pages at the time. I am pretty sure that once I am done, my resulting code will be short and neatly organized, and yet not very readable.
What I write feels declarative, as if I was writing an XML file that drives some other magic engine, except that there is no clear documentation on what the XML should look like and what the engine does except for the existing examples that I can read as well as the source code for the ‘engine’.
There has got to be a better way. IMO using composition over inheritance can help quite a bit. That way the computation will be linear rather than jumping all over the hierarchy tree. Whenever the functionality does not quite fit into an inheritance model, it will need to be mangled to fit in, or the entire inheritance hierarchy will need to be refactored/rebalanced, sort of like an unbalanced binary tree needs reshuffling from time to time in order to improve the average seek time.
As I mentioned before, my co-workers are very smart; they just have been doing things a certain way and probably have an ability to hold a lot of unrelated crap in their head at once.
I want to convince them to give composition and functional as opposed to OOP approach a try. To do that, I need to find some very good material. I do not think that a SCIP lecture or one by Rich Hickey will do – I am afraid it will be flagged down as too academic. Then, simple examples of Dog and Frog and AddressBook classes do not really connivence one way or the other – they show how inheritance can be converted to composition but not why it is truly and objectively better.
What I am looking for is some real-world example of code that has been written with a lot of inheritance, then hit a wall and re-written in a different style that uses composition. Perhaps there is a blog or a chapter. I am looking for something that can summarize and illustrate the sort of pain that I am going through.
I already have been throwing the phrase “composition over inheritance” around, but it was not received as enthusiastically as I had hoped. I do not want to be perceived as a new guy who likes to complain and bash existing code while looking for a perfect approach while not contributing fast enough. At the same time, my gut is convinced that inheritance is often the instrument of evil and I want to show a better way in a near future.
Have you stumbled upon any great resources that can help me?
7
It’s not a duality; the question is not “should I use composition or inheritance”, but “at which points in my object graph do I want to have inheritance hierarchies”.
As far as examples go, I like to come up with car metaphors, so here goes.
Suppose you have an abstract base class Vehicle
, and two classes that implement it: Car
and Truck
. They have a bunch of methods, e.g. get_num_wheels()
and get_fuel_type()
, get_num_seats()
, etc. All is fine, but now you need to further split up the Truck
class, because you have to support two-axle trucks (with four wheels) and three-axle trucks (six wheels). You also have to support cars that run on diesel as well as cars that run on gasoline. So now you have TwoAxleTruck
, ThreeAxleTruck
, DieselCar
and GasolineCar
. Oh, but now your passenger car comes in a pickup version with just two seats – two more classes, because that car can also be diesel or gasoline powered. And now the customer wants you to track the kind of cargo your vehicles can support; there’s eight different classes of cargo, and all types of trucks and pickups should be able to support it. Is anyone counting? And we have another problem: pickups and two-axle trucks have a lot in common, but because the pickup inherits from Car
and not from Truck
, we have to duplicate that common behavior over both classes.
This is where composition comes in: We define a class Vehicle
, which has a few properties, say Seats
, Wheels
, Engine
, CargoHold
, and each of these has a polymorphic type. The beauty is that the vehicle itself doesn’t have to be polymorphic anymore: you can just combine individual instances of your component base classes to form any kind of vehicle you need. Note that we’re still using inheritance to share common functionality: we’ve just split up the functionality into related groups, and build individual inheritance trees for each of them. Obviously, this works best if the components are functionally orthogonal, that is, that they can function mostly independently – e.g., the wheels don’t need to know what kind of cargo they’re transporting.
On a side note; Python’s OOP model addresses some of the problems found in the classic inheritance situation through mechanisms such as advanced multiple inheritance (unlike, say, C++, python resolves base class conflicts such as the diamond problem in a well-defined and useful way), mix-ins, run-time object construction, etc. Because of this, multiple inheritance can sometimes be the better solution in python even if it would make for messy code in something like Java or C#.
1
Without seeing a specific example, it’s difficult to say if the inheritance is inappropriate or not. Sometimes a problem is inherently complex, and “magic glue” code could just be a sign of good (albeit poorly documented) abstraction.
That being said, if the code truly can be improved by applying a given design principle, the best way to prove it to your coworkers is to do it. Take a small part, change it to use composition instead of inheritance, and present that code. You’ve already discovered that throwing a phrase around doesn’t help. That’s because they are comparing concrete and familiar code to your theoretical concept. You have to make your concept just as concrete. Another academic example won’t help.
Technically what you are asking is impossible to be obtained; composition and inheritance are two distinct concepts when speaking about object modeling and one cannot be replaced by other.
When modeling there is nothing wrong with inheritance; the real problem is when in reality you do not have inheritance and in code you have inheritance. When you just use inheritance only for the sake of code reuse you usually go wrong; here composition is a better approach. It in this scenario, that the famous GoF principle “Favor composition over inheritance” is applied, that is use inheritance when and only when you model an “is-a” relationship; it would be a pretty bad design idea to model an “is-a” relationship via composition. Also, there are many more “has-a” relationships in the real world than “is-a” relationships.
On the other hand when you are not really modeling a real-world entity (software stuff) in order to obtain code reuse, composition is preferred in most of the cases. There are example that could be given here.
9