Saturday, April 28, 2012

Why Writing Tests is Fundamental to Computer Programming

A typical day in the life of a student of life involves trying to gather information about whether what a person says about himself, and our own ideas about that person, are accurate. One simplistic example involves getting a sense of a person's experience and background in the hard sciences by presenting the following word to him or her, without alerting the person that they are being put on the spot:
Most people might see the word union-ized, but a high school or college student who has spent some time with the periodic table, or someone in a laboratory, working with protons and electrons, would know about the tendency for some atomic elements to gain or lose electrons to other atomic elements, according to an atom's orbital shell; they might see the word as un-ion-ized. A person who works with her hands, or perhaps a labor law paralegal, who has experience in workplace discrimination or worker injury cases, or who served as a mediator in employment contract negotiation, may see union-ized. If a person says he is a chemist, and, in an unguarded moment, immediately sees and pronounces the word as union-ized, then you may be dealing with somebody who may be less than what he says. If a person says he is a community organizer, and pronounces the word as un-ion-ized, you may be dealing with someone who may be more than what he says.

Students of life that we are, you should already know much about studying for and taking tests and quizzes against a clock deadline, with observers making sure you have no unfair advantage, and the numerous assignments, problem sets, term papers, group projects, oral reports and other homework required of you at educational institutions, for which you then receive a score, grade or mark for your efforts. The American education system administers standardized PSAT and SAT or ACT tests in reading, writing, and math for students on the college track, which give you an idea of how well you performed answering verbal and quantitative questions in a controlled setting, in comparison with your peers. The people who paid for the test systems to be created and administered get an idea of what you know and whether you know how to use what you know to solve problems.

Whether you like it or not, you need to make space in your life for tests, either testing other people or being tested yourself, so that you're always subjecting your assumptions to scrutiny, making sure that the model of the world you have in your head corresponds to reality. In this way, you help decrease the probability of encountering unpleasant surprises in your daily work that could affect your life in a profoundly negative way. In 2002, Kent Beck introduced his book Test Driven Development, suggesting that the proper way to write computer programs was to begin not by writing code, but by writing a test for what you expect the code to do. Let's say you wanted to write a computer program that helped you pick lottery numbers, let's say for a large Mega Millions jackpot. Here are some expectations you demand must be met, or your code is no good:
  • There should be a total of six numbers
  • The first five numbers should include or be between 1 to 75 (formerly 1 to 56)
  • The sixth number should include or be between 1 to 15 (formerly 1 to 46)
  • Out of the group of five numbers, none of the numbers should be the same as another in the group
If your computer program code has failed any of the tests, then the code must be changed until it can pass the test. If all the requirements are met, then your code is passing all the tests, and you can move on to writing the next test, which might involve figuring out which sets of numbers are winners, or picking numbers for a different lottery game, perhaps the Fantasy 5, or Daily 3, and so forth.

In essence, writing a test involves first setting a minimum standard for your code that must be met, then writing your code and seeing it pass or fail. Writing the test first may seem silly (it certainly did to me for the longest time, and frankly, it sometimes still does), but the idea is that if you begin by writing code, you can spend hours and days optimizing and improving some piece that is not important; you should really be getting into the discipline of ensuring basic functionality is up and running (you can always make your code more terse, elegant and abstract when necessity demands). You want to prevent yourself from getting distracted from the main goal, which is to publish a basic, working prototype. Initially we wanted a way to generate numbers for a specific lottery game, but then we wanted numbers for different lottery games, and to figure out which number sets were wins. As your desires expand and grow, what was a simple computer program becomes more of an involved project, and quickly the program can become an application that is the foundation for a business or enterprise that might involve other programmers who want to look at and change your code. As your codebase grows, it becomes more complex and much harder to maintain, simply because what was once a simple computer program is now doing much more, and depends on more technology, written by other people, that is out of your control, and you may need to have people look over and touch your code. Writing tests first is based on the assumption that, in the long run, untested code requires much more time spent poring over and fixing puzzling bugs, than if you had done the hard work upfront. If your code is not supported by tests, you may have a greater probability of encountering a showstopper, i.e., some hard to find, unexpected problem in your system that prevents you from moving forward and releasing improved versions of your software in a timely manner.

One caveat: writing tests first is hard, perhaps more difficult than writing code first. There is the argument that if you start by writing tests, setting an expectation for what you want to see your code do, you can improve the design, and readily determine what are the essential pieces, and how you want to organize your code so that you can get a better idea when something goes wrong.

In closing, a recent PBS NEWSHOUR story really brought home to me the message of how important it is to create a system that is easy to maintain. A woman who has worked in Africa understands the problem of women dying in childbirth due to lack of light in maternity wards. Her husband, in response, designs a solar lighting apparatus that is portable:
Developing countries are a graveyard of well-intentioned technologies from the First World.

SPENCER MICHELS: Environmental engineer Ashok Gadgil has been consulting with WE CARE Solar. He developed the Darfur Stove that has revolutionized cooking in the developing world. And he's a senior scientist at the Lawrence Berkeley National Laboratory.

He says he's impressed with what he's seen so far, but he says if Stachel and Aronson are to succeed, they must address how the system will be maintained over the long term.

ASHOK GADGIL: No single technology, no single piece of machinery has infinite life. When one wants to introduce a technology into society, it needs social placement. The technology needs links and threads that connect it to a Web of experts or spare parts dealers or maintenance people or diagnostic technicians which will keep it going.

SPENCER MICHELS: How do you know that, after a year, this thing isn't going to get rusted or break or whatever?

Watch 'Solar Suitcase' Sheds Light on Darkened Delivery Rooms on PBS.
See more from PBS NewsHour.