Introduction

A little over a year ago, I moved from a free-wheeling web development job to a more technically demanding job at Johnson Space Center. I was very optimistic about the experience and the cool technologies I would get to see.

Most of all, I was ready for a chance to work for an organization that enforced uniform coding standards. For those of you that do not program, coding standards are important. It can be the difference between spending an hour or two debugging a problem and spending a week understanding what is going on before you even can start debugging a problem.

I was not let down. My first week, I was given several documents that delineated the code practices at NASA. For three months (until I received my security clearance to actually log in and work) I read about the processes that NASA put in place for engineers to get things done. The documents had great suggestions.

Then I logged in and began maintaining existing code. The first sign of danger was the entire code base is written in C, while the vast majority of JSC software is written in C++ or Java. C is not necessarily a bad language, (in fact is it a very powerful language) but it will let you do just about anything you want, anyway you want without checking up on you at all. It fosters an attitude of clever solutions to problems and, because it lacks many of the built in benefits of object-oriented programming, these solutions will often be repeated, line for line, in different files.

My system, for security reasons I will call it the Current Resource Analysis Program (formally a piece of the System Heuristics Information Tracker), was a hodge-podge of different programmers being clever.

Clever

I should explain that clever is not always a good thing in programming. A clever solution often solves a problem in a manner that no one has before utilized. Sometimes a clever solution will get the job done in fewer lines (sometimes referred to as elegance) than another less clever solution. Many times, clever programmers fail to properly comment clever solutions, making them impossible to figure out unless you know the original programmer or spend some quality time with the code and a debugger. My first point, with regard to coding standards, is that if you want to be clever, you had better document what you did for the poor schmuck that follows after you.

I will give you an example of a clever solution that is currently executing in my system, the CRAP:

v.d = ((double)*((unsigned long*)(dc->d[i].v[j]))) + 0.0;

Ah. So elegant. It gets the jobs done and does so fairly quickly. This statement properly takes the value stored in the value array and converts it to a usable double. One problem though: Why, in God’s name, do it this way? Leaving the poor variable names for later discussion, why the cast/deference/pointer cast of a value that is only used here? I am not sure if this is clever or ridiculous, but is more indicative of the programming choices made by CRAP developers.

Variable Naming

for(ss = s->ss; ss; ss = ss->ss);

What the heck:

Does s stand for?

Does ss stand for?

For those of you that are interested, the line traverses a linked-list of sources and sub-sources to process the values inside (loop block omitted). But it took a good deal of research to figure that out, because there were no comments and the variable names, well, suck.

This brings me to my next point about coding standards: Names (method, function, class, variable) are important and programmers should not overlook them.

Most of the variables in CRAP are one or two letters long. Originally, this was due to the memory constraints involved when programmers first designed and built the system. Some of the code guilty of one and two letter names was written in the late nineties. The explanation told to me was that CRAP programmers took it as a badge of pride that their code was so hard to understand and it was a sort of initiation test to new team members to understand the code despite the poor variable names. (My current teammates and I are currently rectifying this issue, but CRAP is a big system and it still is not always clear what dc or v do.)

If you have a variable that is a rating of employees at an organization, organizationEmployeeRating is not a ridiculous name, while eratingis.

If you have a method that calculates the risk of an investment, name it calculateInvestmentRisk(), not risk().

A name should inform what the code selection does without needing to have intimate knowledge of the program.

Code Comments

A college professor at Texas A&M, Dr. Salih Yurtas told us that he believed comments were useless. His argument was that people rarely pay enough attention to code comments and that since developers often add them at the last minute after the program is finished, they are often incomplete. In its place, he suggested that code should be self-documenting instead. Whether you want to comment your code or not, self-documenting code is a good habit to get into.

Source Formatting

Many programmers need not worry about this anymore with IDEs like Eclipse and .NET offering functions that will automatically format your code for you. Me? Here in the space program we code in good ol’ vi, or gvim if we are lucky with our terminal.

Source formatting is usually dependent on the language you are using, but the most important thing is that everyone on the team (or in the organization if necessary) agrees on a standard format for code. Poor or variable formatting can create difficulties in understanding code until familiarity is gained with a certain piece of software.

CRAP has all of the following ways of defining an if-else statement:

if(test) do_something()
else dont()

if(test)
do_something()
else
dont()

if (test) {
do_something()
} else {
dont()
}

if(test)
{
do_something()
}
else
{
dont()
}

First off, use brackets. because if your if statement goes from:

if(test)
do_something()

to

if(test)
do_something()
do_something_else()

You probably are not going to get the functionality you were expecting. Second, brackets let other programmers know what you intended the scope of a statement to be.

But most important is that everyone agrees on a style and that they communicate that style to any new hires that may in the future work on your system.

Indirection

David Wheeler once said:

All problems in computer science can be solved by another level of indirection 1

And Kevlin Henney answered

…except for the problem of too many layers of indirection. 2

Indirection (and its cousin Abstraction) is a supremely useful tool in programming. C programmers often fall prey to the fault of too much indirection. Consider the example s->ss->dc.d->v + i. If that seems incomprehensible to you, join the club. The C programming paradigm does nothing to help this monstrosity, but in general this many layers of abstraction is just a poor design. There are times when a problem will require something like this level of complexity, but during those times, ensure that the variables are meaningful and that the line makes sense. If you cannot do that, rethink the logic.

The other side of C/C++ indirection is pointer logic. Pointers are powerful, but dangerous. For now I will just say try to stay away from statements like:

Further Information

This is really a very small piece of what good coding practices entail, and some of the ideas presented are nothing more than my preference. Coding Practices help extend the lifetime of a piece of software by easing the effort required to maintain it. It also helps extend the lifetimes of software engineers tasked to work on it.

In the mean time, there are many excellent guides available for coding standard ideas. A few that I have found useful are:

Good God, I feel your pain! I’m currently working for a major defense contractor and I see a lot of that going on in some of the device driver code. (well, not as much anymore, but 10 years ago it was insane)

You’d get things like a variable called “data” that is of type InfoStruct and a variable called “info” that is of type DataStruct. Both struts contain pointers called either data or info that point to a variable of the other type. No comments. Comments are for the weak! (sarcasm)

That kind of thing makes programmers violent. I prefer less elegant code. “Sophisticated as a club to the face” is my mantra.

Any kind of convention, whether it’s Literate Programming, Self Documenting Code, or or even just a strictly maintained indention and style guide is vital.

On the other hand, I worked on one project in ada where they required us to write the comments and tests for the 25% code review and not a single line of code, (well, other than function stubs) just to impress upon us how seriously the project lead took proper documentation and testing.

You should have plenty of content to contribute to the DailyWTF at least.

A college professor at Texas A&M, Dr. Salih Yurtas told us that he believed comments were useless. His argument was that people rarely pay enough attention to code comments and that since developers often add them at the last minute after the program is finished, they are often incomplete. In its place, he suggested that code should be self-documenting instead. Whether you want to comment your code or not, self-documenting code is a good habit to get into.

I find this interesting. At Georgia Tech, one of my profs is a co-PI working on NS3, a complete rebuild from the ground up of NS2 (a very poorly commented Network Simulator). The biggest debate topics they have happen to be over “coding ettiquette” and proper commenting. Coincidentally, the prof was one of the original authors/coders of GTNetS which is considered one of the top network simulators around because of its extensive documentation and comments…people seem to pay attention when comments are good and raise hell when comments suck…..

I find that my coding practices are much better since I started using TextMate. I’m far more likely to use a nice long name for a variable when I only have to type it once and then just the first letter or two and then hit esc to auto-complete it.

I really like writing in Ruby too. Take the OmniNerd application for example. It’s pretty large and not something I work on every day. I don’t write tons of comments, but I find with Ruby it’s not as big of a deal because the code is more like English. A trivial example is making good boolean names and using the short “if” syntax. So you could have “this_is_a_valid_statement = true” and a counter called “position = 0” and then later write something intuitive like “position.next if this_is_a_valid_statement”. I find stuff like that needs no commenting, whereas something like “if(x==1){p++;}” is just cryptic even if it is simple. So when I come back to some Ruby code that I wrote over a year ago, it’s very quick for me to pick up where I left off due to the readability. When the application was in PHP, this was definitely not the case.

On this general topic, let me offer a plug for the book Clean Code, by Robert C. Martin.

Aside from the absolutely horrible chapter on error handling (which was contributed by Michael Feathers), the book has a lot of sound advice for writing good, clean, readable and maintainable code.

More importantly, much of the advice is concrete and actionable—it’s not vague platitudes like “use descriptive names”, it spends an entire chapter on what makes a good name.

Read this book (just skip chapter 7), and the next piece of code you write will be better. Get the whole team on board and the whole project will be better.

I know I sound like an advertisement, but clean code is something of a soapbox issue for me, and this is an excellent contribution to the subject. I just can’t imagine what possessed Uncle Bob to use that abysmal chapter on errors, though.

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.

“If you have a method that calculates the risk of an investment, name it calculateRiskInvestment(), not risk().”

Functions that have no side effects should have nouns or noun phrases for names, with the noun describing the return value 1. Save the verbs for functions that change state. A better name is simply “RiskInvestment”, or, for those who like some space between words, “risk_investment”. The word “calculate” is superfluous (everything you’re doing is a calculation of some sort); it reduces readability because you have to read half-way into this long name before you get to something that has some information content.

1 An exception: side-effect functions that return Boolean values are usually better named with adjectives or adjective phrases, e.g. the “empty()” (could be “is_empty()”) method of C++ STL containers.

dont need comments if you understand programming, should be a quick glance and you understand what it does.

Ive spend 25+ years writing code from games, control systems, compilers, satellite receivers to police sirens, ive worked from scratch with no spec except what the hardware designer wants, i worked from a 1000 page specification, ive worked on an idea with no input from the client, “we need something to do this”

And all along ive had programmer who keep asking, “Why dont you comment your code more”, my answer is that if they need comments to work out what the code is doing they should find another easier programming job.

Ive also worked with a 18 year old french guy whom was the same as me, i gave him my code, he added in features, gave me the code back, i added more features, and not once did we need to have “comments” to tell the other person what was going on,

To me you can either read and understand the code or you cant, if you need lots of comments to understand the code your working on you need to find a simpler project.

1. Avoid nesting loops. Refactor the sub-iteration to a separate method. It will eliminate the possibility of using the wrong index variable or inserting statements in the wrong scope. It will also make the code easier to understand.

2. Avoid nesting conditionals. Combine them into a single boolean statement if possible, or better yet, check disqualifying conditionals for a chance at returning from the method early or continuing a loop early. Your computer science professor told you to only have one return statement in a method and never use breaks or continues. He was completely wrong. Used correctly, these create more readable and much less error-prone code.

3. In general, keep code as “flat” as possible. Commenting closing brackets isn’t a good solution. It doesn’t work and everybody knows it.

4. Comments should never describe what code is doing. They should describe why the code is executing. They should help the programmer understand a system or customer process better. They should provide information that can’t be provided in the code itself. I can’t tell you how many times I’ve seen:

I think mainly he is complaining about his lack of experience using C. I used to think other peoples code was CRAP before I had any experience. I’m sure I would think the same way again if I tried to jump disciplines to web development.

1. Any experienced programmer should see the linked-list-walk pattern leap right out at them from that code
2,3. s is the head of the list and ss is the current node, and you can tell that without even having to look up their datatypes; anything else you want to know about the nodes themselves you’ll have to look up the type defintion.

Also,

For those of you that are interested, the line traverses a linked-list of sources and sub-sources to process the values inside.

4. No it doesn’t. You put a semi-colon at the end of the for, closing the loop, so actually it just walks directly to the last node in the list. Then falls off the end, uselessly leaving ss as NULL. ROFL, I imagine you didn’t mean to do that, but attention to detail is actually quite important in programming.

If that was the worst example you could find, that and a few bits of bad formatting and some under-informative variable names, it seems your problems are trivial and could be more or less entirely solved by mechanical refactoring. And frankly, when you’re dealing with some code that deals with concepts like empoyees and ratings, “erating” should seem more obvious to you in context.

The things you mentioned are perfectly fine and acceptable. The only things you mentioned with possible merit is the notion of using curly braces to avoid accidentally inserting code outside of the scope of a block that is being evaluated either iteratively or once (e.g. succeeding an if statement) and using the C++ STL, although the C++ STL is not available in C for obvious reasons.

Everything else you said demonstrates a complete lack of understanding when it comes to programming and if you need to spend weeks figuring such simple things out, you are in the wrong line of work.

To illustrate just how bad your education is, I am a computer science undergraduate student and I recognized what “for(ss = s→ss; ss; ss = ss→ss);” did without issue. I guess I have the C class I took that is neither required nor an elective for my major to thank for that, but honestly, I have written plenty of C code for fun and many times, I found myself writing statements identical to that (with different variable names and with a block in place of the the semicolon; otherwise it is the logical equivalent of “ss = 0;”).

By the way, since I feel like practicing my Latin; here is a maxim you should learn:

The syntax of a C(++)-like language lacks the expressiveness to explain all sorts of things you need to know before you understand any nontrivial program, including the meaning and purpose of its abstractions, assumptions about what is going on in the rest of the program when a method is called, constraints on how mutually-dependent entities may interact, the possible ways the state of a program may evolve (it’s not just a disjunction of all the states each object, considered individually, could be in)… A design-by-contract language like Eiffel might help with explaining some of these things, but I’m sure it cannot cover everything. I leave the question of whether such information should be in code comments, or elsewhere, as an exercise for the writer (look up ‘literate programming’ for an approach once championed by Knuth.)

On the other hand, one has to assume a certain level of knowledge of both programming and the problem domain, or else writing the documentation would become an impossible task. Deciding what to comment (and how) is a matter of judgment that cannot be reduced to painting-by-numbers coding standards.

After reading so many of the snarky, self-important replies to this, I felt I should say I actually do like C. C was my first experience with programming (in high school and college). C-style languages are my preferred tool when approaching a problem. That is one reason why all of our scripts are written in Perl now instead of bash or ksh or other shells… I like the C feel of the code. Of course, I apparently fail to write classic (ie using conventions created in the 80s when lack of memory was a problem) C, but I still like C nonetheless.

VB makes me want to kill myself in its efforts to make the code understandable to the everyday joe.

But in this day and age, when you use one letter instead of a word, you are just being lazy (and I am not talking about iterators, psychos), or trying to keep your job by ensuring that no one who comes after you could maintain your code.

For the other posters who are against writing code that us idiots at NASA can understand, I found a link to your standards document. A good read. Too bad I didn’t include it in the references section.

I worked at JSC as a contractor for 7 yrs on real-time fight control systems and mission control center code used around the world, on the shuttles and space station.

While I can’t comment specifically on the CRAP system or any other that I didn’t work, I can assure you that for the 4 systems on which I worked with teams of 3 to over 500 developers:
a) code maintainability was as a critical aspect
b) efficiency was an issue, almost always (imagine running on 15+ yr old hardware and still adding code to it with the old RAM still inside)
c) reformatting code just to make it pretty was against the coding standards. We didn’t touch a line if we didn’t have clear authority to change it for functional reasons. We did make it pretty while working on it, just not when checked in.
d) self documenting code is a good idea, provided the coders aren’t small minded and can step back and think like the next coder will. That is a rare skill, in my 20+ yrs of coding. Commenting based on what the next guy wants to know isn’t easy. Some compilers had stupid limitations on variable lengths.
e) nobody should be allowed to write new code until they’ve been a maintenance programmer for 2 years. You learn a ton on how not to code that way. It doesn’t really matter what language.
f) for systems that allowed dynamic memory allocation, a memory leak was considered a Sev 1 bug. Real-time FC systems don’t usually allow memory allocation.
g) unclear code comments were considered minor bugs, including spelling errors. Had to be corrected before the code was submitted.
h) every line of every program was reviewed by at least 2 other people who physically signed a piece of paper saying they didn’t find any errors. When you sign your name to a review and hand it in, you tend to actually perform a careful review. That paperwork with my signature can still be found, I’m certain.
i) if someone assigned to review design, code, or test work wasn’t ready, we held up the review until they were. PERIOD. If they didn’t consistently review and catch errors that other reviews found, they were encouraged to “find someplace else” to spend their days via peer pressure. This wasn’t needed very often. We all counted on each other to catch mistakes that could get people killed or destroy billion dollar vehicles.

For the GN&C software I developed, only 2 errors made it outside our group in over 5 years were attributed to me. I introduced many errors, but the team caught almost all of them. I caught my share of errors in other peoples’ code too. When I left that team, all 11 remaining developers introduced less than 1 error every 2 years combined.

Last I heard, a few of the guys now work at pace maker companies writing software. My mother has a pace maker and I’m very happy these guys probably ensured it works perfectly, EVERTIME.

Wow. You found a part of NASA that actually has any coding standards at all? I assure you that they aren’t NASA-wide standards. I worked at NASA for over 35 years (retired about 3 years ago), and for the last decade or so of that, I pushed in vain to get the center I worked at to establish any coding standards at all.

I was greatly disappointed when I was directed at what was alleged to be the software development standard, only to find that it had not one word or one reference that had anything to do with coding. It was mostly about such things as management responsibilities and various required paperwork.

Heck, I’d have even been happy with the single requirement that each major application must be accompanied by documentation of what the coding standards for that particular app were. It wouldn’t have to be onerous documentation either; a one-line citation of a reference would be fine, or perhaps citation of a reference plus a list of allowed exceptions/extensions. I could not get people to even document things like what language extensions were used, much less style matters. More than once I turned in a bug report about the use of some nonstandard syntax which hindered porting an app to a different compiler/machine. The usual reply was that it worked on the compilers they were using, which seemed to be the only coding standard they had. They wouldn’t write down even that much as their standard (perhaps because it would have looked too obviously bad?).

Hello world.
I understood pointers in c, also pointer arighmetic in c, when I started learning assembly. I saw that a compile-time-known-table-in-c generated element acces code different that a pointer. Pointer in c needed a dereference. At least one instruction more in x86. To you all: make some simple examples and generate assembly code from *.c files. Then see how it is done in asm by your compiler.
It was like lux-veritatis for me. After I understood this, I stop investigating asm, and started to make really magic c programs using pointer arithm. Tables, no, no more. Linked lists ? – double dereference. List scanning – simple for loop with double dereference (first element of node is pointer to another node.) Use C casting from (Some_node_t *) to (void *) and make your code fly. Greets.

The principle of expressing a unidirectional traversal of a linked list in a single statement is the ‘right thing to do’ since before I start reviewing the code in the loop I already know how the loop works.

The same simply isn’t true of:

ss = s;
while (ss) {
/* stuff */
ss = ss→ss;
}

Since I won’t know the loop is a linked list traversal until the end.

Naturally using sensible variable names is helpful but the pattern you identified is better than a comment since from its form I know the code is correct (or more accurately I know to review the code in the braces for element removal).