These lessons are pretty basic, but they have served me well over the years. When I find myself getting lost in a project, it helps to go back to the basics and get some perspective.

I have learned most of these lessons the hard way, i.e. by not following them and getting burned. In some cases, I have been burned more than once. (What can I say? I'm a slow learner.)

On the other hand, following every lesson consistently always leads to positive outcomes. Many of these lessons seem like additional work, but my experience has always been that they save time and aggravation over the life of the project. A little investment of effort up front can prevent a lot of catch-up work down the road.

So here's my top 10 (plus one bonus) list of programming lessons I've learned over the last ten years.

A whole project - even an ostensibly simple one - is overwhelming to contemplate and leads to defensive procrastination. Always take the time at the beginning to break the project into manageable components, even if it seems like a waste of time. You'll be glad you did when a week or two goes by, the project scope has expanded, and you're starting to lose sight of the big picture.

With a list of components, you don't have to worry about the big picture - you just work through the steps until complete. Of course, this means you must be sure to review and revise the list of steps as your requirements change.

Accept it. Embrace it. Understand that the final product will be better if you're willing to change your mind when the facts change.

It's generally impossible to know, in advance, exactly what the end product is going to look like. The harder you try to detail the end product in absolute, unchanging terms, the more wrong you will end up being.

When coding a project, take the shortest path to a simple system that works, even if it's only a fractional subset of the total project requirements. Then incrementally add functionality, testing as you go, until the project is completed.

This includes both code comments and external documentation for application and/or API users. Every time you add or change a feature, update the documentation to reflect the change. Just make it a core part of your workflow.

If you wait until you've finished coding to start documenting, it will end up looking forced, rushed, and incomplete. Ideally, include your documentation right inside your version control.

Never you mind that 'quick fix' that will just take a monent to type out. Put it in development, test it, commit the change, and then push to production. Do this every time, and you won't end up looking like an asshole when something goes wrong.

This should be a no-brainer, so don't be one of those people who has to learn the hard way. You need a proper, reliable, redundancy-tested offsite backup, and you need to test regularly that you can restore from your backups.

No, a RAID array is not a backup solution. Nor is blindly trusting your hosting provider to do their job.

Don't walk out on code that won't run. It's surprisingly demoralizing to come to work the next day knowing that a broken build is waiting for you. If you have to roll back or comment out a half-finished code block, do it.

In addition, it's helpful to draft up a quick todo list so you can quickly pick up where you left off the next day. (Thanks to bsaunder on Hacker News for this suggestion.)

Cognitive science tells us that our brains protect us from the stress of not knowing how to solve a problem by ... hiding key information about the problem from consciousness. Thanks, brain.

For small to medium-sized problems, I find a good brisk walk is enough to break the logjam in my mind and see through to a solution. For big problems, I may have to pull out the big guns: a good night's sleep.

I'm not being silly or even exaggerating: sleep on it is an essential tool of my problem solving strategy, a tool on which I rely regularly, and which has yet to fail me.

Don't add new features while any identified bugs are still outstanding. When part of your system doesn't work, the last thing you want to do is introduce additional complexity.

When troubleshooting bugs, try to be scientific about it. Don't just randomly make changes and hope the bug will go away - this is a recipe for introducing more bugs. Make sure you come to understand what's causing the bug so that you can be confident your fix really is a fix. (Thanks to bendtheblock on Hacker News for this suggestion.)

When you're developing a project for someone, keep the channels open at all times. Clearly communicate your timelines, progress and difficulties and provide regular status reports.

If you realize something is going to take longer than you expected, resist the urge to go into hiding! Instead, notify them as early as possible. Likewise, if the client comes back to you with changes that impact your time lines, be very clear in communicating what those impacts will be.

Finally, though it may seem like a hassle, make yourself available to answer questions and provide demonstrations. If you followed #3 and #8, you will always have something to show.