Tip 6Be Stylish
White Belt[​​White Belt] Writing code with good style helps well before the professional world.

These two functions do exactly the same thing:

Fibonacci.c
 
uint64_t
 
fibonacci(​unsigned​ ​int​ n)
 
{
 
if​ (n == 0 || n == 1) {
 
return​ n;
 
}
 
else​ {
 
uint64_t previous = 0;
 
uint64_t current = 1;
 
 
while​ (--n > 0) {
 
uint64_t sum = previous + current;
 
previous = current;
 
current = sum;
 
}
 
 
return​ current;
 
}
 
}
Fibonacci.c
 
unsigned​ ​long​ ​long​ fbncci(​unsigned​ ​int​ quux) { ​if
 
(quux == 0 || quux == 1) { ​return​ quux; } ​else​ {
 
unsigned​ ​long​ ​long​ foo = 0; ​unsigned​ ​long​ ​long​ bar
 
= 1; ​while​ (--quux > 0) { ​unsigned​ ​long​ ​long​ baz =
 
foo + bar; foo = bar; bar = baz; } ​return​ bar; } }

Which would you rather maintain?

Maybe that example is a little extreme, but it illustrates a simple point: your code isn’t just read by a compiler; it’s read by other programmers, too. Writing code with good style is a factor in software quality because you simply can’t maintain code that you can’t read.

Factors to Style

The broad term style refers to all the things that the compiler doesn’t care about but humans do. Here are some examples:

  • Naming of classes, methods, variables, files, and so on

  • Arrangement of functions within a file and across files

  • Comments

  • Braces and parentheses (where optional)

  • Choice of control structures (where equivalent)

  • Capitalization

  • Indentation and other whitespace

The definition of good style varies depending on the programmers you’re working with, project or corporate style guides, and conventions established by the programming language. However, there are some common themes we’ll look at here.

Why Naming Matters

Well-written code won’t read like a human language, but it shouldn’t read like alien hieroglyphics, either. Good naming of classes, methods, parameters, and variables will go a long way toward making the code read naturally to another programmer. This doesn’t mean names need to be overly wordy; they just need to be appropriate to the problem domain.

Consider the Fibonacci code opening this tip. The variables previous, current, and sum are descriptive to their purpose. The parameter n is short but appropriate to the problem domain; the purpose of the function is to return the nth Fibonacci number. Similarly, i and j are often used as index variables in loops.

If you’re struggling to name something, that’s a tip-off that the purpose of your code may be questionable. Here is an example:

 
im = InfoManager.new
 
puts im.get_customer_name_and_zip_code(customer_id)

What exactly is an InfoManager? What do you do with one? How do you reason about one? Vague names like InfoManager usually indicate vague purpose. The method name should similarly tip you off to questionable code. Contrast that code with the following:

 
customer = Customer.find(customer_id)
 
puts customer.name
 
puts customer.address.zip_code

Objects like customers and addresses are things you can reason about, and natural-sounding method names—find, name, and so forth—should come, well, naturally.

Commentary

Legend speaks of the ultimate code comment of woe. It is, of course:

 
i = i + 1; ​/* add one to i */

Comments shouldn’t tell the reader how the code works. The code should tell them that. If the code is not clear, fix the code to make it clear. Instead, focus comments on the following:

  • What is the purpose of this code, if it’s not intuitive? For example, the IMAP protocol defines the user’s inbox as the special string INBOX, so a comment in your code could refer the reader to the appropriate section in the specification: list("INBOX"); /* mailbox INBOX is special, see RFC3501 section 5.1 */.

  • What parameters and return values are expected? Some of this may be inferred from the names of the parameters, but for public APIs, a summary comment before the function can be useful. Also, many documentation generators can scan source files and generate summary docs for public APIs. JavaDoc[10] and Doxygen[11] are common tools for this task.

  • Is there something you need to remember temporarily? Programmers will use strings such as TODO and FIXME to make a reminder to themselves during development. However, fix these strings before checking in: if you really need to do something later, put it in whatever system your team uses for tracking tasks. If it’s a bug, fix it or enter a bug report. Source code is not your to-do list or bug database.

  • What is the copyright and license for the file? It’s normal practice to put a header comment in each file specifying the copyright ownership (typically your company) and any license terms. If in doubt, there is no license; it’s “all rights reserved.” Code contributed to open source projects needs to explicitly state a license.

Used properly, comments complement the code in a natural manner, giving future readers a clear picture of what’s going on and why.

Conventions for Exits and Exceptions

This is part style, part correctness. Some style guides, typically for C code, specify that a function can have only one exit point. Often the origin for this rule is to ensure that any allocated resources are released. I’ve seen code similar to the following in several operating system kernels:

ExitPoints.c
 
int
 
function()
 
{
 
int​ err = 0;
 
char​ *str = malloc(​sizeof​(​char​) * 5);
 
 
if​ (str == NULL) {
 
err = ENOMEM;
 
goto​ ERROR;
 
}
 
 
// ...
 
 
FILE *file = fopen(​"/tmp/foo"​, ​"w"​);
 
 
if​ (file == NULL) {
 
err = EIO;
 
goto​ ERROR_FREE_STR;
 
}
 
 
// ...
 
 
err = write_stuff(file);
 
if​ (err != 0) {
 
err = EIO;
 
goto​ ERROR_CLOSE_FILE;
 
}
 
 
// ...
 
 
ERROR_CLOSE_FILE:
 
fclose(file);
 
ERROR_FREE_STR:
 
free(str);
 
ERROR:
 
return​ err;
 
}

In the happy path, execution falls through the fclose and free at the bottom, releasing resources in the opposite order of their creation. The use of labels at the end allows error cases to simply set the desired return value and jump to where the correct resources are released. This is conceptually similar to throwing an exception, except that you call the “destructors” yourself. This technique can be less error prone than checking every return statement by hand.

Of course, other C style guides insist that you never, ever, on penalty of death, use a goto statement. If the company style guide insists on both a single exit point and no goto, prepare for some painful acrobatics to fulfill both rules.

Exceptions can use a similar strategy if you are calling APIs (like a C library) that don’t provide a class with a constructor and destructor. However, it’s often better to make a lightweight class that wraps the appropriate resource. Here’s an example in C++:

OpenFile.cpp
 
class​ open_file
 
{
 
public​:
 
open_file(​const​ ​char​ *name, ​const​ ​char​ *mode) {
 
_file = fopen(name, mode);
 
 
// ...raise exception here if NULL...
 
}
 
 
~open_file() {
 
fclose(_file);
 
}
 
 
// Conversion operator so instances can
 
// be used as parameters to fprintf, etc.
 
operator​ FILE*() {
 
return​ _file;
 
}
 
 
private​:
 
FILE* _file;
 
};

In this example, an open_file instance can be created on the stack, and the file will be closed on return from a function, no matter if you leave with a return or an exception—C++ will call the destructors of any instances on the stack.

If in Doubt...

If your company has no coding style guide, fall back to the following:

  • Match the style of any code you’re editing. Even more annoying than poor style is a file with a mishmash of multiple styles.

  • Follow any established language conventions. Some languages, like Ruby, have very well-established precedent for naming and indentation. When writing in Ruby, do like the Rubyists do.

  • For languages with inconsistent precedent, like C++, follow the precedent of major libraries you’re using. The C++ Standard Template Library has a consistent naming style, so it makes sense to match their style when using STL.

For projects with multiple languages, it still makes sense to follow conventions for each language—make Ruby look like Ruby, and make C++ look like C++. This goes beyond issues like naming and indentation; follow the idiom of each language as well. See Idiomatic Programming for further discussion. Provide a bridge layer if needed.

Further Reading

Take a look at Robert C. Martin’s Clean Code [Mar08]; it’s an authoritative work on coding style.

Consult Wikipedia[12] for links to a large assortment of style guides.

Actions

Find a style guide (sometimes under the name coding standards) for a language you use, preferably one that explains the rationale for each of its rules. Some rules will be arbitrary, but most have the intention of reducing accidental bugs or improving readability. Read it for the why behind the rules more than the what.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.152.58