Sunday, May 24, 2015

Object Spaghetti

Every so often some new programming paradigm comes along  that is hyped to save us (programmers) from ourselves.  Most of them have at least some merit, and some are very good and stand the test of time.  For instance, structured programming was just a buzzword before the term buzzword became a buzzword.  But it made great promises and mostly has lived up to that promise.  It has lived up to it so much that most new programmers aren't even taught the term any more: it is simply acknowledged that programming will be done that way.

Object oriented programming has made some great promises and has been rather successful.  Not to the same extent that structured programming has, though.  And it has taken longer.  What many people don't realize is that object oriented programming is nearly as old as structured programming.  It made its first (by my minimal research) appearance in the Simula 67 almost 50 years ago.  But it didn't really begin to gain traction until the 80s and 90s with the introduction of Smalltalk 80, C++, and Java.  A large percentage of new languages being introduced are object oriented to one degree or another, and most of the older languages have had objects added to some extent (including BASIC, Pascal, Fortran, and even COBOL.)  Microsoft entered the arena with C#, which is very similar to Java in many ways, but I think much better.  I've heard it described as "Java done right."  That seems about right to me.  I write a lot of C# and rather like it.  But what has object oriented programming really done for us?  Is the success of OOP (object oriented programming) its own downfall?  What have we learned?  What have we forgotten?

If there is one common thread between programmers, it is that we are lazy.  We are always looking for the easy way out.  And we demand that our languages give us those easy ways.  Some nice language comes along from research that nice and clean and makes the theoretical computer scientists somewhat happy as well as the practicing programmers.  And if real people writing real code find it useful, and it is hip and cool, it will become successful.  One thing that makes it attractive to real programmers is when the language makes it relatively easy to do the all too frequent "uncommon" types of things.  Take a look at C.  Why was it so successful?  In part, because it gave a fairly clean structured language that still allowed you to do almost anything, including efficiently twiddle bits and move data around at a low level.  C became insanely popular.  It is still used for quite a few large programs.  It is the language of choice for the Linux kernel.  It is the closest thing to a standard for embedded systems.  Programmers like it.  It makes complex and off the wall things easy that other languages make difficult.

C# started out as a really nice, clean, object oriented language that both academia and real programmers could get behind.  It enforced some safety mechanisms but was still flexible enough to make programmers pretty happy.  And with Microsoft making it their language of choice, it almost had to become successful.  With that success has come the "wouldn't it be neat if" features.  But that isn't the root of the problem, just a symptom.

Wait a minute.  What problem?

Oh, yeah.  We have a problem.  And just like addiction, the first step to recovery is to admit you have a problem.  Our problem is that we are writing terrible code, but we are packaging it up nice and pretty with our World Saving OOP and our design patterns and calling it good.  And we are teaching whole generations of programmers, who have never heard the term structured programming, how to write spaghetti code.

One of the basic foundations of OOP is that it aids in data hiding.  Within a class or object, we hide away the data that object needs internally without exposing it to the outside world.  We can be sure it is in the state we want/need it to be in because nothing outside the object can access it without going through us.  Obviously, some of that data needs to be read or written to from outside.  Typically, we write accessor methods of some sort: getters and setters.  We don't expose the variable itself.  If someone wants to read a variable, we provide a getter method (ie getVelocity() ) that returns the value any way we want.  We are free to store it with whatever format makes the most sense, and pass it to anyone who needs it in a well-structured, fixed way.  Our getter method will do any translations needed.  If we need to set the variable, we write a setter method (ie setVelocity( double metersPerSecond) ) and check the incoming values for sanity before assigning the variable.  Again, we can do any processing required and store the value however makes the most sense.   That makes the velocity value accessible, but only in safe, controlled ways we authorize.  Nice.  Clean.  Safe.

But programmers are lazy.  That's a lot of little methods we have to write.  And then we have to call a method to get or set the value.  "It would be neat if" we could access it just like a variable.  Without all that method call typing.  But public variables are bad.  We can't just make them public.  The creators of C# used a really neat trick (I don't know who invented it.  But C# was the first place I encountered it.) that lets you safely access private variables like they are public, but safely: the property.

A property looks and works like a variable, but with backing code that acts like a method.  It's a really neat and useful idea.  You get the convenience of a public variable with the safety of using accessor methods.  Say you have a class Automobile and in that class you have a private variable _speed.  You want to be able to set the speed directly, but without exposing the variable.  You can create a property in the class like so:

public double Speed {
   get{ return _speed;}
   set{ if (value >= 0.0) _speed = value;}
};

The get clause allows read access to the property (and the backing private variable) and simply returns its value.  The set clause allows you to set the value, but only if it is not negative.  Of course, you can do much more than shown here.  You can then use the property just like a variable once you have instantiated an instance of the Automobile class:

Automobile maserati = new Automobile();

maserati.Speed = 185; // lost my license, now I don't drive

The Speed property looks and acts pretty much like a public variable except that it provides the same protection as getter and setter methods.  You can omit either the get or set clause if you only want to provide one or the other.  If the set clause was omitted above, you could read the value, but not set it.

But programmers are lazy.  Somewhere along the way somebody decided that was too much trouble.  They added a bit more syntactic sugar to the language.  Now the language will allow you to do this:

public double Speed{ get; set;};

and you don't even have to declare the backing variable.  It will create it for you.  This has become quite common.  It's simple and easy.  There is almost no code to write.  It is also very, very dangerous and very bad style.  It is, unfortunately, very common.  Programmers are lazy.  I'm waiting for someone to tell me how this is any different than a public variable.  There is absolutely nothing to prevent me from assigning any value to Speed.  I can now make my maserati go -4987.25 miles per hour.  Granted, we could have had the same effect without this new syntax by just doing this:

public Speed
{
   get{ return _speed;}
   set{ _speed = value;}
}

But I have rarely seen this.  Perhaps forcing the programmer to write out that much puts him in the mindset that he (or she) needs to put in some protection.  I don't know.  I just know programmers are lazy.  Look around the web for C# code.  I suspect you will find a lot of those constructs.  This is the stuff that OOP was created to prevent.  What are we doing?

I've seen plenty more stuff in OOP that throws me back to my Microsoft line numbered BASIC days.  One day soon I plan to rant about design patterns: the morphine of coding.  They are good when you need them, but very easy to abuse.

I've come to realize that any language can be used to write terrible code.  It takes a concerted effort to keep from falling into the trap.  But I am a firm believer that our programming languages should help us stay away from those traps rather than lead us to them.



No comments:

Post a Comment