Good coding habits in R

Simon Thornley

23 September, 2022


Image from Hackernoon

Good coding habits in R

This is a summary of good habits to get into when coding in general. Since I use R, these will be related to R code. It is derived from the book “Good habits for great coding” by Michael Stueben available here.

Keep your code neat and easy to follow

  1. Document your programs with the following:
  • name
  • date
  • title
  • program description
  • any references
## Author: Simon Thornley
## 23/09/2022
## Program to analyse New Zealand all-cause mortality data 
## for the time-point most likely to result in a step-change.
## The data is available from here:
## ("https://mortality.org/File/GetDocument/Public/STMF/Outputs/stmf.csv")
  1. Use vertical alignment in your code.

Keep your code simple

  1. Limit functions to a single task. Document their inputs and outputs.

For example:

## Function to truncate number to two decimal places
## Returns character of input number to two decimal places.

 trunc_two_d_p_number <- function(x){
                                    stopifnot("`x` must be numeric." = is.numeric(x))
                                    formatC(x, digits = 2, format = "f")
                                    }
  1. Label and align your output

  2. Avoid global variables, but global constants are ok.

  3. In the body of your program, try to limit it to calls to other functions.

  4. Write self-documenting code. This includes ‘verb-object’ function names and descriptive names of variables or data frames.

  5. Refactor your code to make it more streamlined.

  6. Prefer simpler over clever code.

  7. Use a consistent style, such as Google’s R style guide.

  8. If you don’t understand what your code is doing, use that as a prompt to do some research.

Harden your code

  1. Check the class of the input of your function and throw an informative error if it is incorrect.

For example:

## Function to truncate number to two decimal places
## Returns character

 trunc_two_d_p_number <- function(x){
                                    stopifnot("`x` must be numeric." = is.numeric(x))
                                    formatC(x, digits = 2, format = "f")
                                    }

## Correct input
trunc_two_d_p_number(3.1415926)
## [1] "3.14"
## Incorrect input
trunc_two_d_p_number("four")
## Error in trunc_two_d_p_number("four"): `x` must be numeric.
## Alternative
trunc_two_d_p_number <- function(x){
                                    if (!is.numeric(x)) 
                                      stop("argument should be numeric")
                                    formatC(x, digits = 2, format = "f")
                                    }
  1. Write a simple test to ensure your function returns correct output.
    • Consider checking boundary conditions.
## Global variable to error check
Error_check <- TRUE


## Function to truncate number to two decimal places and returns character
trunc_two_d_p_number <- function(x){
                                    stopifnot("`x` must be numeric." = is.numeric(x))
                                    formatC(x, digits = 2, format = "f")
                                    }

## Check output is as expected...
if (Error_check){
if (trunc_two_d_p_number(3.14159) == "3.14") {
                                              print("Error check passed")
                                              } else print("Error check failed")
                }
## [1] "Error check passed"
## boundary test
trunc_two_d_p_number(1e+50) |> print()
## [1] "100000000000000007634202480888288842446682800440060.00"
## Incorrect input
trunc_two_d_p_number("four")
## Error in trunc_two_d_p_number("four"): `x` must be numeric.