Trust me, I get it. I’ve been there. You’ve got a project due and you are struggling to get it to work. It just needs to work. It doesn’t need to look good. The instructor isn’t going to grade how well (or poorly) you created your assignment. That’s not the requirement. The requirement is only that it works, and the deadline is approaching.

So … why do you need to practice good software engineering?

Let’s look at a couple examples, shall we?

Magic Numbers

Principle: Don’t use magic numbers

A magic number is a number that is neither one nor zero, and yet it gets placed into your code with no explanation.

Years ago, I had the opportunity to sit next to an engineer who was trying to maintain a piece of software that predicted certain properties of the ionosphere. The code he was working on had been written decades earlier, and it contained tables of numbers within it. These tables, however, came with no explanation as to how they were derived. The engineer working on this task showed these numbers to me and asked, rhetorically, how shall I know if these numbers are still valid?

While it’s easy to argue that good software shouldn’t include numbers with no explanation, such as this program did, what about throw away software? Software that only needs to work once?

To answer that question, consider the example of a student who was trying to implement a CORDIC algorithm for class. As you may recall from our discussion on how to build a CORDIC algorithm, such an algorithm depends upon a table of arctangents. This student had dutifully calculated and placed this table within his code.

	atanhAngles.push_back(255412811);
	atanhAngles.push_back(125657214);
	atanhAngles.push_back(62581571);
	atanhAngles.push_back(31260178);
	atanhAngles.push_back(15626271);
	atanhAngles.push_back(7812658);
	atanhAngles.push_back(3906269);
	atanhAngles.push_back(1953127);
	atanhAngles.push_back(976562);
	atanhAngles.push_back(488281);
	atanhAngles.push_back(244140);
	atanhAngles.push_back(122070);
	atanhAngles.push_back(61035);
	atanhAngles.push_back(30517);
	atanhAngles.push_back(15258);
	atanhAngles.push_back(7629);

He then asked why his code wasn’t working.

Looking over his code, it was impossible to know if he had gotten the table right. I didn’t know what formula he had used, or even if he had gotten the formula right or not. Further, aside from the problem associated with knowing that the table was correct, there’s also the problem of fixing the table once you discover an error since you would then need to correct every line in the table. Oh, and did I mention that copying tables by hand is prone to error in the first place?

Consider the alternative, shown below:

	for(int k=0; k<32; k++) {
		int32_t	ival;
		double	tanv, drad, atnh;

		// We want the arctan of 2^(-k-1)
		tanv = (1<<(k+1));
		tanv = 1/tanv;

		// The angle, in radians, for the arctangent
		drad = atanh(tanv);

		// Scale this angle to 0..2^N-1 units, for N=32
		atnh = (drad/2.0/M_PI) * (1<<30)*4.0;

		// Convert this value to an integer
		ival = (int32_t)atnh;

		// Stop if this integer ever becomes zero
		if (ival == 0)
			break;

		// Add this value to the table
		atanhAngles.push_back(ival);
	}

Look at all of the math involved in getting this table right. Consider what would’ve happened if there was just one error in this code above.

For these reasons, I will recommend that student’s not use pre-generated numbers within their code. If you really need a table of numbers for your application (this is pretty common), then I would recommend that the code necessary to populate your table also be distributed with the magic numbers.

The rule of one (not three)

Principle: Don’t repeat yourself.

If you have to build an algorithm, build it once. Build it right, use it everywhere, but don’t repeat yourself.

Wikipedia refers to the rule of three in computer programming. The basic rule is that once you have three copies of the same algorithm, then it is time to refactor all three versions of the algorithm so that they reference the same single piece of working code.

Allow me to argue that this rule applies even more to students, and especially to code that hasn’t been proven yet–code that may still be buggy.

Years ago I watched this lesson play out in a computer engineering course. Computer engineering, for those unfamiliar with it, is sort of a cross between computer science and electrical engineering. As a result, the course included both individuals with a computer science background, such as myself, and others with more of an electrical engineering background. The projects in the course involved building various circuits with computer chips and peripherals, and then programming the computer chip within those circuits to do some instructor provided task.

What I remember from the course is being surprised at how little the electrical engineering students were re-using their code. We were writing code in 8086 assembly at the time, and an example piece of code might be the software necessary to send a string over a serial port. My approach was to convert any code that I needed more than once into functions that could then be called as often as I needed them. I considered this to be a standard computer science principle.

What I observed was that the electrical engineering students ended up spending a lot of their time debugging the same software over and over.

Please don’t get me wrong, I’m not trying to be critical of all electrical engineering students. I’m just commenting about those I shared this class with who were kind enough to allow me to look over their shoulders. While it may be that these students hadn’t yet learned this fundamental software lesson, I’d like to think that other electrical engineering students know better.

The problem is that buggy code needs to be fixed, and buggy code in more than one place needs to be more than once. Worse, if you aren’t (yet) certain that the code in question works in the first place, and you are searching for bugs, then it’s really easy to let a bug in one copy slip by you as you fix the other copy.

Time is tight, don’t waste it.

For this reason, I recommend the rule of one for students and anyone else trying to get something to work for the first time. Build it once. Don’t copy it—especially don’t copy it before you know that it works. Make a function and call that function instead.

This also applies to the FPGA designer: reuse logic by separating it into its own module rather than copying it multiple times across your code–especially before you know whether or not the logic even works, or if it is the right logic for the job.

Data Types

Principle: Store items with different meanings in different data types.

To put things simply, let the compiler (or synthesis tool) find as many bugs for you as you can.

I know, I’m a die-hard C-programmer who uses Verilog rather than VHDL. You might find it strange to hear this advice coming from me, but I’ll say it anyway: let the tools find as many errors as you can.

Use software data types to your advantage. If a value will only be one of a handful, use an enumerated type (in software) or set the number of bits for that handful to the smallest number required in HDL. If you have values occupying, for example, several stages within a CORDIC, each having x, y, and angle values, then don’t store those in an array. Use a structure.

In Verilog, run verilator and use the -Wall option.

You can do the same in C++: Turn on the ‘-Wall’ compiler option.

Software data types are there for a reason–use them to your advantage.

Pi is not 3.14159

Principle: Use the tools library to your advantage

I remember hearing a sad satellite story from years ago about the difficulty that the ground team was having while trying to track their satellite(s). Sadly, the details of this story have left me. Perhaps someone else remembers and can fill me in. What I remember from the story, though, was that when all was said and done the problem was the software that declared PI to be 3.141.

On my Linux machine, PI is defined in math.h as

#define M_PI               3.14159265358979323846  /* pi */

Use this definition. Even for students: use this definition. Get into the practice of using your tools–they are there for a reason.

Be kind to others–your grade depends upon it

Principle: Don’t bite the hand that feeds you.

I’ve had the wonderful opportunity to help many wayward students over the years. The one thing that turns me off, however, is the student who is gets frustrated and then angry at whatever difficulty he is having. This angry student will then show up on whatever forum looking for help. He’ll swear at himself, he’ll yell, and destroy his own online reputation.

Sometimes these individuals turn to the forums spewing filth at whoever built the tool he’s using. At this point, it doesn’t make a difference if the tool is good or bad, this individual will turn others off from helping him.

If you are getting angry then go take a walk. Get some exercise. If it’s late at night, get some sleep. Come back to the problem later when you have a clearer mind.

The last thing you want to do is to proclaim to all that you are hard to work with, particularly when you need some help from others.

Patience

Principle: And not only so, but we glory in tribulations also: knowing that tribulation worketh patience; and patience, experience; and experience, hope (Romans 5:3-4)

Yeah, I get it, your project is do in a month, in a week, or even tomorrow. I understand. It’s late at night and it isn’t working. I get it. I’ve been there. However, getting stressed or anxious about it isn’t going to help you get your design working any faster.

Sound engineering requires diligent patience, discipline, and careful attention to the smallest details. This takes time. It requires a cool and level head. Engineering problems can be subtle. They can hide in the difference between a ‘0’ and a zero. Give yourself the time you need, and don’t try to rush the job—even as the end is imminent.

Corrolary: Give each project the time it needs.

If you can’t rush a project at the end, then front load the project and give it the time it needs early on so that you don’t end up rushed at the end. If your instructor gives you a couple of months, then trust him: he might know something. Start early. You won’t be able to recover any wasted time later.

Prayer

While I’m sure there are many other software engineering principles, I’d like to close with a final observation. There have been many times when I’ve personally gotten stuck on one problem or another. Maybe it’s getting late and, after a long hard day, I still haven’t gotten a problem working.

Let me share with you my personal secret weapon: prayer. Put the project down and take some time to pray. Trust God to take care of it, and then get some sleep. In the morning, pray again before returning to the problem.

You’ll be amazed at how prayer both changes your outlook, as well as how God can just suddenly reveal key details to you that you were missing before.