Testing Effectively With Legacy Code

Testing code isn't the easiest thing in the world, and it gets even more complicated when working with legacy code. This chapter explains the theory behind modular coding and how testing can be difficult in this environment.

This chapter is from the book

This chapter is from the book

One of the things that nearly everyone notices when they try to write tests for existing code is just how poorly suited code
is to testing. It isn't just particular programs or languages. In general, programming languages just don't seem to support
testing very well. It seems that the only ways to end up with an easily testable program are to write tests as you develop
it or spend a bit of time trying to "design for testability." There is a lot of hope for the former approach, but if much
of the code in the field is evidence, the latter hasn't been very successful.

One thing that I've noticed is that, in trying to get code under test, I've started to think about code in a rather different
way. I could just consider this some private quirk, but I've found that this different way of looking at code helps me when
I work in new and unfamiliar programming languages. Because I won't be able to cover every programming language in this book,
I've decided to outline this view here in the hope that it helps you as well as it helps me.

A Huge Sheet of Text

When I first started programming, I was lucky that I started late enough to have a machine of my own and a compiler to run
on that machine; many of my friends starting programming in the punch-card days. When I decided to study programming in school,
I started working on a terminal in a lab. We could compile our code remotely on a DEC VAX machine. There was a little accounting
system in place. Each compile cost us money out of our account, and we had a fixed amount of machine time each term.

At that point in my life, a program was just a listing. Every couple of hours, I'd walk from the lab to the printer room,
get a printout of my program and scrutinize it, trying to figure out what was right or wrong. I didn't know enough to care
much about modularity. We had to write modular code to show that we could do it, but at that point I really cared more about
whether the code was going to produce the right answers. When I got around to writing object-oriented code, the modularity
was rather academic. I wasn't going to be swapping in one class for another in the course of a school assignment. When I got
out in the industry, I started to care a lot about those things, but in school, a program was just a listing to me, a long
set of functions that I had to write and understand one by one.

This view of a program as a listing seems accurate, at least if we look at how people behave in relation to programs that
they write. If we knew nothing about what programming was and we saw a room full of programmers working, we might think that
they were scholars inspecting and editing large important documents. A program can seem like a large sheet of text. Changing
a little text can cause the meaning of the whole document to change, so people make those changes carefully to avoid mistakes.

Superficially, that is all true, but what about modularity? We are often told it is better to write programs that are made
of small reusable pieces, but how often are small pieces reused independently? Not very often. Reuse is tough. Even when pieces
of software look independent, they often depend upon each other in subtle ways.