DeepHierarchy

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(Do Not Expose Deep Hierarchies)
Current revision (05:45, 24 September 2022) (edit) (undo)
(Substitution Principle)
 
(14 intermediate revisions not shown.)
Line 1: Line 1:
[[OOP]] encourages code reuse and may lead to deep subclassing hierarchies. Beware of that when designing [[API]].
[[OOP]] encourages code reuse and may lead to deep subclassing hierarchies. Beware of that when designing [[API]].
-
== Do Not Expose Deep Hierarchies ==
+
=== [[OOP]] Models the World ===
Classic [[OOP|object-oriented programming languages]] are said to be inspired by nature and its
Classic [[OOP|object-oriented programming languages]] are said to be inspired by nature and its
-
evolution. Everyone knows the example defining a '''Mammal''' class with basic methods describing
+
[[evolution]]. Everyone knows the example defining a '''Mammal''' class with basic methods describing
the behavior of every mammal, and various subclasses such as '''Dog''' or '''Cat''' overriding the methods
the behavior of every mammal, and various subclasses such as '''Dog''' or '''Cat''' overriding the methods
to do what cats and dogs do differently. This example not only demonstrates what
to do what cats and dogs do differently. This example not only demonstrates what
Line 10: Line 10:
easy it is to describe nature, the object-oriented concept is also elevated to be the right programming
easy it is to describe nature, the object-oriented concept is also elevated to be the right programming
technique to describe the real world. [[OOP]] languages are supposed to be more suitable
technique to describe the real world. [[OOP]] languages are supposed to be more suitable
-
than traditional, procedural ones for coding and capturing real-world concepts.
+
than traditional ones for coding and capturing real-world concepts.
-
After maintaining a framework in Java for more than ten years, I don’t buy this. It’s fine
+
=== Just an Intricate Switch ===
-
that something (usually a class) reacts to messages (in Java method calls) and that there might
+
 
-
be someone who can intercept that message and change its meaning by overriding some of
+
After maintaining a [[NetBeans|framework in Java]] for more than fifteen years, I don’t buy this. Honestly, ''virtual method dispatch''
-
the methods and reacting differently to them. However, honestly, this is nothing other than an
+
is nothing else than an
''intricate switch statement''! A method call isn’t a direct invocation of some code but rather a
''intricate switch statement''! A method call isn’t a direct invocation of some code but rather a
switch that chooses from multiple implementations. The switch is based on the list of subclasses
switch that chooses from multiple implementations. The switch is based on the list of subclasses
Line 21: Line 21:
it’s still a '''switch'''. Of course, explaining [[OOP]] as an ''enhanced switch'' is
it’s still a '''switch'''. Of course, explaining [[OOP]] as an ''enhanced switch'' is
much less fancy than presenting it as a technology that helps us model the real world. That’s
much less fancy than presenting it as a technology that helps us model the real world. That’s
-
why computer courses are likely to stick with the Mammal example. However, I’ll use the switch
+
why computer courses are likely to stick with the '''Mammal''' example.
 +
 
 +
=== Switch with no Limits! ===
 +
 
 +
However, I’ll use the switch
explanation to reveal an important hidden catch: when writing an [[API]], ''the size and behavior
explanation to reveal an important hidden catch: when writing an [[API]], ''the size and behavior
of the switch is unknown'' to the writer of the code. This can be seen as an advantage, increasing
of the switch is unknown'' to the writer of the code. This can be seen as an advantage, increasing
Line 29: Line 33:
maintainable.
maintainable.
-
So, simply exposing a deep hierarchy of classes is unlikely to improve an API’s usability.
+
=== Substitution Principle ===
-
When writing an API, the term “subclass” shouldn’t be used for someone who can “participate
+
 
-
in a switch,but for someone who ''behaves exactly like me'', plus adds some additional behavior.
+
When writing an [[API]], the term ''subclass'' shouldn’t be used for someone who can ''participate
-
True, many would agree that a '''Human''' is a subclass (a specialization) of a '''Mammal'''. But how
+
in a switch'', but for someone who ''behaves exactly like me'', plus adds some additional behavior.
-
much can you use this fact in an API design? Especially [[GUI]] toolkits got this all wrong.
+
True, many would agree that a '''Human''' is a subclass (a specialization) of a '''Mammal'''.
 +
Nice, but simply exposing a [[DeepHierarchy]] of classes is unlikely to improve an [[API]]’s usability magically.
 +
 
 +
Especially [[GUI]] toolkits (full of widgets inheriting from each other) got this all wrong.
They like to claim that a {{JDK|javax.swing|JFrame}} is a specialization of {{JDK|javax.swing|JComponent}},
They like to claim that a {{JDK|javax.swing|JFrame}} is a specialization of {{JDK|javax.swing|JComponent}},
but try to use {{JDK|javax.swing|JFrame}} where you can use {{JDK|javax.swing|JComponent}}! It is going to fail.
but try to use {{JDK|javax.swing|JFrame}} where you can use {{JDK|javax.swing|JComponent}}! It is going to fail.
-
That is not failure of the usage, but failure of the [[GUI]] toolkit [[API]] designer!
+
That is not a failure of the usage, but a failure of the [[API]] designer!
-
The advice here is: instead of big, rooted families, try to define the real interface of the application and let users
+
== Do Not Expose Deep Hierarchies! ==
-
implement it. Always remember the ''Liskov's principle'': if something is a subclass or a subinterface, it can inherently
+
-
be used in place of the original superclass or interface.
+
-
Rather than exposing [[DeepHierarchy]] separate [[APIvsSPI]] and stay as flat as possible!
+
Rather than exposing [[DeepHierarchy]] separate [[APIvsSPI]] and stay as flat as possible! If you have to expose subtyping, remember [[wikipedia:Liskov_substitution_principle|Liskov's substitution principle]]: if something is a subtype, it has to inherently
 +
be ready to be used in place of the original super class or interface.
[[Category:APIDesignPatterns]]
[[Category:APIDesignPatterns]]
 +
[[Category:APIDesignPatterns:Anti]]

Current revision

OOP encourages code reuse and may lead to deep subclassing hierarchies. Beware of that when designing API.

Contents

OOP Models the World

Classic object-oriented programming languages are said to be inspired by nature and its evolution. Everyone knows the example defining a Mammal class with basic methods describing the behavior of every mammal, and various subclasses such as Dog or Cat overriding the methods to do what cats and dogs do differently. This example not only demonstrates what object-oriented languages do best, but it also justifies the whole purpose of OOP. By showing how easy it is to describe nature, the object-oriented concept is also elevated to be the right programming technique to describe the real world. OOP languages are supposed to be more suitable than traditional ones for coding and capturing real-world concepts.

Just an Intricate Switch

After maintaining a framework in Java for more than fifteen years, I don’t buy this. Honestly, virtual method dispatch is nothing else than an intricate switch statement! A method call isn’t a direct invocation of some code but rather a switch that chooses from multiple implementations. The switch is based on the list of subclasses and can potentially grow as various developers create more and more subclasses. But it’s still a switch. Of course, explaining OOP as an enhanced switch is much less fancy than presenting it as a technology that helps us model the real world. That’s why computer courses are likely to stick with the Mammal example.

Switch with no Limits!

However, I’ll use the switch explanation to reveal an important hidden catch: when writing an API, the size and behavior of the switch is unknown to the writer of the code. This can be seen as an advantage, increasing the number of ways that a piece of code can be reused. However, a few releases later, if you don’t know the actual participants in the switch, you can have a nightmare on your hands. Simply allowing an unknown party to participate in your code “switch” can be too open to be maintainable.

Substitution Principle

When writing an API, the term subclass shouldn’t be used for someone who can participate in a switch, but for someone who behaves exactly like me, plus adds some additional behavior. True, many would agree that a Human is a subclass (a specialization) of a Mammal. Nice, but simply exposing a DeepHierarchy of classes is unlikely to improve an API’s usability magically.

Especially GUI toolkits (full of widgets inheriting from each other) got this all wrong. They like to claim that a JFrame is a specialization of JComponent, but try to use JFrame where you can use JComponent! It is going to fail. That is not a failure of the usage, but a failure of the API designer!

Do Not Expose Deep Hierarchies!

Rather than exposing DeepHierarchy separate APIvsSPI and stay as flat as possible! If you have to expose subtyping, remember Liskov's substitution principle: if something is a subtype, it has to inherently be ready to be used in place of the original super class or interface.

Personal tools
buy