Tips For Lowering Indention Levels

Linus Torvalds, the creator of linux, sets his tabs/indentations to 8 spaces. Personally that seems a little wide, but he says some interesting things about why shorter isn’t necessarily better. Me, I’ll stay with 4 because it just looks right. But you still shouldn’t have too many indent levels.

“If you need more than 3 levels of indentation, you’re screwed anyway, and should fix your program.” – Linus Torvalds, Linux Kernel Coding Style

Use Continue

Example:

for item in sequence:
     if is_valid(item):
          if not is_inconsequential(item):
               item.do_something()

Becomes:

for item in sequence:
     if not is_valid(item):
          continue
     if is_inconsequential(item):
          continue
     item.do_something()

Notice you have to flip the values of your if statements making this change. This only works inside a loop and if your language has continue.

Factor Out A New Method

This is true for a lot of things. As I recently heard if a method starts to get over 10-15 lines it starts to feel like maybe I’m doing something wrong.

If your indents are starting to get deep, maybe some of those sub-levels should just be put in their own routine.

On a python related note, Mr Rhodes points out if you need a new routine and you are in a class, your natural thought is to make a new method on the object. But if you aren’t using self – referring to the object in your new method – you can just make a function. These become easier to test and easier to move.

Factor Out An Iterator

Mr Rhodes says iterators are a Python superpower. I don’t understand python iterators yet and didn’t even understand his example, in the interest of completeness, here’s his example.

Example:

for item in sequence:
     for widget in item:
          for pixel in bitmap:
               pixel.align()
               pixel.darken()
               pixel.draw()

becomes:

def widget_pixels(sequence):
     for item in sequence:
          for widget in item:
               for bitmap in widget:
                    for pixel in bitmap:
                         yield pixel
 
for pixel in widget_pixels(sequence):
     pixel.align()
     pixel.darken()
     pixel.draw()

Lastly he talked about going to an argument per line for function calls. I want to write a full post on this idea because it has some cool implications in version control. The short version is once a function call gets to 79 characters, just go right to putting each parameter on its own line.

Shortening Lines & Binary Operations

One of the core values of Python is readability.

I think it’s cool a computer language has values.

To encourage this value it has a set of guidelines on how to format your code called PEP 8. Most of these points are applicable to all languages, so even if you aren’t blessed to use Python you still might want to check it out.

One of the PEP 8 rules is lines shouldn’t be longer than 79 characters. This is also a rule in typography. That’s the length of line that doesn’t require extra mental effort to move back to the beginning of the next line.

Much of this post and the next one are from a talk by Brandon Rhodes entitled A Python Aesthetic: Beauty and Why I Python and available on YouTube. It got me inspired to think about this stuff again and motivated to make these posts.

Here’s a few of tips on how to shorten lines effectively.

Shorten Lines By Adding Variables

As Mr. Rhodes pointed out in the source video, it’s a feature of math that you can assign some part of an operation to a variable and use that to pass on to another operation. Why do programmers seem to want to avoid this?

I don’t know, probably because programmers are lazy. Well some programmers. The same kind of programs that use one character variable names and magic numbers.

But not you right?

Example:

canvas.drawString(x, y, ‘Please press {}’.format(key))

Our first thought is using return to shorten.

canvas.drawString(x, y, 
     ‘Please press {}’.format(key))

But if it has to be two lines anyway….

message = ‘Please press {}’.format(key)
canvas.drawString(x, y, message)

Adding the message variable not only shortens the line, it gives us a variable that tells us what it is. The message is now easily changed, printed for debugging or logged later.

Shortening Long Formulas

In math a binary operation is where the two parameters are on either side of the operator. Like 1 + 1. In a way this is a function, just written differently than a normal function would be, ie. add(1,1).

Sometimes you have a big mathematical formula that stretches past 79 characters. Especially if you use good variable names. Here Mr. Rhodes disagrees with PEP 8 and I agree with him.

Example:

adjusted_income = (gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deductions - student_loan_interest)

PEP-8 says to divide binary operations after the operator. This is bad.

PEP-8 badness:

adjusted_income = (gross_wages + 
     taxable_interest + 
     (dividends - qualified_dividends) - 
     ira_deductions - 
     student_loan_interest)

Donald Knuth says divide before the operator.

Knuth Goodness:

adjusted_income = (gross_wages 
      + taxable_interest 
      + (dividends - qualified_dividends) 
      - ira_deductions 
      - student_loan_interest)

This seems much clearer, and put the operators front and center. Subtractions actually look like the variable is negative.

Source: A Python Aesthetic: Beauty and Why I Python by Brandon Rhodes

Image: Photographer Ron Davis (Me). Model Virginia McConnell.

Remove Comments By Making Them Code

I like comments, probably too much. Lately I’ve been rethinking some comments because they just don’t make sense or work in the real world. But not till I watched this video did I realize you could change them into code.

Make A Comment Into a Variable.

Variable names – good variable names – are self commenting. Extreme Programming uses the phrase “Destroy All Comments”.

Example:

# is window too tall
if window.height > 100:
     fix_window_height()

Becomes:

IsWindowTooTall = window.height > 100
if IsWindowTooTall:
     fix_window_height()

Example:

widget.reset(True)  # forces re-draw

becomes:

force_redraw = True
widget.reset(force_redraw)

Also makes it easier to put in debugging code later because you already have a name for the value to print. True is also a magic number in a sense because we don’t know what it means.

Make Code Section Comments Into Functions

Example:

# open the barn
barn = code.Barn.get()
barn.unlock()
barn.open()
 
# saddle the horse
saddle = code.Saddle.get()
saddle.install(horse)

Becomes:

open_barn()
saddle(horse)
 
def open_barn():
     barn = code.Barn.get()
     barn.unlock()
     barn.open()
 
def saddle(horse):
     saddle = code.Saddle.get()
     saddle.install(horse)

I once asked a boss if we could get people to add a few more comments so it would be easier to tell what code did. His reply was that when consultant programmers who get to work on lots of code they didn’t write come into a new project, they run a script that removes all comments. He said comments are often misleading. I think that’s a little extreme, but if you turn comments into code, that documentation will always be there.

Source: A Python Aesthetic: Beauty and Why I Python by Brandon Rhodes

Tactical Coding

When programmers are taught they are taught about how programs work. They are also taught how structure large projects so the parts work together – architecture or strategic programming.

But I don’t ever remember learning tactical programming. This is how to write code at the function and line level to decrease errors and increase things like understanding and readability.

I remember reading the book Code Complete after just a few years as programmer and being blown away. Why didn’t anybody tell me this stuff. You mean my variable names shouldn’t just be one letter? I should check parameters before using them? If I write the shell of a function first, I probably won’t forget to close a bracket or return a value.

I’ve decided to write a series of blog posts about tactics of coding. They have their own category on the blog now – Coding – Tactical.

Of course that means that all our code must be black, because everything tacticool is black.

Footnote: I like the first edition of Code Complete better than the newest one, but it is still good stuff.