How do you work with really bad code?

Most programmers will at some point have to answer this question. We all like to think that it won't happen to us, but unless you are constantly thinking about how to keep your code good, it will go bad. 

Good code doesn't just happen – You have to make it happen. 

I'm forced to think about this, because I'm way behind deadline on some development because of the bad code in the rest of the system. This is after I tossed out about 50 000 lines of the worst code. I'm still figuring some parts out, so this will be a series of posts on the relevant subjects as they come up. 

I will also write a series on how to write good code at the same time as the ultimate goal is to replace the bad code with good code and make sure that this doesn't happen again. 

The system I'm working on is a Java application with over 600 000 lines of code and practically no unit tests, so the focus will be on how to make changes that will keep increasing the quality of the code base without making radical changes.  While a lot of the code is not great, the system is stable and does work with very few known bugs. The main problem is just adding new features.

To start with, We'll look at what makes bad code and how it happens in this article. Then in future posts, I'll write about:

  • When to throw away code.
  • Refactoring existing code.
  • Writing unit tests and doing test driven development.
  • Using design patterns.

I'll link these once I write them and also add any other topics I think of in here.

What is bad code?

There are a lot of different measures for what makes good and bad code. For me, bad code is code that is unreadable, unmaintainable and untestable. 

To make code that is maintainable and testable, your code should be well encapsulated and loosely coupled. 

Encapsulation means that all the related code for a feature is together (For example, in the same package). Encapsulation is mostly important because it makes your code easier to understand.

Coupling is when code depends on other code. Loose coupling means that related code only depends on the obvious code in the same class or same package. Esentially, if you can compile a single class without compiling anything else, it is loosely coupled. If you need to compile another class, which compiles another class, which has to compile another class, that code is set to be tightly coupled. Tight coupling is bad because it means that a change to a class might affect a completely different class somewhere else in a seemingly unrelated part of the system. This makes it difficult to make any changes in the system. 

Tight coupling also makes it difficult to write unit tests, since each method might depend on methods in a completely different part of the system.

Even if the code works fine, as programmers, we spend a lot more time reading code than writing code. As such, it makes sense that difficult to read code is bad. The biggest mistake is to over complicate things. Don't use more dificult code because it might perform better. Rather use simple code and if there are performance problems, just tune the worst bottlenecks and make sure that you put comments explaining why the more complicated code was used.

On the topic of comments, make sure that comments tell you why something was done, not what was done. The code should tell you what was done.

So how does bad code happen?

The worst time, where code usually goes bad, is after the initial version of your software has been released and you start getting requests for new features. Ad to that tight deadlines because of bug fixing that you didn't anticipate, and most programmers will cut where they can.

There really are only 4 factors that you can realistically change when you are under pressure:

  • Move the deadline.
  • Cut features.
  • Add Resources.
  • Compromise on quality.

Usually, management will not cut features or move the deadline, since they have already started marketing. Adding resources are unlikely to happen in any case, but even if it does, by the time people realise that they are in trouble, it is too late to add more people to a project.

This leaves the only option: Compromise on quality.

Most programmers hate doing this, and doesn't necessarily realise immediately that they are doing it, but that's what happens. 

“Yes, I know this design isn't great, but we have to ship, so I'll just make it work and we can clean it up later.” Sounds familiar? How many times do you go back and clean it up? 

That's called technical debt. And like any other debt, there's interest on it. The longer you leave it, the more it will cost to fix, until eventually you get to a point where everything is too broken to fix and the only solution is to rewrite from scratch. Of course, doing that just starts the process again and you eventually end up in the same position.

Esentially, the only way to keep code from going bad is to put in a conscious effort to leave the code in a better condition than you found it every time you work on it. Even if you only put some meaningful comments, rename a few variables to make more sense or just write a couple of unit tests.

Always look at the code after you worked on it and ask if you made it better or worse.

The Fabled Software Development Plan

iterative developmentLike I mentioned in my previous post, there are no generic software development plan templates. In the same way, there isn’t really some simple software development plan that you can just take and run with. Each company has different needs and each development team does things differently. In the long run, patterns will develop and development methodologies will tend towards the same established methodologies, but they are always subtly different. Continue reading “The Fabled Software Development Plan”

The Mythical Software Development Plan Template

Software development plan templateMost small development companies tend to go through the same chaos when they start out, and then eventually (If they survive this phase), they start managing their development properly.

I see it time and time again. In small development houses, the general approach is to have an idea, rush headlong into development, rush to get something done, and then step back to see what they end up with. During this process, they realize that they missed some killer feature, so the put it in. But while they’re working on this feature they figure out that they missed another feature, so they start working on that at the same time. Because of this the software is never done, and no thorough testing can happen.

Eventually, 2 years down the line, they realize that instead of their 1 week email notifier project, they now have a full fledged email client and Microsoft is their competition. They also realize that because they didn’t do any planning, the architecture is so shaky that they’ll need another six months to fix it before they can release.

At this point, it is time for the “Software development plan template”. They know they have to plan, but have no idea how to do it, so just ask Google for a template. This unfortunately does not work. Most templates you find will apply to a company bigger than yours.

So what do you do?

The problem is that the plan needs to be adapted to your needs and for your resources. These are the main points you need to consider:

  • What’s the scope of the project? How much time and resources can you afford to allocate for this?
  • You need to plan and document the requirements. Decide upfront what features need to be in this release of the software and stick to it.
  • Design the software based on the requirements. You need to document this in a design spec. See Joel’s functional spec information for a brilliant resource and example.
  • Now you need to spec the development and decide on estimates.
  • Review the estimates and see if you can finish the software on deadline. If not, you need to take out features, add more developers, or move the deadline.
  • Do the development. Note that this is only one step in the process. If you’ve done the preceding steps properly, this will be as painless as is possible.
  • Develop a test plan and do the testing. Unit tests should be written as you are developing the system.
  • Once you are happy with the software, develop training materials for the end user.
  • Develop any necessary user documentation. Help manual, installation guide, etc.
  • Beta test. Identify beta testers and deploy to them. Get feedback and decide what actions are necessary. If the software needs to change, go through the above steps again.
  • Plan maintenance and set up any necessary structures.
  • Deploy the product.
  • Review the product as well as the process. Document any lessons learned and adjust your software development plan as necessary so that you will do it even better the next time.

As you can see, there are a lot to consider. Most small businesses focus on the development, but never consider the supporting functions. Even if they do get it right and develop a useful product, without planning for deployment or maintenance, they can become a victim of their own success.

You can get a Microsoft Project software development plan template at this site if you want a starting point for creating your own template.

Starting with Ruby on Rails

I recently rediscovered rails when I needed a holiday project and decided to build a management dashboard for the company I work for. With it being a project done in my free time, I could focus my time on learning the basics rather than trying to build a working project on a tight deadline.

This is how I did it.

Read more on: