Wednesday, February 8, 2012

Where does bad code come from?

Let me tell you a story. There is this developer. Who could be you or me, or any other of the thousands out there. He goes to work every day, not because he has to, but because he wants to, because he loves what he does. But, no matter what, there is always something that prevents him from enjoying his day fully: bad code.

Yes, that putrid, stinking amorphous "thing", that after a while if you are anything like me, makes you want to cry. The subject of probably more than one song and definitely, the cause of a great deal of the headaches developers suffer.

But... you have to wonder how is that bad code comes to be? Where does it come from? How is it that even if code is not organic, if its not a piece of meat, it starts degrading and rotting like one.
I know, I known... someone else wrote it. The bad code I mean. ;) But... What is that the other guy does, or doesn't do to make it rot?

I think the answer is simple. Writing software, and particularly software design is about how you structure your software. What goes where, who talks to who, which parts of your code do you allow to do what, etc. That is pretty hard to do properly most of the time. There is of course, a lot more into it. I am for the brevity of this post over simplifying it. But I personally think that is one of the main concepts behind it. It is also, the main reason for bad code to exist: dependency management. Or to say it properly: bad dependency management. You don't see it? Keep reading.

So... What goes wrong with software development?
Let's go back to our developer friend. Let's say he starts a new project, and that he has all his requirements ready! What does he do?

He goes and draws these big diagrams. Because who doesn't like drawing? Right?. He creates this huge representation of what he is going to do, maybe database schema, gantt chart, etc. When he is finished, and after a few minutes  of  contemplating his magnificent work of art, showing it to everyone, etc. he finally sets of to write the code.

The code then flows like a river. It just does! Lines and lines of code come out until its finished! Then he ships it and that's it! He lives happily ever after!

Ok. In the words of Orson Welles: If you want a happy ending, that depends, of course, on where you stop your story.

Yes, sadly, we know that's not the whole story. Because, after shipping ,what actually happens is that people start using this code. Not only that. They start requesting changes. What? Then some more changes. Then even more changes, and after that.. You guessed it right!... more changes! Finally, the poor guy who is developing it just decides to end it all and kills himself.

Why did this happen?
Well, this developer didn't manage his dependencies so the code started to putrefy. It became rigid. It became ugly, hard to maintain, hard to modify, hard to fix and easy to break. It probably was not even easy to test. It started rotting, to have a mind of its own and at one point the stench was so bad he had no other choice but to run away from it. Creator running away from its creation like a Frankenstein.

Its not the changes that created the problem, but the way he dealt with them. I mean, who has not written one of those famous patches, just to annotate it with a big TODO, o FIXME. Always with the hope that, some day, when you have a time, you will come back later and do some house keeping. We know that day, is yet to come.

This concept is not new. Not at all! In fact, I am positive most developers and projects that I know of, suffer from some kind of technical debt. You don't (or at least I don't) write perfect code from the start most of the time. Its a process! An evolution. It is a part of the software development processes to create that technical debt, and to repay it. When, and how you decide to do it, is what makes the difference. 

Will you pay it at the end, with all its interest and let it ether drive the project to the ground, or in many cases, constraint development and probably dictate the architecture. Or will you chose to repay it as you go, and keep your architecture evolving and open to as many possibilities as you can. In any case, if you are not good on regularly doing your house keeping, at least, you can train your nose to detect early that something needs two minutes of your time.

Which brings me to my next point. 

How do you know your code is starting to decay? 
Answer: When you feel the smell.

Doing some research, I found that the main code smells have been already classified by Robert C. Martin. If you don't know who "Uncle Bob" is, and what he has done, you go Google it! Now! Well.. not now, first finish reading my post... but I mean it. ;)

These groups in which he classified code smells are:

If your code starts getting stiff, like a dead body, it may as well be. That means, if you can't take care of that little thread that is showing up out of place, without unweaving the whole t-shirt, you have a problem. By that I mean, if you have a bug that in order to fix it you have to go around the whole code base touching stuff, your code is definitely rigid.

Have you ever had a system that got broken by the most unexpected and unrelated thing ever. Kind of, the butterfly effect. A butterfly flaps its wings half a world away and a tsunami ends up destroying your house.

For example, miss-spelled magic strings. The typical case of the new guy that sees one of those magic strings and can't resist the temptation to correct the spelling mistake. But it turns out that mistake is hard coded on views and probably even 3rd party systems, and after a while you find out half the application stopped working. Yeah... I've been there...

How much of your code can you reuse? If you wanted to rebuild your code using a different MVC framework, or maybe move it into a desktop application. How much of it would you have to write again? If your answer is, almost all of it, you have a mobility (re-usability) problem. In fact you probably have an architectural problem, but that is another story.

We developers, are lazy. That's a fact. When something is tedious and boring to do, but we "have" to do it, chances are that we will try to find ways not to. This particular code smell type, comes in two flavors.

What I mean is, when faced with two options, one that solves the problem and maintains the architecture, and one that does not, if the proper solution is much harder to implement, developers will not tend to use it. There you go, sticky everywhere, the view accessing the database, or the model that knows about the services. Uncle Bob call's this kind of viscosity: by design.

On the same line if there are several ways of making a change but the one that is not a hack, includes a 2 hours build. People will use the hacks. They will try to find ways in which to avoid that 2 hours build, and you would be surprised how inventive some people can be. In this particular case where the development environment is the one conspiring against you, you have an environmental viscosity problem. 

I think we can agree that a 2 hours build and people committing changes where they compromise the architecture are problems on their own. The important part here is to notice how subtle things directly affect the way you manage your dependencies, which in turn, if not addressed properly, can, and will deteriorate the quality of the code base.

Anyways... In subsequent posts I am going to be talking a lot more on this subject and how can you actually hone your skills at managing your dependencies so that this code smells eventually get reduced to a minimum. I will also be talking about SOLID Software Design Principles and lots of other stuff like re factorization of legacy code and unit testing.

Keep tuned!

No comments:

Post a Comment