Introduction
Using R package development practices will boost your productivity when building applications and make it easier for your collaborators. First, you will have a clear structure for your files. Second, others can easily share and use your work.
A guiding principle in this book comes from the Benjamin Franklin quote,
“A place for everything, everything in its place”
Packages help you
Do future you a favor.
Standardizing your projects helps anyone reading your code, especially future you. By structuring every Shiny app like an R package, you save time on setup (or re-orienting yourself to each project’s structure). Clear code is essential for Shiny applications in production, and using an R package is a common way to organize your code.1
“a package [is] the fundamental unit of shareable, reusable, and reproducible R code.” - R Packages, 2ed
If you’re using RStudio or Positron, the package structure lets you access user-friendly tools for developing Shiny applications. These tools help you develop and test functions, run unit tests, store data, manage dependencies, and create documentation.
Packages help them
Assume someone else will read your code.
R packages provide a standardized way to enhance R’s capabilities, allowing others to install and use them in their R environment. When developing Shiny apps for production deployment, it’s important to remember that the code will likely be accessed and used by others.
To quote Marie Kondo, the de-cluttering expert,
“Ensuring that each one of your belongings has its own spot is the only way to maintain a tidy and clutter-free home. Clutter has nothing to do with what or how much you own – it’s the failure to put things back where they belong.”
R packages simplify sharing your work with colleagues by eliminating the need for them to determine where everything is located, how everything connects, and how it works.
Packages are scalable
Great R packages solve common problems.
If you’ve developed R functions for tasks such as analysis, data visualization, or report generation, consider creating a package instead of using source() to load them. This approach will help you expand your understanding from specific use cases (e.g., “this code performs a specific task”) to a broader perspective (e.g., “this package can perform various tasks”).
The advantage of having a mental model for R packages is that you will often observe similarities in common problems. Developing packages that address and solve frequent issues in your workflow can lead to some of the most valuable and popular contributions, as seen with packages like datapasta and reprex`.
Packages to know
I highly recommend reading and bookmarking the Shiny articles and the sites for the core package development tools:
How to read this book
Transitioning from programming in R to building Shiny applications and writing R packages presents a steep learning curve. The chapters in this book are aimed flattening the package development portion of that curve. As with any new skill, app-package development involves new mental models, concepts, terminology, habits, and details. If you find yourself getting frustrated, I recommend the 15 minute rule:
“By forcing yourself to try for 15 minutes, you gain a deeper understanding of what you’re troubleshooting so that, even if you don’t fix it in 15, next time you’re in a better position to troubleshoot than you were the last time.
And by forcing yourself to ask for help after 15, you not only limit the amount of banging-your-head time, but you also get to see how the other person solves the problem while all the details are still fresh in your mind, so that you’ll more likely have a deeper understanding of why what you were doing to fix it wasn’t working, and why the ultimate solution actually worked.” - Hacker News, 2013
The chapters in this book (roughly) represent the steps of R package development, but through the lens of an existing Shiny application.2 Each topic can be applied to creating a new app-package, but–in my experience–many Shiny developers have existing applications they’d like to convert into an R package.
The stable stuff
The first two sections contain topics that aren’t likely to change anytime soon. Introduction covers the development of a Shiny app project and it’s gradual progression of complexity to warrant an R package. The app-packages section applies the key components of R package development to a Shiny app.
1 Whole app game is a ‘whole game’ for the development of a toy app-package. This chapter gives a high-level overview of the app-package development workflow.3
In 2 Shiny we’ll dive into shiny development, focusing on the files and folders found in most Shiny applications.
R packages are introduced in 3 Packages, and it covers the differences between Shiny app projects, R packages, and Shiny app-packages.
4 Development introduces
devtoolsand the app-package development workflow.5 Documentation covers documenting the application’s utility functions, modules, UI, server, and standalone app function using
roxygen2.Managing dependencies (both imports and exports) using the
NAMESPACEfile is introduced in 6 Dependencies7 Data discusses the storage, format, and documentation of data files your app-package.
There are multiple ways to launch an application from an app-package. 8 Launch covers options to include in the
app.Rfile and your standalone app function.9 Resources covers the many uses of the
inst/folder in R packages. This chapter also covers how to add external files and resources to your application.
The opinionated bits
The sections below represent my approach to developing app-packages. Most of these practices come from the same resources referenced above, but there are many ways to debug and test your code.
Debugging is an important part of development, both for R packages and Shiny apps. This section contains chapters on using an interactive debugger and other methods for ensuring you can reliably investigate and address bugs in your code quickly and effectively.
10 Debuggers covers using R’s interactive debugger,
browser(), to pause execution and inspect a Shiny app’s reactive values, then applies it in a worked example with theggplot2moviesapp.11 Print debugging explains print debugging techniques, including wrapping
print()andcat()inobserve()and usingreactiveValuesToList()to expose an app’s reactive values in the UI.12 Debugging apps gives strategies for debugging Shiny app-package modules, covering UI function debugging, server function debugging, and diagnosing communication between modules.
13 Logging describes how to add structured logging to your app-package with base R and the
loggerpackage, a strategy that complements interactive and print debugging in production environments.
While developing your application, you’ll want to ensure it’s features are documented and tested. The Tests section covers testing:
Before running any tests we need to set up the test suite in our app-package. 14 Test suite briefly covers setting up the testing infrastructure with
testthat.Knowing what features to implement and what tests to develop reduces the chances of writing code that doesn’t address a user needs. 15 Specifications discusses how to identify user specifications, features, and functional requirements. It also briefly introduces behavior-driven development.
16 Test tools covers how to include testing tools (fixtures and helpers) in your test suite to ensure isolated yet controllable test conditions.
Reactivity makes testing modules tricky. In 17 Testing modules, I’ll cover some strategies and approaches for verifying that your modules are communicating correctly with Shiny’s
testServer()function.18 System tests introduces performing system (or end-to-end) tests in you app-package with the
shinytest2package.
After you’ve developed your Shiny App-Package, you’ll likely want to deploy it (or put it ‘into production’). A selection of popular methods are covered in Deploy:
19 shinyapps.io describes publishing an app-package to shinyapps.io with the
rsconnectpackage, and how to read the deploy and app logs to troubleshoot a failed or misbehaving deployment.20 Docker explains how build Docker images and containers using Docker desktop. These topics are also covered in 23 golem.
21 GitHub Actions covers continuous integration (CI) / continuous deployment (CD) for Shiny app-packages using GitHub Actions.
22 pkgdown websites are an excellent way to enhance it’s visibility and usability of your app-package (and it’s made seamless with
usethisand GitHub actions (see Deploying your site)).
Frameworks
If you’re Googling ‘what is the best way to build a Shiny application?’ you’ll eventually encounter a Shiny framework. This section contains the development workflow and methods for three popular Shiny application frameworks (golem, leprechaun, charpente and rhino).
23 golem covers developing an application using the
golemframework (which is introduced in Engineering Production-Grade Shiny Apps).For developers looking for a ‘lightweight’ version of the
golempackage, 24 leprechaun introduces theleprechaunpackage and development workflow25 rhino covers how to build a
rhinoapplication (which is not technically a package, but is still worth including based on it’s popularity and features).
LLM tools
The LLM tools section covers using LLM-assisted tools during app-package development, from the Shiny Assistant chatbot to the ellmer package and the chores and gander packages by Simon Couch.
26 Shiny Assistant covers the Shiny Assistant, an AI-powered chatbot that can build a Shiny application from scratch or make changes to an existing one.
27 ellmer introduces the
ellmerpackage, which gives us access to LLM providers and serves as the backbone for the other LLM tools covered in this section (chores,gander, andbtw).28 chores covers the
chorespackage, an RStudio and Positron addin for repetitive, hard-to-automate tasks like writingroxygen2documentation andtestthattests.29 gander introduces the
ganderpackage, which reads context directly from your R environment and the open file you’re working in, letting you ask questions about your code in-place instead of supplying context via a prompt.30 🏗 btw (this chapter is under construction)
Special topics
The special topics section includes a handful of topics on development, UI developement tools, code styling, storing and retrieving data, reading error outputs, using R6 objects, and keeping track of dependencies.
31 🏗️ Shiny UI Editor (this chapter is under construction)
32 Code style covers formatting your app-package’s code consistently and checking it for common problems with the
goodpracticepackage.33 🏗️ App data explores the differences between and use of
shiny::reactiveValues()andsession$userData.34 R6 (this chapter is under construction)
35 Stack traces (this chapter is under construction)
36 🏗️ Dependency hell (this chapter is under construction)
David Neuzerling has a great post on the benefits of structuring your project as a package↩︎
The original code and data for the application in this book comes from the Building Web Applications with Shiny (BWAS) course.↩︎
R Packages, 2ed, has a similar chapter that covers developing standard R packages.↩︎