Cover of The Pragmatic Programmer by Andrew Hunt, David Thomas - Business and Economics Book

From "The Pragmatic Programmer"

Author: Andrew Hunt, David Thomas
Publisher: Addison-Wesley Professional
Year: 1999
Category: Computers

🎧 Free Preview Complete

You've listened to your free 10-minute preview.
Sign up free to continue listening to the full summary.

🎧 Listen to Summary

Free 10-min Preview
0:00
Speed:
10:00 free remaining
Chapter 5: Bend, or Break
Key Insight 4 from this chapter

Avoiding Inheritance and Preferring Alternatives

Key Insight

Traditional class inheritance, whether used for code sharing or type building, is often a problematic design choice, summarized by the quote, 'You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.' Its origins in Simula 67 and Smalltalk have led to a generation of developers using it to avoid typing or to express 'is-a-kind-of' relationships. However, inheritance fundamentally creates coupling; a child class and any code using it become deeply tied to its entire ancestral hierarchy, including parent and grandparent classes.

When inheritance is used for code sharing, as seen in a `Car` subclassing `Vehicle`, changes in the parent's API (e.g., `move_at` to `set_velocity`) or internal instance variable names (e.g., `@speed` to `@velocity`) silently break the child class and top-level code, demonstrating significant coupling. Using inheritance to build types leads to overly complex class hierarchies, growing into 'wall-covering monstrosities' that make applications brittle. Furthermore, accurately modeling real-world relationships often demands multiple inheritance (e.g., a `Car` as a `Vehicle`, `Asset`, `InsuredItem`), which is frequently unsupported in modern languages due to historical issues, thereby limiting accurate domain representation.

To avoid the 'Inheritance Tax,' three better alternatives are proposed. Interfaces and protocols (e.g., Java's `public class Car implements Drivable, Locatable`) allow classes to declare that they implement specific sets of behaviors without inheriting implementation, providing polymorphism based on type compatibility. Delegation enables a class to forward requests to an encapsulated helper object, breaking tight coupling to frameworks (e.g., an `Account` delegating persistence to a `Persister` object) and allowing better control over its public API. Mixins, traits, or similar mechanisms provide a way to extend classes or objects with new functionality (sets of functions) without using inheritance. This is useful for sharing common finder methods (e.g., `CommonFinders` mixin) or applying specialized validation sets (e.g., `AccountForCustomer with AccountValidations, AccountCustomerValidations`), offering flexible code reuse and improved separation of concerns.

📚 Continue Your Learning Journey — No Payment Required

Access the complete The Pragmatic Programmer summary with audio narration, key takeaways, and actionable insights from Andrew Hunt, David Thomas.