> For the complete documentation index, see [llms.txt](https://monasheng.gitbook.io/zerotohero/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://monasheng.gitbook.io/zerotohero/arduino-zero-to-hero/core-skills/clean-code.md).

# Clean Code

{% embed url="<https://www.youtube.com/watch?v=wucFSGh9zLY>" %}

There is a wide chasm between code that *works* and code which is *good*. Broadly speaking, and for our purposes, good code:

* is *modular*, utilsing functions as black boxes to break up it's complexity and enable *unit testing,*
* is easily *human-readable*, being well structured, well commented/documented, and obvious in application, and,
* is *efficient* in its use of computational resources.

## Modularity

Ensuring modularity of your code is crucially important for both its readability and reliability.

Modularity allows for *unit testing* - that is, testing each aspect (i.e. black box, module) individually, before integrating into a larger system.&#x20;

Where projects become large, or involve multiple developers, or aim for reusability/expansion, modularity is essential for any sustained effort.

### Functional Programming

A simple way to modularise your code is via so-called *functional programming*. Here, as much as possible, parts of the codebase related to the same action are grouped together into functions to:

1. simplify the main `loop()` of the code,&#x20;
2. aid in testing/troubleshooting/debugging, and,
3. allow for easy re-use of these functions in similar circumstances, or expansion of the code to perform other functions.

### An Example

Consider the following example, which involves illuminating one of three coloured LEDs using the `digitalWrite()` function, depending on the value of an analog sensor (e.g. a potentiometer). A non-modular version of this code might look like:

```arduino
#define REDPIN 2
#define GREENPIN 6
#define BLUEPIN 10
#define POTPIN A0

void setup() {
  // Set the LED pins as outputs
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  // Set the potentiometer pin as an input
  pinMode(POTPIN, INPUT);
}

void loop() {
  int potValue = analogRead(POTPIN);
  int threshold = 341; // i.e. 1023 / 3, 1/3 of the range of the pot

  if (potValue < threshold) {
    // light up only 
    digitalWrite(REDPIN, HIGH);
    digitalWrite(GREENPIN, LOW);
    digitalWrite(BLUEPIN, LOW);
  } else if (potValue < threshold * 2) {
    digitalWrite(REDPIN, LOW);
    digitalWrite(GREENPIN, HIGH);
    digitalWrite(BLUEPIN, LOW);
  } else {
    digitalWrite(REDPIN, LOW);
    digitalWrite(GREENPIN, LOW);
    digitalWrite(BLUEPIN, HIGH);
  }
}
```

And *does* work:

<figure><img src="/files/oBOHe3fxmbXQwVmkq5bA" alt=""><figcaption></figcaption></figure>

Now consider a modularised version of this code:

<pre class="language-arduino"><code class="lang-arduino"><strong>#define REDPIN 2
</strong>#define GREENPIN 6
#define BLUEPIN 10
#define POTPIN A0

void setup() {
  // Set the LED pins as outputs
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  // Set the potentiometer pin as an input
  pinMode(POTPIN, INPUT);
}

void loop() {
  int potValue = analogRead(POTPIN);
  int threshold = 341; // i.e. 1023 / 3, 1/3 of the range of the pot

  if (potValue &#x3C; threshold) {
    writeAllLEDS(HIGH,LOW,LOW);
  } else if (potValue &#x3C; threshold * 2) {
    writeAllLEDS(LOW,HIGH,LOW);
  } else {
    writeAllLEDS(LOW,LOW,HIGH);
  }
}

// A user-defined function to set all LED states
void writeAllLEDS(bool redPinState, bool greenPinState, bool bluePinState) {
  digitalWrite(REDPIN, redPinState);
  digitalWrite(GREENPIN, greenPinState);
  digitalWrite(BLUEPIN, bluePinState);
}
</code></pre>

By *modularising* the LED writing functionality, we have:

1. simplified the main `loop()` function and improved the human-readability of the code,
2. improved it's reliability by taking an action (writing 3 pin states) that was previous repeated 3 times, and isolated it to a single function call, reducing the chance of human-error, and,
3. isolated this action to it's own function, which we can unit test with a simpler sketch and hardware setup to validate the functionality of both as a step toward full integration.

Such a validation sketch might look like:

<pre class="language-arduino"><code class="lang-arduino">#define REDPIN 2
#define GREENPIN 6
#define BLUEPIN 10

void setup() {
  // Set the LED pins as outputs
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
}

void loop() {
<strong>// Test just the RED LED
</strong>writeAllLEDS(HIGH,LOW,LOW);
delay(2000);
// Test just the GREEN LED
writeAllLEDS(LOW,HIGH,LOW);
delay(2000);
// Test just the BLUE LED
writeAllLEDS(LOW,LOW,HIGH);
delay(2000);
}

void writeAllLEDS(bool redPinState, bool greenPinState, bool bluePinState) {
  digitalWrite(REDPIN, redPinState);
  digitalWrite(GREENPIN, greenPinState);
  digitalWrite(BLUEPIN, bluePinState);
}
</code></pre>

And the validation hardware setup is simpler also:

<figure><img src="/files/9XIsK4HRGEZZDh3b7A9e" alt=""><figcaption></figcaption></figure>

## Readability

Clean code should be easy to read and understand, even for someone who is not the original author. In addition to [#structure](#structure "mention"), [#commenting](#commenting "mention") and [#obviousness](#obviousness "mention"), there are few simple guidelines you can follow to improve the readability of your code:

* **Descriptive Naming**: Use meaningful names that convey the purpose of a variable or function. Avoid acronyms and/or single-letter variables where possible. For instance, defining `int userAge` is more readable than `int uA`.
* **Consistent Formatting**: Follow a consistent style guide for indentation, spacing, and variable naming throughout your code. This uniformity can help a reader quickly see structure and flow.
* **Short Functions**: when [#functional-programming](#functional-programming "mention"), limit functions to a single task where possible. Avoid longwinded or complicated functions.

### Structure

While Arduino is not particularly picky about where various elements of your code lie within a sketch, adopting a consistent and logical/chronological structure can aid greatly in readability. In general, the structure provided in [Arduino C](/zerotohero/arduino-zero-to-hero/arduino-programming/arduino-c.md#code-structure) is preferable for this module - that is, in order:

* All library inclusions, constant definitions, and global declarations, followed by;
* The `setup()` function, followed by;
* The `loop()` function, followed by;
* user-defined functions.

With these sections separated by comment blocks `/*---------*/`.

### Commenting

Striking a balance between succinctness and clear explanation via comments is essential for clean code. Consider the following general principles when writing comments.

* **Explain Why/How, Not What**: Comments should explain why a particular approach was taken, not just what the code is doing. Well-written, modular code should itself make the "what" clear.
* **Avoid Redundant Comments**: Don't state the obvious. For instance, `// Set x to 5` is redundant if the code is `int x = 5;`. Instead, use comments to explain complex logic or algorithms, or group together related actions (e.g. `//declare input variables`).
* **Keep Comments Updated**: Ensure comments are updated when code changes. Outdated comments can be misleading and potentially worse than no comments at all!

&#x20;If in doubt, always err on the side of providing more, rather than fewer comments.

### Obviousness

The purpose and behaviour of your code should clear to a reader at a glance. Your aim should be to reduce the cognitive load on any reader of your code, and minimise the need for extensive additional documentation through obvious and self-documenting approaches. Consider:

* **Writing Self-Documenting Code**: Use approaches and variables names that are self-explanatory. For example, a function named `isUserLoggedIn()` is self-documenting, implying both what it does and what a `TRUE` return would mean, compared to  e.g. `checkLoginStatus()`.
* **Avoiding Over-Engineering**: Keep solutions as simple as possible. Avoid unnecessary complexity and clever tricks that can obscure the code's intent.

## Efficiency

Arduino MCUs are not particularly powerful, and can struggle to perform complex or time-consuming operations (e.g. writing to the serial monitor) - especially if these are requested every loop iteration. Consider:

* Using timers or [Interrupts](/zerotohero/arduino-zero-to-hero/advanced-skills/interrupts.md) to call processor-intensive functionalities on a less-frequent interval than every loop iteration, or on-demand based on user inputs,
* Utilising off-the-shelf [Arduino C](/zerotohero/arduino-zero-to-hero/arduino-programming/arduino-c.md#library-inclusions) wherever possible, as many of these have been optimised for the Arudino platform,
* Minimising redundant operations, including the use of loops, in your code.
  * Avoid unnecessary calculations or operations within loops. Move invariant code outside the loop to reduce the number of computations.
  * If possible, save the results of processing-expensive but time-invariant operations in variables for later use, rather than re-calculating them every time.

Note that there often arises a trade-off between [#efficiency](#efficiency "mention") and [#obviousness](#obviousness "mention"). In these situations, *you should almost always favour the latter.*&#x20;

It is rarely the case that poor function of your code can be solved by over-engineering trickery - consider other big-picture changes (e.g. moving to [#functional-programming](#functional-programming "mention"), using off-the-shelf libraries, and performing calculations on a less-frequent interval) before you resort to *clever* programming.
