My code works, and I’m not satisfied until the user is satisfied. I’m not saying that I’m a miracle worker, but I do have a number of principles that have enabled me to succeed where others have given up.
Understand the user
I started in engineering and have worked with management, software development, research, operations, sales, and a variety of other groups. It may take a little work, but you can eventually get them to tell you what they want. It amounts to getting their work done faster and with less effort, making customers and management happy, and avoiding surprises. There are differences, but there are far more similarities. Also remember that the developer will have an easier time understanding the user than the user will have understanding the software.
When the user describes what he thinks is a bug, listen. When working in the chemical industry, I often found that the operators were correct about what was happening, even if they were wrong about why it was happening. “He yelled at me” is not a good reason for not listening. I usually take it as a sign that he cares about whether things work, and he will yell a lot less if I listen to him.
Know what’s easy and what’s difficult
One of the biggest problems that I have seen when communicating with users is that they don’t understand what’s easy and what’s hard in the development of software. There are often things that are easy to do in the software but very difficult for the user. There was one application where the mail room received multiple copies of a few dozen reports and they had to create packets for each of the recipients. I changed the software to collate the reports by recipient and the mail room was ecstatic. It only took me a few days but it saved them weeks of effort. They didn’t realize that the reports could come off the printer sorted by recipient.
On the other hand, some things are very difficult to do in software, such as voice recognition software and character recognition for handwritten notes. If you explain the problems, you may find that the requirement is not as important as originally reported. Furthermore, there may be an alternative that’s easy for software to carry out and still meets their needs. For example, it would be difficult to extract the “From” field on hand written notes sent via facsimile. On the other hand, the computer can sort them by the telephone number of the fax machine that sent the note.
Use your experience
I’ve been working in software for many years and have seen many problems. There are very few that are entirely new. A fellow programmer was having problems with a program that was going into an infinite loop and asked for my help. I took a quick look at the program, pointed to a line and asked him if that was what he really meant. He looked at it, and asked how I could have read the program so fast. I told him that I didn’t know what the program did, but the line was a complicated mass of nested arithmetic and logical operations, and that was where errors resulting in infinite loops were usually found. I had a few other cases where the other person was amazed at what appeared to be magic. In almost all of the cases, my explanation was the same: that was what the problem was the last few times I encountered it.
If your experience can’t solve it, ask others. Don’t be afraid to let people know that you need help. In one case, I asked for help with an algorithm for processing medical data. When I explained how my code worked, he said that I was using the wrong reference value for one of the measurements. When I followed his suggestion, I obtained the correct answer. It turned out that there was an error in the reference documentation for the equipment.
In another case, a magazine article mentioned how there was a requirement that an equipment room be accessible in an emergency, but entrance had to be prevented at other times. (The employees were using it as an unofficial smoking lounge.) The article went on to state how it was impossible to satisfy both requirements, a statement that I found hilarious. You simply put an alarm on the door. People know that opening the door will set off the alarm, and they won’t use it unless it is an emergency.
Not a perfectionist
I am not a perfectionist. I merely want a close enough approximation such that nobody else can tell the difference. It’s actually not as difficult as it sounds. Management will sometimes tell you to only handle the serious problems, but there is no way to tell with certainty which problems are the serious ones. There was a program that could be compiled for two different computer architectures, but it was only working for one of them. I found an addressing error in the code that caused it to crash on one system but didn’t cause any noticeable problems on the other. When I fixed the bug, it worked fine on both systems. The problem is that I don’t know if the results were correct on the system where it was working. Ignoring error messages has been known to cause deaths in some situations. (See Therac-25) If web application crashes once a week and has to be restarted, do you really know what happens when it crashes?
It may be that time constraints prevent you from fixing some of these problems. However, they should be noted and fixed when you have the time.
When you design a database, there are some rules called Codd’s Rules of Normalization. Sometimes you have to break the rules in order to improve performance. I remember a heated debate with a database “expert” who argued that you always follow the rules even if it renders the application non-functional. This is what I call religious fanaticism in software engineering. (By the way, data warehouses are a violation of the normalization rules.) I am not a religious fanatic. In this case, I believe that the reason for the violation of the rules should be stated in the documentation, together with possible problems and how they should be handled.
Other fanatics will specify the use of frameworks or software libraries because they feel that that is the current technology for all applications. Using a tool or method because other software components work that way may actually be justified because it limits the number of packages for which the maintainers have to maintain proficiency. However, using packages such as Spring, Struts, JavaServer Faces, Facelets, or the current fad of the day because it is the current fad of the day is rarely a good idea.
Fanatics will also tend to mention things like agile programming, extreme programming, Six Sigma, and the SEI’s Capability Maturity Model as if the proper incantation of the mystic rituals will achieve success. These are frameworks for thinking about processes, and, in my opinion, the key word is “think”.
Look for tools, not solutions
I will often use Google or go through my reference books to find a solution to a problem. However, I don’t really expect to find the solution. What I expect to find are the tools that will enable me to build a solution, and I keep looking until I find them. That is how engineering really works. The reason that most people give up is that they can’t find a solution and using the tools to build a solution is hard work. When you look at it, the engineering process works for both bridges and software and can be thought of as having the following steps.
- Observation – Collect relevant observations about the problem
- Decomposition – Break the problem into smaller pieces
- Analysis – Examine the pieces and how existing tools can deal with them
- Synthesis – Construct a design for the solution
- Implementation – Convert the design into a solution