# install.packages('pak')
::pak('mjfrigaard/shinypak') pak
27 Code Style
“We’re in the business of keystrokes and neurons”
During development, it can be challenging to keep the code in your app-package clean and perfectly formatted. Fortunately, the R ecosystem has some excellent tools for making your code functional and easy to read.
27.1 Code style and formatting
The lintr
and styler
packages in R serve related but distinct purposes and have different focuses in their functionality. The primary difference between lintr
and styler
is that styler
can automatically fix any stylistic issues it identifies in your code (rather than just reporting them).
Launch app with the shinypak
package:
launch('21_style')
27.1.1 lintr
lintr
is a static code analysis tool used to identify syntax errors, semantic issues, and violations of stylistic guidelines in your code. The package contains a list of ‘linters’ for various potential problems and can be customized according to your needs. lintr is designed to help improve your code’s quality and readability by generating reports in the ‘markers’ pane. Running lintr
won’t automatically correct the identified issues (you’ll need to fix the linting issues it reports manually).
27.1.2 styler
On the other hand, the purpose of styler
is to ensure consistency in the code formatting, which is crucial if you’re working in a team or contributing to open-source projects (like tidyverse
packages). The styler
package will change your code’s format according to specified style guidelines. These changes include indentation, spaces, and line breaks that adhere to your style guidelines.
While there is some overlap (both packages can help enforce coding style guidelines), lintr
is a more general tool for code quality, spotting potential issues and bugs. At the same time, styler
focuses on code formatting and can automatically apply fixes. Many developers find combining both can help catch potential issues and ensure a consistent, readable coding style.
27.2 Checking your code
I’ve previously mentioned running devtools::check()
can be overkill for your app-package (especially if it’s not destined for CRAN). A nice alternative to check()
is the goodpractice
package..
goodpractice::gp()
inspects your package and prints any areas that might need ‘good practice’ advice:
library(goodpractice)
<- gp(path = ".")
pkg_checks pkg_checks
Preparing: description
Preparing: lintr
|====================================================================| 100%
Preparing: namespace
Preparing: rcmdcheck
── GP sap ───────────────────────────────────────────────────────
It is good practice to
✖ add a "URL" field to DESCRIPTION. It helps users find information about your
package online. If your package does not have a homepage, add an URL to
GitHub, or the CRAN package package page.
✖ add a "BugReports" field to DESCRIPTION, and point it to a bug tracker.
Many online code hosting services provide bug trackers for free,
https://github.com, https://gitlab.com, etc.
✖ avoid long code lines, it is bad for readability. Also, many people prefer
editor windows that are about 80 characters wide. Try make your lines
shorter than 80 characters
data-raw/tidy_movies.R:49:81
R/data.R:4:81
R/data.R:7:81
R/data.R:17:81
R/data.R:21:81
... and 13 more lines
✖ not import packages as a whole, as this can cause name clashes between the
imported packages. Instead, import only the specific functions you need.
✖ fix this R CMD check NOTE: display_type: no visible binding for global
variable
‘.rs.invokeShinyPaneViewer’ display_type: no visible binding for global
variable
‘.rs.invokeShinyWindowExternal’ display_type: no visible binding for global
variable
‘.rs.invokeShinyWindowViewer’ mod_scatter_display_server : <anonymous>: no
visible binding for global
variable ‘movies’ Undefined global functions or variables:
.rs.invokeShinyPaneViewer
.rs.invokeShinyWindowExternal
.rs.invokeShinyWindowViewer movies
We can also check specific components of our package by looking up the available checks in all_checks()
:
grep("import", x = all_checks(), value = TRUE)
[1] "no_import_package_as_a_whole"
[2] "rcmdcheck_undeclared_imports"
[3] "rcmdcheck_imports_not_imported_from"
[4] "rcmdcheck_depends_not_imported_from"
[5] "rcmdcheck_triple_colon_imported_objects_exist"
[6] "rcmdcheck_unexported_base_objects_imported"
[7] "rcmdcheck_unexported_objects_imported"
[8] "rcmdcheck_empty_importfrom_in_namespace"
All of the checks with the rcmdcheck_
prefix are part of the R CMD check
diagnostic, but goodpractice
comes with other checks that are good practices (even if you’re not submitting your package to CRAN).
For example, no_import_package_as_a_whole
checks the practice we covered in managing imports. If we pass the no_import_package_as_a_whole
check as a character vector to the checks
argument:
gp(path = ".", checks = 'no_import_package_as_a_whole')
Only this check is performed:
── GP sap ───────────────────────────────────────────────────
It is good practice to
✖ not import packages as a whole, as this can cause name clashes between
the imported packages. Instead, import only the specific functions you need.
───────────────────────────────────────────────────────────────────
27.3 Recap
This chapter covered an introduction to some tools and practices for improving and maintaining the quality of the code in your app-package. Maintaining code style and standards (lintr
and styler
) and performing thorough checks to adhere to best practices (goodpractice
) will ensure efficient and reliable development and deployment for your app.