Wednesday, April 13, 2011

Variable names should usually be descriptive

By Chad Perrin

Takeaway: Chad Perrin says the long evolution of programming style leads us to one inescapable conclusion about variable naming conventions: what we should name our variables depends on context.

A programming practice that largely vanished with early versions of the BASIC programming language was the use of single-character variable names. The difficulty of deriving meaning from a variable named a, meant to represent a concept like "accounts receivable," impedes the quick and easy comprehension of what our code is supposed to accomplish for us. As a result, a common "best practices" rule of thumb was developed that could be expressed thusly: use descriptive names for variables.

This concept is central to the more modern, more general rule that, to the extent reasonable, source code should be self-documenting. It is preferable to be able to read source code directly and have all the information we need to understand it in full right there in the source, rather than having to read separate documentation of the code and keep track of where that documentation matches up with the syntactic elements of the source itself. It is preferable not least because of the tendency of documentation and source code to get out of sync. This applies almost as much to code comments explaining how code works as to separate documentation.


With self-documenting code, then, code comments can be reserved for why we wrote our source code the way we did. We increase the information density of our source code files without increasing the difficulty of reading them, this way. In fact, reading and understanding get much easier when the source code itself reads a bit like a story of how the code works, rather than like pseudorandom streams of characters.

The rule of thumb that we should use descriptive, (presumably) verbose variable names is just that, though — a rule of thumb. It should not be taken as a divine commandment, never to be broken. There are cases where long descriptions of what a variable does are not appropriate or desirable when trying to make our code as clear, and thus maintainable, as possible.

To the extent that a variable name is confined to a narrow context, it is often appropriate to use a shorter, less descriptive variable name. In fact, doing so is often more than appropriate — it is advisable, because a lengthier name would make it take longer for the developer to read and grasp the meaning of the variable in that context, cluttering up the code.

This is particularly the case where a single, primary looping variable is used to iterate through data stored in some kind of data structure, where the meaning of the variable name is fairly explicitly defined in an obvious, encompassing location in the code. Take a Ruby iterator block as an example:

purchase_list.sort.each {|p| puts product_descriptions[p] } 

As we can see, the fact that we are iterating through a list of purchases is directly tied to the use of p as a looping variable. That variable, then, is used as an index or key used to retrieve product descriptions from the product_descriptions collection. Loops wherein a primary looping variable serves as the key used to retrieve a value from a collection constitute the most obvious example of where a single-character variable — often derided as a cardinal sin of programming — actually helps clarify code. Consider instead this needlessly verbose alternative:

purchase_list.sort.each do |purchase_list_item|   puts product_descriptions[purchase_list_item] end 

In this example, by choosing to be more explicit in describing the source of the looping variable, we not only clutter up the code so that it takes slightly longer to read and understand, we also create a mismatch between the name of the variable and how it is to be used within the loop. In addition, our lines of code are lengthened to the point where, for clarity, a single-line, simple iterator should be broken up into multiple lines — using do . . . end syntax instead of braces in accordance with Ruby coding style conventions for the multiline version. Another needlessly verbose alternative attempts to correct the deficiency in relevance to where the variable is used within the block:

purchase_list.sort.each do |product_key|   puts product_descriptions[product_key] end 

In this case, we tie the name of the loop variable to its use within the loop, but in so doing we divorce it from its source. Furthermore, in doing so, we make the name essentially redundant with the name of the collection for whose values it serves as keys, and convey no information that is not stunningly obvious to the reader.

Slavish devotion to the common rule of thumb that variable names should be verbosely descriptive produces an effective reduction in quick and easy reading and comprehension of code here, rather than an improvement. One of the most important factors in play is the fact that the beginning of the loop provides a directly corresponding connection between the loop variable's name and the source of its contents on each iteration. Another is its use as a key or index for a collection, where the syntactic significance of the variable in use is made clear by context.

That rule of thumb is certainly not without its merit in most cases, though. It is a rule of thumb because it works most of the time. For instance, given a variable whose scope is global to the current program file, a single-letter name provides little or no guidance within the context of its use in various parts of the program to its meaning for the algorithmic model as defined by the source code. More descriptive names are necessary for such circumstances because of the relative lack of cues in close proximity to the variable's points of use — a direct result of the distance within the source file from the source of the variable's value.

This is why one might create a hash like the following near the beginning of a program to capture command line arguments whose values must be used later in the program:

command = {   :name      => ARGV.shift,   :target    => ARGV.shift,   :attribute => ARGV.shift } 

This way, the programmer can see sources and names of command line arguments all in one place at the beginning when maintaining that particular part of the program, and code comments can be added to clarify why things are organized that way. This provides a sort of configuration rule set for the rest of the program, defining the relationship between program inputs and the datums derived therefrom as they are used later.

At the same time, the programmer reading through other parts of the program has an immediate cue as to the meaning of a given datum that originated as a command line argument when it is used within other code because of the descriptive hash-and-key names:

inventory_table = InventoryTracker.new(datafile)  if command[:name].downcase.eql? 'delete'   inventory_table[     command[:target]   ].delete_entry(command[:attribute]) end 

By contrast, the following could be disastrous for quick and easy comprehension of what our code is doing:

i = InventoryTracker.new(f)  if c[:n].downcase.eql? 'delete'   i[ c[:t] ].delete_entry c[:a] end 

In this case, compressing things into fewer lines of code provides greater brevity only at the cost of any contextual cues about the meaning and purpose of the variables, resulting in what looks more like line noise than actually useful notation. On top of that, we must take into account the difficulty of finding the appropriate variable when doing a text search for something like f or — worse yet, because variable assignment may not actually contain this specific group of characters — c[:t]. Instead, assignment may look more like this:

c = {   :n => ARGV.shift,   :t => ARGV.shift,   :a => ARGV.shift } 

Another bad approach would be to simply use ARGV indices:

if ARGV[0].downcase.eql? 'delete'   i[ ARGV[1] ].delete_entry ARGV[2] end 

Now, we have to remember the order in which we have specified users should enter their command line arguments every time we have to make use of one of those arguments in our code. By taking the first approach described here for managing command line arguments, creating a command hash at the beginning of the file with descriptive names, we keep all our non-descriptive variable names together within the context of early organization of the way we handle data in the program, and use more descriptive terms in later code to give the code a self-documenting quality.

The term "cargo cult programming" was coined to describe cases where people employ what they believe to be "best practices" and to copy code in full or at least in form, without understanding the reasons for the practices or how the code they copy works. Taking an approach like this results in abuse of descriptive verbosity in variable naming, turning a practice intended to clarify code into yet another way to obscure its meaning from the programmer who has to read it later.

Ultimately, the correct answer to questions like "How should I name my variables?" is "It depends." When using a rule of thumb, think critically about it to determine whether you are using the rule correctly.

Five tips for a lighter, leaner Linux desktop

Takeaway: With a little tweaking, you can achieve a noticeable increase in speed for your Linux desktop. Jack Wallen looks at a few simple steps for tuning up performance.

The Linux desktop is flexible, powerful, and reliable, and it's certainly ready for your business and/or home needs. One of the many reasons why the Linux desktop can handle numerous needs is its ability to be highly tuned to meet the requirements of the user. In addition to customizing the desktop, you'll sometimes want to tweak it so that it's as light and lean as possible. For example, you may have a slower piece of hardware you want to eke more life out of. Or you might have an application that requires a larger amount of CPU cycles than a standard desktop allows. Regardless of the "why," we're going to focus on the "how." Here are five ways you can have yourself a lighter, leaner Linux desktop.

1: Use a lighter desktop

There are plenty of options available. From Enlightenment to Fluxbox to Xfce, Linux has plenty of options (all with varied feature sets) that allow you to have the lightest possible desktop. One of the lightest of all (outside of console only) is Fluxbox. Although this desktop may require you to do some manual configurations, the result is an incredibly fast desktop — likely the fastest desktop you have ever experienced. You can install many of these lightweight desktops right from your Package Management system. For Enlightenment, however, I would go with a distribution that offers E17 as an option or as the default (such as Bodhi Linux.)

2: Don't use indexing

As with the Windows desktop, indexing can cause a significant slowdown on your Linux desktop. Both KDE and GNOME use indexing (with the help of Strigi and Beagle, respectively) to enable more powerful desktop searching that is accessed not only by end users, but by applications as well. The act of indexing is when either the Beagle or the Strigi indexing daemon indexes every file within the configured directories. Both tools allow for the configuration of specific times to handle indexing, which is one way to get rid of the issue at hand. But if you don't do much searching or you don't use applications that depend upon desktop searching (such as a groupware suite like Evolution), you can disable the indexing services altogether.

3: Turn off visual effects

Yes, visual effects are cool. That Compiz cube can't be beat for desktop awesomeness. But Compiz (and other compositors) can really put a hit on your system. Just because your GPU can handle the task doesn't mean your CPU or RAM can handle the added load. For slower systems (or when you really need as much CPU as you can get), disable visual effects completely in GNOME or KDE. The latest KDE (4.6 as of this writing) has a nice feature that will automatically disable visual effects if they take too long to load or cause a noticeable hit on the system. For GNOME, just click System | Preferences | Appearance and then disable Visual Effects from within the Visual Effects tab. For KDE, click K Menu | System Settings | Desktop Effects and uncheck  Enable Desktop Effects in the General tab.

4: Remove KDE Plasmoids and GNOME widgets

With either KDE or GNOME, the more widgets you use, the slower your desktop can get. By default, KDE 4 will ship with a single Plasmoid, which won't create a noticeable hit. But if you long for a bit more speed, you can remove that Plasmoid. Same thing with GNOME. I have seen the GNOME Do widget in a GNOME panel cause slowdowns on a system. Of course, with GNOME 3, this all changes, as you can't add widgets to the Panel. You can think of these Plasmoids and widgets similarly to Windows startup applications. They require resources to run and the more you have, the more resources they will use. This is especially true if you have visual effects turned on, since the Plasmoids often make use of those effects. And if you are using Plasmoids or widgets that are updated from a network feed, you could easily see a slowdown should your connection fail or suffer a slowdown.

5: Use a different file manager

I know this might seem counterintuitive, as both Dolphin (KDE) and Nautilus (GNOME) are integrated file managers and should be optimized for use. But the thing is, those file managers are notorious resource hogs. Yes, they offer an incredible number of features and are hands-down the most user-friendly, feature-rich file managers you will ever use. But when speed is the key, you want a file manager like PCMan File Manager or Thunar. Both offer some unique features for a file manager and both will blow the competition out of the water when it comes to speed. Between the two, you will find PCMan File Manager to be the lighter weight, as it doesn't depend upon the Xfce libraries that Thunar requires for installation. But both of those solutions are blazing fast and will not slow down your system in the slightest.

When trying to decide upon which Linux desktop to use, you should rest assured that (unless your hardware demands a much lighter desktop) you should be able to tweak your desktop to the point where the increase in speed is noticeable. Although many would argue that today's powerful machines can handle anything thrown at them, not all businesses or homes can afford the latest-greatest. In those instances, it's always nice to know a leaner, lighter desktop can be had, thanks to Linux.


ITWORLD
If you have any question then you put your question as comments.

Put your suggestions as comments