Agile Zone is brought to you in partnership with:

I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 636 posts at DZone. You can read more from them at their website. View Full User Profile

What we don't need in object-oriented programming

09.30.2010
| 19772 views |
  • submit to reddit

Once I heard Alberto Brandolini giving a keynote at an Italian conference, saying, between other insights, that Lego bricks where one of the most abused metaphors in software engineering.

One of the most abused sayings, instead, is this one:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. -- Antoine de Saint-Exupéry
that is often used in reference to application design. However, it is in general true that you should strive for writing code as simple as possible (in length but in complexity too) to obtain an end result specified by a requirement or a user story. If there are two designs for a feature, almost always we would choose the simplest.

This article takes a broader view on object-oriented programming, and ask the following question:
  • What are the constructs we don't need in an object-oriented language? What we can take away without hampering our capabilities of building software?
  • If we actually don't need them, we can eliminate them from the language, and make it more simple. At the same time, make the application written in it more consistent, since they have less features to abuse.
We'll examine some typical reserved keywords of Java and PHP we could theoretically eliminate along with the features they represent. Of course the final destination of this journey would be the Turing-complete assembly, but I want to stop before ruining the object-oriented paradigm. Higher levels of abstraction in modern programming languages are sometimes crucial (classes and objects), sometimes prone to abuse (subclassing).

Forgive me if I'll refer to patterns instead of code, but I don't want this discussion to become language-specific.

instanceof

Usually, when you check for an object being instance of a class, you can implement the scenario with polymorphism.

The Template Method and the Strategy patterns are all about this replacement, which comes handy also in the case of switches and if statements.

goto (jumps)

Should I say anything? Even Java, the most-diffused object-oriented language in the world, has Goto as a reserved keyword (I hope it is not implemented).

break and continue (disguised jumps)

They are really gotos which have put on camouflage, and any professor of computer science would keep an eye on you if you used them (mine did, and I was too young to recognize the value of clean code).

extends (subclassing)

Subclassing is very often abused, with classes extending other ones only to gain access to their methods, in spit of is-a relationships; maybe we can prohibit them altogether. We'll gain almost automatic conformance to the Liskov Substitution Principle, since it would involve only interface and their implementations. The main reason for its infringements, sharing methods code, would go away.

Since eliminating subclassing is a bit extreme, an idea that stroke me while re-reading Uncle Bob's explanation of SOLID principles is to eliminate subclassing of concrete classes. This way, we'll never introduce a dependency towards an implementation detail, but we can still make use of abstract classes, very valuable in an API.

protected (subclassing scope)

Of course, if we eliminate subclassing, we can throw away the intermediate protected scope altogether. Also if we choose a single level of subclassing towards an abstract one, this scope would do less harm than it does today.

For example, in Zend Framework almost always is protected instead of private, and the user is free to subclass and access any internal part of the framework's components. The scenarios that happen then are two: either the framework developers cannot modify code anymore to avoid breaking backward compatibility (so why they bothered restricting the scope in the first place), or the user has to revise his classes when upgrading from 1.6.1 to 1.6.2 because of sudden changes.

public (for fields)

Public fields are the death of encapsulation, and I can't remember the last time I introduced a public field long time ago. Let's just throw them away.

private (for methods)

How do you test private methods? Often we arrive to a situation where we have complex private methods we want to test independently. This is often a smell of a class that does more than one thing (Single Responsibility Principle), and should be ripped up. In this case, we can move the private methods away and transform them in public methods on a private collaborator, safeguarding encapsulation but simplifying the picture and being able to test them due to the new contract established between the main class and the extracted one.

switch (conditional chain)

Switch chains, especially if duplicated in different places, can be replaced with polymorphism. The idea is to push the switch up to che choice of the object, and push the particular operations in each of the switch branches into the chosen object.

if (conditional)

If we can replace switches, we can also replace ifs, that are a special case of switch with only two branches. The reasoning is the same and the advantages are clear: you would have only one execution path to test for each method, and you'll be sure of which lines are executed: all of them. Misko Hevery says that often most of the ifs can be replaced with polymorphism, but you should be pragmatic about it and not try to kill them all.

The problem with the last two elimination is that in our languages we can't remove all ifs yet, but only push them up in the creation of the object graph. But if we had a language or a construct capable of transforming textual configuration into a graph of objects, we could get rid of ifs even in the Factories. Dependency Injection containers actually transform configuration into objects wired in different ways, so we may be near to a solution.

Conclusion

Some of this crude eliminations are extreme and maybe not even practical. However, before making a trade-off between two scenarios, a programmer has to know the extreme situations that arise from the overuse and absence of a construct or feature. I am the first to recognize to have committed (in both senses) if and subclassing abuse. I hope to have made you think a bit about subclassing, scopes and conditionals, so that the next time you start coding you will ask yourself: I really need to use yet another subclass / a very long private method / this duplicated switch construct?

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Alessandro Santini replied on Fri, 2010/10/01 - 7:06pm in response to: Giorgio Sironi

I work at IBM if that matters. What you have shown, is that you do not seem to think with your own mind. For as wrong as it can be, I have given you an answer with some (possibly logically flawed) reasoning, you simply preferred to hide behind someone else.

Alexander Radzin replied on Mon, 2010/10/04 - 2:22am

I agree with some of statemenets from this article and would like to comment them.

  • instanceof is really strange operator. There is other way to do the same: obj.getClass().isAssignableFrom(). This way is more verbose and this is good: you think twice before you are writing such code and probably find better solution.
  • goto - agree 100%. But it is not implemented in Java, so no worries
  • break and continue - strongly disagree. These operators intorduced in C help to better code. I have been coding in Pascal proor to C and I remember my ugly code with 10 levels of nesting. Moreover sometimes I even use break with label and I do not think that this is a crime if this tool is used carefully.
  • It is a good idea to extend only abstract classes. I disagreed when I read this paragraph first time but than thought a little bit and changed my mind.
  • I agree that protected methods/fields are often dangerous but they allow us to implement (for example) template method pattern. I think that @Override annotation introduced in Java 5 helps us to use protected scope carefully. I think that less extreme rule is that protected methods should be always final or abstract or empty implementation. Final is good if you wish to allow subclass to use some services of abstract class, abstract is good for patterns like template method and empty implementation is good for adapters (e.g. WindowAdapter).
  • pulibc fields could be only final.
  • private methods are usulally contain code that is used by other mehthods of the same class and cannot be tested separately. When I have to write unit test of private method I use one of the following strategies:
    • delegate this method to external package protected utility class.
    • comment out private modifier and write comment that it is done for testing.
      // This method must be private. It is package protected to enable unit testing
      /*private*/ int foo(int param) {
          return param * 2;
      }
  • only legal place for swith is factory or factory method. Better switch variable is not int but enum. In this case compiler reminds you to modify switch when enum is being changed.
  • Elimination of if statement is INHO to extreme. I think that compiler should create warning when one uses "else if" sequence because it is a switch like structure coded using if-else statemenets.

Giorgio Sironi replied on Mon, 2010/10/04 - 3:37am in response to: Alexander Radzin

Thank you for your feedback. Many commenters read only the article title and didn't take the time to reach the final conclusions. I am experimenting with many of these programming choices, but eliminating the features altogether is probably too extreme for general-purpose languages.

Germán Hohmann replied on Tue, 2010/10/26 - 10:01am in response to: Giorgio Sironi

 Hey Giorgio, very interesting post! Excellent for thinking and coding exercises.

  Also, the comments are always very very valuable here in this comunity (btw, I have to confess that enjoy them as much as the posts). I believe some of them correctly point out the use of some of these reserved words and patterns to improve performance (for instance).

 On the other hand, nice OO and readable code is great (oh yes it is!), but usually fast and usable functionality is more important (of course than flexible/rubust/extensible code too) Glad to hear about Misko here also :)

 I have to take a look at Smalltalk now...

 Keep posting!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.