Summary
Usually at Artima we focus on how to make code better, but it can also help to see real-world examples of bad code, to help spread understanding of why the code is bad and how to avoid creating such code. What are some of the most common problems you've seen in code, and how could they be avoided?

Advertisement

What would really be useful is classes of coding problems you've encountered, and how the entire class of problem could be avoided if the programmers behaved differently.

I'd like to give an example of what I think should be made available everywhere as a tool for programmers: extreme modularity of executable code.

The monolithic programs that need to be run in entirety to be tested are a PITA. The goal should be to allow the pieces of the program to be run separately all the time, which helps in speeding up the development and the testing.

Think web pages for instance! As popularized by ASP and PHP. The programmer can edit and run the pages in fast iterations. Now expand that to almost all of your program pieces, be it command-line, GUI, or whatever! I have that kind of functionality in my Ruby programs, in GUI, command-line, or Web sites. And I am not talking about TDD, of course.

I think as dynamic languages like Ruby gain popularity, more and more of features like this will become mainstream. The dynamic part is maybe core to the idea.

That is, bad code would be the non-modular, hard to develop, hard to test one.

BTW, I've found the a very modular Ruby library can be reused by allowing pieces to be imported and reused.

One of my latest programs imports pieces from another 5 or so libraries, and the import code can be a one line of code for every imported module, for instance, for adding an external GUI CRUD Table (database) support.

Im not joking. Somebody has implemented a loop to find out how big an array is. I had to read this piece of code several times because my mind kept revolting against this stupidity... The code is correct, so a Unit Test does not help here. IMHO The best thing to prevent such stupidity errors is pair programming.

Here is another fine piece of code where somebody wrapped exceptions into another one:

The problem is that since String is immutable, replace() does not modify the string but return a new one. Again UnitTests are helpful. I also think it is a good idea to have a naming convention for methods to be able to differenciate code that modifies internal behaviour and code that does not. I usually use the prefix calc for every method that does not modify internal state.

The worst code I've ever seen was written by myself. :) I write tons of really BAD CODE (BC), but fortunately I catch the worst of them before letting them out in the wild. Sometimes I write some code, look at it, and go "whoaaa!!!....that is some really BAD CODE!" But that's how every learning process goes, by failing and trying again. And we all know we're never done learning when it comes to the art of programming.

Many moons ago when I was an FCS/EPS programmer I had to take over a management accounting and budget suite. FCS was all the worst parts of line numbered BASIC with a Fortran variant called TABOL thrown in and a whole lot of other shit.

The 'suite' was a singe file called it2logf (you can see that after nearly two decades it is still fresh in my mind) that stored it's data in a single data file called llabtoof (football backwards). However to handle multiple years accounts and budgets the program would change directories to, say the 1984 accounts, read some data from llabtoof, change directories to the 1985 accounts, read some data from llabtoof, and then change into the 1986 budget directory read some more data, from the llabtoof file there, and then do come calculations, by calling calc(1000,'123') - which would execute lines 1000 to whatever line number was held in line number 123 - and then write the data to llabtoof.

Actually FCS wasn't a bad language for mainframes but it made C look like extreme bondage.

> I'd like to give an example of what I think should be made> available everywhere as a tool for programmers: extreme> modularity of executable code.> > The monolithic programs that need to be run in entirety to> be tested are a PITA. The goal should be to allow the> pieces of the program to be run separately all the time,> which helps in speeding up the development and the> testing.

if that *really* made life *really* better, Mach would be the OS of choice. last I heard, it had withered away. sometimes one big ball o stuff works better. not that it's easier to fix/extend. but goes faster. faster is better, to most folk. and for programs that are expected to run mostly unchanged for a long time (think, mainframe OSs), the trade-off of ease of mod loses to speed.

(the casts may not be quite right, but the string-buildup anti-pattern is the thing to notice)

My other favorite was not bad code so much as it was functionality. I was working on a team whose client-side software for TV stations would dub a "playlist" of MPEG-2 files to an RS-232-connected VTR by programmatically turning on the VTR's record and playing the files one by one. The dub was kicked off by a clicking a button in the GUI. Guess what? The original developer kept the dub on the AWT event-dispatch thread. Meaning that, until the last MPEG-2 had finished playing, the entire GUI was frozen, not even repainting if you switched apps and allowed other windows to overlap onto ours.

There was also a fabulous bug in this code that didn't check the NAK back from the VTR and was sloppy about CRC's, so sometimes "play" commands would turn into "rewinds", for reasons too detailed to get into here. Still, funny bad.

Oh wait, no, there was the code to keep a directory a certain size by deleting enclosed folders based on age of contents. Except it kept the queue as a textfile inside the folder to survive restarts. And sometimes that queue file itself would be the next thing to delete, and the entire enclosing folder would be deleted, and then someone would be on the phone asking us where their last two days' of video went.

Ah, good times. I take it we're all agreed that ugly code that behaves correctly is still preferable to pretty code that misbehaves.

My favorite bug of all time was in a backup script I have written. I used it to backup my important data each day at 3am. After more than half a year of perfect operation it suddenly destroyed all my backups. It took me a while to find the bug: the reason was that end of march here in europe we have daylight savings, so at 4am the computer switched back again to 3am, so it the backup program was called twice with exactly the same time. I did not foresee this case and it caused great havoc.

> (the casts may not be quite right, but the string-buildup> anti-pattern is the thing to notice)

That and reading one byte from the stream at a time. It's too common to call it the 'worst', though. Actually, in recent versions of Java, this doesn't even cause that much havoc because of GC improvements. It's still slow but what is worse that this is the code where the developer has decided that he or she much ALWAYS use a StringBuffer.

The worst code that I have worked with was for a company that had an interesting approach to source code versioning. They copy and pasted the old version within the current code base sometimes commenting out the old code, sometimes keeping it in an uncalled function, sometimes after a unconditional return or in a if(false) block.

It was not the first or last time I was to run across this anti-pattern but it was the most extreme example I have come across. The majority of Modules had 3 or 4 obsolete copies and one had 15.

I had zero luck convincing management that they should use source control software.

I saw a lot of bad code in the last 10 years. And I agree, one can learn a lot out of it. I am actually producing article about the things I´ve learned, coming soon, but I cannot show the code that brought me onto the insignts I gained.

A very shocking thing to me was, that bad coders easily and quickly can dominate a project, maybe that´s the main reason they keep doing it. More shockingly was the fact, that there are quite a lot of people, who just don´t want to improve it. Ignoring Books, Article, Design Principles, etc.

So, working with those programmers can be very painful but this way one gets a very strong and concrete view on what can happen. However, I quit.

All those programmers had something in common: They mentioned things like: "What do you want, it compiles", or "You can name it as you want, names are not important at all", and so on. The main reason for the madness is the lack of some idea, i.e. completeness paired with minimality, or a too formal understanding of encapsulation without without getting in the head that an object represents a concept and so on.

However, I don´t look at the code alone, but also onto the programmer who produced it, and I can say that the way they look at the world is directly related to the way the code looks. Every bad code is bad in his own way. Good codes do have something in common.