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 638 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
| 20489 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

Steven Van Poeck replied on Thu, 2010/09/30 - 3:33am

Hi Giorgio, These are indeed extreme propositions! Thing is, for some there actually is no viable alternative. By actually I mean "for the moment" and in PHP. And I can reassure you, Java does not implement goto, it's just a reserved keyword: http://java.sun.com/docs/white/langenv/Simple.doc2.html#5551 :) Thanks for the interesting post - as most of yours are. Steven

Liam Knox replied on Thu, 2010/09/30 - 4:20am

I think the thought of removing if is just plain nonsense. Sure it often make sense to do polymorphic dispatches but assuming you can do that everywhere and that will make code less complex is just crap.

Erwin Mueller replied on Thu, 2010/09/30 - 5:19am

You missed the static keyword. If nothing else, we should get rid of static methods and static attributes.

Giorgio Sironi replied on Thu, 2010/09/30 - 5:58am in response to: Erwin Mueller

You're very right, but I just forgot that it existed in the last year. :)

Giorgio Sironi replied on Thu, 2010/09/30 - 5:59am in response to: Liam Knox

Removing it is probably too much, but "coding without ifs" is a diffused exercise in object-oriented and functional programming circles:

http://www.google.com/search?q=coding+without+ifs

Alessandro Santini replied on Thu, 2010/09/30 - 7:24am

Giorgio,

I am sure you already feel how controversial this article is. I more or less agree with some of them, even tough I would like to make some clear distinctions:

  • Public fields - I wholeheartedly disagree. There is no reason to make a field private unless you really require encapsulation. Java sucks big time in this respect because encapsulating a field changes the syntax required to access its contents (and leaving the reflection API aside for now). If the syntax would be consistent as, say, in C# I would have no hesitation to make them all initially public.
  • Static - I do not see static methods as an evil. Methods that do not require to interact with the state of an object can be safely static. This also improves performances in terms of less instances created and less burden on the Garbage Collector (and yes, GC is still a problem)
  • Switch/If - although I agree they can most of the times be replaced with polymorphism, this could lead to an explosion of classes only to handle very simple cases. This is not necessarily a problem but something that must be kept in mind.
  • Extends/Implements and the Liskov substitution principle - I do not understand how implementing an interface instead of extending a class would yield easier conformance to the LSP.
    The main problem in LSP is ensuring that q(x) = q(y) since in both cases (i.e. extends/implements) S extends T. It may sound as a paradox, but there are odds that q(x)=q(y) can be obtained for free by extending rather than by implementing.
  • Private methods - they normally are used to fence portions of code that are reused by public methods; as such they can be tested by testing the public methods relying on them.

This post really sounds like a flame bait :)

Ciao,

Alessandro

Jason Kilgrow replied on Thu, 2010/09/30 - 9:17am

I think some of your ideas are cracked. Sure, just like PERL, there's more than one way of doing it. But, just because a tool (like "if" or "switch") exists, does not mean that you have to use it. Software development as as much art as it is science/engineering and the "art" part of it comes in when the developer has to start making decisions like "should I use this tool or that one? which one works best? which one is most understandable for this situation". Limiting our options is like tying one hand behind your back to wipe your butt. Sure you can do it, but why would you want to when you already have options?

Erwin Mueller replied on Thu, 2010/09/30 - 10:44am in response to: Alessandro Santini

I don't see a reason to make any field public. So the field should get the most restricted scope. And if I need the field to be public, I just put a getter method, so the syntax don't change for the client.

--

If a class is using a static method you will have a hard time to test the class. You can't replace the static method with a stub. In example:

In the first example you can't replace the expensive function with a stub. If the function is expensive your tests are long, or if it does like creating a database, creating files, etc. you need to replace the method with a stub.

In the next example, it's very simple to replace the used method with a stub.

class Foo {
    double doSomething(double x) {
        return Math.someExpensiveFunction(x);
    }
}

class Foo {

    private final Math math;

    public Foo(Math math) {
        this.math = math;
    }

    double doSomething(double x) {
        return math.someExpensiveFunction(x);
    }
}

Andy Leung replied on Thu, 2010/09/30 - 11:39am

You gotta be kidding me with the "Eliminate IF" statement. I may agree with Switch but then I don't use it doesn't mean it shouldn't be there, which is exactly Jason's point.

For IF statement, yeah polymorphism could help sometimes but most of the time we are resolving some simple problems such as following:
String temp = "StartWithAXXX"; if(temp.startWith("StartWithA")){ // Do this }


and you are saying we should really use polymorphism to do that? May be you could show your employer and see if they agree to pay extra money for your coding effort to create all these classes just for polymorphism.

Giorgio Sironi replied on Thu, 2010/09/30 - 12:02pm in response to: Alessandro Santini

It's not an all or nothing proposition, every idea is independent from the others. :)

As other commenters pointed out, public fields shouldn't be the default (but private ones should). About the static methods, keeping them on an instance is useful also for providing a seam other than to ensure no global state is maintained. 

For LSP, many outiright violations come fromlarge class hierarchies. Eliminating subclassing of concrete classes would be a step in the simplifying direction.

Claude Lalyre replied on Thu, 2010/09/30 - 12:04pm

Removing goto, break, continue ? I think you are a bit too extremist in your point of view. If I perform a for loop and I find a searched value, it is better to "break" the loop instead of continuing the irrelevant useless search, no ? Maybe you should invent a natural programming language. Then you will not deal with variables or block control.... Your post is too harsh, this is terrorism programming !

Giorgio Sironi replied on Thu, 2010/09/30 - 12:07pm in response to: Jason Kilgrow

The tools available in a language effectively shape the solutions developed with it, to the point that for example the Python motto is the exact contrary of Perl's one, privileging consistency and simplicity over adding a bunch of features to a language like PHP and Perl do: 

    There should be one-- and preferably only one --obvious way to do it.  http://www.python.org/dev/peps/pep-0020/

 

 

Giorgio Sironi replied on Thu, 2010/09/30 - 12:09pm in response to: Andy Leung

As it is cited in the article, the advice of OOP masters like Misko Hevery is to try to eliminate as many as possible of the ifs (the ones based on state), without becoming a taleban about it.

Artur Biesiadowski replied on Thu, 2010/09/30 - 12:10pm

Replacing ifs/switches with polymorphism is not that obvious in single-dispatch language like java.

Imagine I have a model, representing test results. I want to color the table row displaying result depending on test status (NOT_RUN, FAILED, PASSED). 'Polymorphism' answer to that would be to make a color an attribute of state, which I suppose we all agree is quite ugly. Isn't small switch statement in renderer just best way to split the responsibility between model and this particular view?

I have a feeling you will answer 'Visitor pattern'... but isn't a separate Visitor mechanism a bit overkill for every single substate of the model you want to visualize?

As far as breaks/continues are concerned, most people who are 'against' are just replacing them with extra boolean variables. So

 

outer: while (x) {
   while(y) {
      something
      if (z) { break outer;}
      somethingelse
   }
   andyetanother
}

 becomes

boolean fakeVar = false;

while(fakeVar && x) {
   while (fakeVar && y) {
     something
      if (z) { fakeVar = true;}
      else {
         somethingelse
      }
   }
   if (!fakeVar) {
     andyetanother
   }
}  

Please tell me with straight face that fakeVar is something else than just disguised goto, just triple as ugly as break.

Mark Haniford replied on Thu, 2010/09/30 - 1:37pm

What "we" don't need is anymore people saying "we" ;)

That said, I did like the article.  I guess the overall theme is think about polymorphism and testability.  There's a good Google video on  Inheritance, Polymorphism, and Testing

 

Edit - oops...missed the link to that video in the article, but great stuff none-the-less.

 

 

Andy Leung replied on Thu, 2010/09/30 - 1:39pm in response to: Giorgio Sironi

No offense but isn't that the example the "OOP master" Mr. Hevery shows a bit too trivial, I mean simply it's a bad one. Honestly, will you really code couple classes to JUST replace simple Switch on some primitive types? Translate my previous example of String comparison case into "Non-If" design, and then repeat it 300 for an enterprise application, see if you are sick of it or what. To me, unless the code is at a very low-level (like I/O), I usually break things into small objects with adequate number of methods, and maintain 10 - 30 lines of code for each at max AND I keep using IF/SWITCH. I know it may be hard to read but I actually have trouble reading too many objects (especially ones for replacing IFs) because I have to understand each object before I could even read what the method is exactly doing even though method name may be clear enough.

And Bod replied on Thu, 2010/09/30 - 1:47pm

Oh you re a php devvy. That exlains alot. U use patterns and polymorphism none the less. In php. That s like making coat hangers for paper mache shirts. Look everyone s entitled to their opinion but atleast be honest and admit you re referring to php when u have all thesd intectual.stomach akes. Stop pretendig that its about other or some generic oop language.

Alessandro Santini replied on Thu, 2010/09/30 - 2:16pm in response to: Giorgio Sironi

Misko Hevery? OOP master? Please Giorgio, I do not mean to be offensive but get out of the books and dive into production code and deadlines :)

Also, I have worked with Alberto (we were also desk-mates) and I distinctly remember him typing if statements :)

Endre Varga replied on Thu, 2010/09/30 - 2:16pm

Public fields are not a problem in Scala as they are implicitly interpreted as a pair of getters and setters. This also means that there is no difference in variable access and function calls.

Alessandro Santini replied on Thu, 2010/09/30 - 2:18pm in response to: Endre Varga

That was exactly my point, Endre - if Java had a uniform way to access fields and properties, one could just create public fields and encapsulate those who need validation or lazy initialization at a later moment, without affecting clients.

Thanks for making it clearer.

Artur Biesiadowski replied on Thu, 2010/09/30 - 3:04pm

As far as I know, C# field->property migration is only source compatible. You still need to recompile all the clients. If you are in API/library writing mode, it is a no-go.

Check out

http://blogs.msdn.com/b/abhinaba/archive/2006/04/11/572694.aspx

for more detailed explanation.

Erwin Mueller replied on Thu, 2010/09/30 - 4:30pm in response to: Artur Biesiadowski

Wow, that is bad. If the code don't change, the bevavior should not change either.

I like it how it's done in Groovy. If you want public attributes, Groovy will make internal standard Java Bean get/set methods. If you need to add validators/etc. you just write a get/set method yourself.

But why you need public attributes anyway, Alessandro? You never need public attributes, maybe only in Java Bean classes.

Alessandro Santini replied on Thu, 2010/09/30 - 4:54pm in response to: Erwin Mueller

I agree. I should rephrase my example stating Groovy instead.

As to why public attributes, I simply do not see the need for two methods (accessor/mutator) that clutter my codebase, increase my total SLOC count for doing... well, nothing but passthrough.

Alessandro Santini replied on Fri, 2010/10/01 - 4:10am in response to: Giorgio Sironi

 As other commenters pointed out, public fields shouldn't be the default (but private ones should).

What I read from other commenters is that other languages (e.g. Scala, Groovy and, to some extent, C#) provide much better mechanisms to transform a field to a property and vice versa. Have you ever had to deal with an object carrying data only (e.g. a JAXB-bean representing a web service response)? Do you really think that getters and setters provide added value? And please, do not point me to what other people said, I personally dislike this approach (the Master said, so that's true).

About the static methods, keeping them on an instance is useful also for providing a seam other than to ensure no global state is maintained. 

Static methods should obviously be re-entrant. Global state can also be used as long as this does not provoke concurrency issues.
Now think about an object in your IOC container of choice. When a dependent object gets an instance of this class, it is unaware if it is a singleton or not; this situation (which is even worse) may change over time just by changing an XML file (or annotations). If it is a singleton, you may encounter just the same problems of global state and concurrency, just without the "static" word.

For LSP, many outiright violations come fromlarge class hierarchies. Eliminating subclassing of concrete classes would be a step in the simplifying direction.

Can you explain this sentence to mere mortals like myself?

 

Ciao,

Alessandro

Amin Mansuri replied on Thu, 2010/09/30 - 7:41pm

The minimalistic language you are trying to come up with is called: Smalltalk. And it was the original OO language (Simula wasn't a complete OO language).

Smalltalk omits if, break, continue, while, for, do, and basically most keywords in favor of dynamic dispatch. So if you want to do a loop you'd write something like:

[aBooleanExpr] whileTrue: [ "do something loopy" ]

Smalltalk is so down to the bare minimum that I have a hard time thinking of a language that could be more barebones and OO. My theory is that without knowing people are gravitating towards Smalltalk (or some new incarnation of the language). Hence they preferred Java over C++ (references, gc, vm from Smalltalk) and now many prefer Ruby over Java (dynamic typing, many similar statements as ST had).

Erwin Mueller replied on Fri, 2010/10/01 - 4:25am in response to: Alessandro Santini

Global state should never be used. It hides dependencies and makes testing so much harder.

About testing I already wrote an example. But because of a dependency to a global state you can't run tests in parallel, you can't just test a specific class, etc.

It also hides dependencies. If you use static methods/attributes you don't see them, because they are all over the class. If you do DI you can spot every dependency in the constructor of your class.

In adition, you can't see why a class don't work. Because it uses a global state you need first to get to this state to use the class. This is not obvious.

 As for public attributes, there is no need for a global state. But it's true that Java makes the getter/setter a lot more verbose then it should be. Nevertheless, just because Java makes it so verbose you should not just use public attributes.

Cosmin Mutu replied on Fri, 2010/10/01 - 4:54am

I just lost 10 minutes of my life reading this article ...

Alessandro Santini replied on Fri, 2010/10/01 - 5:01am in response to: Erwin Mueller

I think I did not convey my ideas they way I wanted.

Of course I did not mean to say that global state is a good thing or should be used, only that it sometimes happens to keep some kind of global state, particularly in desktop applications (there is too often the assumption that web/enterprise applications are the only scope of the discussion).

Back in the days of the singleton pattern (which happened not too far ago), the singleton instance represented a form of global state in its own right, and many applications relied on it without any particular side-effect (with the only exception of testing).

Giorgio Sironi replied on Fri, 2010/10/01 - 10:51am in response to: Alessandro Santini

Misko Hevery works at Google. Now if Google does not have production code... :)

Josh Marotti replied on Fri, 2010/10/01 - 11:43am

I never understood hatred of goto except readability.

If you are familiar with Assembly, or, even moreso, Compilers, you'll know that 'jump' is used often, and is basically a goto in machine code.  So a goto is simply something that makes the compiler convert the code to machine code easier and more efficient.

There is something to be said of readability vs performance of the compiled code.

Comment viewing options

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