Test
No, seriously, test.
I've been coding for over 20 years and I still don't trust myself to write a loop correctly the first time. I write and run tests that prove it works before I suspect it works. Test each side of every boundary condition. For example a rightIndex
of 0 should do what? How about -1?
Keep it simple
If others can't see what it does at a glance you're making it too hard. Please feel free to ignore performance if it means you can write something easy to understand. Only make it faster in the unlikely event that you really need to. And even then only once you're absolutely sure you know exactly what is slowing you down. If you can achieve an actual Big O improvement this activity may not be pointless, but even then, make your code as readable as possible.
Off by one
Know the difference between counting your fingers and counting the spaces between your fingers. Sometimes the spaces are what is actually important. Don't let your fingers distract you. Know whether your thumb is a finger. Know whether the gap between your pinky and thumb counts as a space.
Comments
Before you get lost in the code try to say what you mean in English. State your expectations clearly. Don't explain how the code works. Explain why you're having it do what it does. Keep implementation details out of it. It should be possible to refactor the code without needing to change the comment.
The best comment is a good name.
If you can say everything you need to say with a good name, DON'T say it again with a comment.
Abstractions
Objects, functions, arrays, and variables are all abstractions that are only as good as the names they are given. Give them names that ensure when people look inside them they won't be surprised by what they find.
Short names
Use short names for short lived things. i
is a fine name for an index in a nice tight loop in a small scope that makes it's meaning obvious. If i
lives long enough to get spread out over line after line with other ideas and names that can be confused with i
then it's time to give i
a nice long explanatory name.
Long names
Never shorten a name simply due to line length considerations. Find another way to lay out your code.
Whitespace
Defects love to hide in unreadable code. If your language lets you choose your indentation style at least be consistent. Don't make your code look like a stream of word wrapped noise. Code should look like it's marching in formation.
Loop constructs
Learn and review the loop structures in your language. Watching a debugger highlight a for(;;)
loop can be very instructive. Learn all the forms: while
, do while
, while(true)
, for each
. Use the simplest one you can get away with. Look up priming the pump. Learn what break
and continue
do if you have them. Know the difference between c++
and ++c
. Don't be afraid to return early as long as you always close everything that needs closing. Finally blocks or preferably something that marks it for automatic closing when you open it: Using statement / Try with Resources.
Loop alternatives
Let something else do the looping if you can. It's easier on the eyes and already debugged. These come in many forms: collections or streams that allow map()
, reduce()
, foreach()
, and other such methods that apply a lambda. Look for specialty functions like Arrays.fill()
. There is also recursion but only expect that to make things easy in special cases. Generally don't use recursion until you see what the alternative would look like.
Oh, and test.
Test, test, test.
Did I mention testing?
There was one more thing. Can't remember. Started with a T...
Best Answer
The kernel strongly prefers simple algorithms
While a variety of algorithms may require deeply nested loops within loops, in context of the Linux kernel (in which the quote was said) you generally need quick real time responses. In that context, deep nesting is a smell that may indicate that the code flow is too complex for this domain and may needs to be changed because of it's execution characteristics, not readability or indentation issues.
Furthermore, Linux kernel is different from most application code as for the requirements of auditability and testing - and thus would prefer to not have a 4+ level nested algorithm in a single function. It should be obvious to see what each code fragment does exactly and in detail, including all the possible control flow and edge cases. Deeply nested code hampers that.