Coding style
The most visible part of a coding style is the naming convention.
People use many different styles of naming conventions within the R
ecosystem (Bååth 2012). Popular ones are
alllowercase, period.separated,
underscore_separated, lowerCamelCase and
UpperCamelCase.
checklist default
We picked underscore_separated because that is the
naming convention of the tidyverse packages. It is
also the default setting in the lintr
package which we use to do the static code
analysis.
At first this seems a lot to memorise. RStudio makes things easier
when you activate all diagnostic options (Tools > Global
options > Code > Diagnostics). This
highlights several problems by showing a squiggly line and/or a warning
icon at the line number. Instead of learning all the rules by heart, run
check_lintr() regularly and fix any issues that come up. Do
this when working on every single project. Doing so enforces you to
consistently use the same coding style, making it easy to learn and use
it.
Rules for coding style
-
underscore_separatednames for functions, parameters and variables. - A line of code or comments must be no longer than 80 characters. Pro tip: have RStudio display this margin in the editor. Tools > Global options > Code > Display > Show margin
- Object names must not be longer than 30 characters.
- Start a new line
- after the pipe (
|>or%>%) - never before but always after
{ - before
}
- after the pipe (
- Use spaces instead of tabs. Pro tip: make RStudio place 2 spaces when you hit the tab key. Tools > Global options > Code > Editing > Insert spaces for tabs
- Use spaces consistently
- Use exactly one space before and after
- assignments
<-,->,= - operators like
+,-,*,/, …
- assignments
- No space before and one space after
, - No space after or before
(or[- except in constructs like
if (),for (),while ()
- except in constructs like
- One space between
)and{, e.g.function () {
- Use exactly one space before and after
- Use double quotes (
") to define character strings. - No trailing whitespace
- spaces at the end of a line
- blank lines at the end of the script
Pro tip: We strongly recommend to use Air to format your code automatically when saving the file. This works in 99.9% of the cases and saves you a lot of time.
Static code analysis checks
- Is an object defined before you use it?
- Do you use an object after you defined it?
- Use
<-or->to assign something. Only use=to pass arguments to a function (e.g.check_package(fail = TRUE)). - Use
is.na(x)instead ofx == NA. - Use
seq_len()orseq_along()instead of1:length(x),1:nrow(x), … Advantage: whenlength(x) == 0,1:length(x)yieldsc(1, 0), whereasseq_along(x)would yield an empty vector. - Don’t store code in comments. If you don’t want to lose code, use
version control systems like
git. If it is code that you need to run only under special circumstances, then either put the code in a separate script and run is manually or write an if-else were you run the code automatically when needed. - Avoid code with lots of nested loops or if statements. If the code
is too complex, you’ll get a warning that the cyclomatic
complexity is too high. Tips for reducing the code complexity:
- Use
assertthat::assert_that()to validate object or conditions instead ofif() stop(). - See if you can use
ifelse()instead ofif(). - Split the main function of your code over sub functions.
- Don’t use else if not strictly necessary. Use early returns when ever possible.
- Use
Using a different coding style
checklist allows you to define your own set of linters
at the organisation level. Because checklist depends on the
citeme
package, and citeme allows to define custom organisation
settings via a git repository, we will reuse this repository. To do so,
create a .lintr file in the root of your organisations’
citeme repository. This allows for a different coding style
that better fits your organisation, but still enforces the same style
within your organisation.
In case there is no citeme repository in your
organisation, or there is no .lintr file in it,
checklist looks for a local .lintr file in the
root of your project. Note that a local .lintr file is
ignored if a .lintr file is found in your organisation’s
citeme repository. checklist falls back to
using the default .lintr file provided with the
checklist package when no other .lintr file is
found.