Programming Framework
This post is about coding as much for yourself as for others. While it’s really easy to write pages of code with only a few comments, in the long run, writing well structured and clearly legible code helps a lot when you return to it months later and are forced to ask yourself “What was I thinking?”
Programmers Lament: ‘I think I wrote this section of code late at night after I had a few beers with friends. I think I need to go out and have a few beers to understand why I wrote it like this.’
I try to write all my code as if I was about to post it to public blog and that the reader will have only rudimentary knowledge of what my goal is. This means that I will need to explain myself clearly. This will impact the kind of comments I write and will remind me that resorting to cute code tricks and obfuscation (even accidental) is a bad idea.
I will admit that I am not a professional programmer, but I play one on IRC. Joking aside, I am not even a trained programmer unless you count reading books on programming. My advice here comes from concepts I have learned through years of reading other peoples code. I have found that what I call the “good” code is written by someone who is well organized writes decent comments and is reasonably methodical in how they break down a problem. Some of my own ideas start as inspiration from these organized and creative programmers whose shoulders I stand on. I will show you a programming template technique I learned from Jon McPhalen. See what I did there? Programming rule #1 should be, “Always include attribution and give appropriate credit for your borrowed ideas”.
While there are some decent books on programming style, it’s not the main focus here. This is about remembering that you could have a future audience that reads your code, so writing efficiently, being consistent and adopting good conventions is paramount.
Using a template for organized code
The Arduino environment already enforces a certain method of coding on us. It requires us to write using the core C++ language and that we employ two sections of functionality in our code. So the base minimum code is the well understood:
void Setup() {
}
void Loop() {
}
While it is nice that the Arduino developers have saved us a lot of trouble but making “getting started” so easy, it doesn’t much help when you come back later to revise your code later and are clueless because you thought, “I’ll make it pretty later” and you never do. I have adopted a starting point for code that includes some more information than just the bare minimum required. The goal here is to start with a template that is nicely sectioned out so you have a road map for moving forward.
Here is an example of a template as a starting point:
//==============================================================================
// TTTTT EEEEE M M PPPP L AAA TTTTT EEEEE III N N OOOOO
// T E MM MM P P L A A T E I NN N O O
// T EEEE M M M PPPP L AAAAA T EEEE I N N N O O
// T E M M M P L A A T E .. I N NN O O
// T EEEEE M M P LLLLL A A T EEEEE .. III N N OOOOO
//==============================================================================
//==============================================================================
// Program: template.ino
// Author: Pete Willard
// Version: 1.0
// Target: Uno
// Date: 2015/04/02
// Time: 06:41:02
// Notes:
//
// ----------------------------------------------------------------------------
// 'THE BEER-WARE LICENSE':
// petewillard@gmail.com: As long As you retain this notice you
// can do whatever you want With this stuff. If we meet some day, And you think
// this stuff is worth it, you can buy me a beer in return. Pete Willard
// ----------------------------------------------------------------------------
//
// Reference:
//==============================================================================
//=====[ INCLUDE ]==============================================================
//=====[ CONSTANTS ]============================================================
#define DEBUG 1 // 0 = debugging disabled, 1 = enabled
//=====[ PINS ]=================================================================
int onboardLed = 13;
//=====[ SETUP ]================================================================
// Runs only one time at startup
void Setup() {
pinMode(onboardLed,OUTPUT);
}
//=====[ MAIN PROCESS LOOP ]====================================================
void Loop() {
}
//=====[ SUBROUTINES ]==========================================================
void printBreak() {
Serial.println("=============================");
}
I actually went so far as to write a small program that uses a fill in form to create this template format on demand. It even creates that retro-style banner with the file name spelled out on top.
A quick review shows that the template has defined a sample constant that you can use while debugging code. Changing this constant between 0 and 1 will enable you to write some conditional code that will print or stop printing debugging data with just 1 edit.
It also contains an example of using meaningful names. Using the variable assignment such as ‘onboardLed’ for pin 13 helps to make the code more readable.
Variable names don’t have to be short and are much better when multiple words are compounded into a meaningful descriptive names. For enhanced readability, try to avoid using using ALLCAPS and avoid variables with leading underscores. Try to adopt the much more accepted “camelBack” notation. This notation starts with lowercase and is the practice of writing compound words or phrases such that each following word or abbreviation begins with a capital letter*. Inserting underscores inside variable names makes the camelBack method redundant so just pick either one and stick with it.
Modular thinking
To me, when it comes to reading other peoples code, there is nothing more disturbing than reading page full of if conditional statements that include redundancies and a clear sign of poor planning. If I need to keep track of more than a few conditions while reading code I find that the logic of what “was intended” to be easily lost.
My approach to solving this has always been to create function blocks of code and keep the main section, in our case the Loop(), as clear and readable as possible. In C, this is called creating a “function” and it is sometimes referred to as a procedure or subroutine. I personally use all three terms interchangeably.
In most cases, you will write a procedure that accepts an argument and returns a result but this is not a requirement. For example, you can have a subroutine that just performs a task that makes the rest of your code look cleaner. Like this:
void printBreak() {
Serial.println("=============================");
}
So in your main code, all you need to type is:
printBreak();
In one of my programs, I have a Loop() section that basically contains 3 steps:
sampleSensors(); // collect all external sensor variable data into a “struct” variable</span>
printResults(); // send the results in 1 CSV formatted line</span>
cycleCheck(); // is it time to get updates from sensors?</span>
The functionality of the loop section remains readable and it is not bogged down with actual logic decisions. The logic and action steps are reserved for the procedures themselves and the procedures call other procedures to keep things organized. Breaking up tasks will actually help make your procedures more useful and in a lot of cases… re-usable.