Development Best Practices

rstudio::conf(2022)
Building Production-Quality Shiny Applications

Eric Nantz

More to come

Warning

These slides are under construction and will be updated continuously until the workshop date.

All About Perspective

R is the standard-bearer for data analysis tooling

Shiny App Development

Not just providing another interface for data analysis

You are engineering an entire workflow

This Could Happen to You

Thinking of You

These principles can guide (future) you on the right path:

  • Rapid prototyping in design process
  • Deliberate control of app dependencies
  • Managing code complexity with native R frameworks
  • Defending against regressions with testing
  • Version control for collaboration and peace of mind

Rapid Prototyping

Blueprint for Rapid Prototyping

  • Elicit goals & requirements from customers early and often
  • Resist urge to perfect server-side processing right away
  • Bring a minimum viable product (MVP) to customers for feedback

Code-Along

Code-Along 1: Using the {shinipsum} package for rapid UI prototyping

Additional Tools

  • moqups.com: Streamlined web app to create wireframes, mockups, diagrams, and more
  • excalidraw.com: Collaborative whiteboard tool for sketching diagrams
  • Any presentation software (yes, even PowerPoint)

Application Dependencies

It’s Never Just Shiny

… at least for production-quality apps!

  • External data sources
  • Connections to other execution backends
  • Additional R packages!

Turned Upside-Down

Imagine your application is working great!


update.packages(ask = FALSE)
remotes::install_github("pkg")

Turned Upside-Down

ggplot2 version 0.9.3

ggplot2 version 1.0.0

Take Control with {renv}

Create reproducible environments for your R projects.

  • Next generation of {packrat}
  • Isolated package library from rest of your system
  • Transfer projects to different collaborators / platforms
  • Reproducible package installation
  • Easily create new projects or convert existing projects with RStudio or built-in functions.

Under the Hood

Upon initializing a project:

  1. Project-level .Rprofile to activate custom package library on startup
  2. Lockfile renv.lock to describe state of project library
  3. renv/library to hold private project library
  4. renv/activate.R performs activation

Develop a Routine

Sticking with {renv} will pay off (trust me)

  • Fair play to mix packages from CRAN, GitHub, and proprietary sources
  • Roll back when a package upgrade doesn’t play nicely
  • You make the call when to update your library!

Application Structure

A Single Point: app.R

Prototype apps can coast by with a single app.R

  • More inputs, visualizations, modules, tabs …
  • Eventually the app.R almost explodes
  • Difficult to collaborate without conflicts

R Directory

  • Shiny supports auto-loading scripts in an R directory
  • Nested directories not supported
  • More information on the App Formats article

Enter the {golem}

Opinionated framework for building production-grade Shiny applications as R packages

  • Scripts guide you with first steps akin to {usethis} & {devtools}
  • Encourages Shiny best practices (especially modules)
  • Streamlines deployment on multiple platforms

Code-Along

Code-Along 2: Create a new Shiny application using the {golem} framework

::: footer engineering-shiny.org

Enter the {rhino}

Create Shiny apps using software engineering best practices and development tools

  • App structure inspired by other web app stacks
  • Also encourages Shiny modules
  • Pre-configured development tools
  • Relies on {box} for importing functions
  • Automatic configuration of {renv} for package management

Code-Along

Code-Along 3: Create a new Shiny application using the {rhino} framework

Regression Testing

A Familiar Strategy

#> Error: Can't access reactive value 'x' outside of reactive consumer
#> ℹ Do you need to wrap inside reactive() or observer()?
#> Error: Unexpected character object for output$greeting
#> ℹ Did you forget to use a render function?

Enter {shinytest2}

{shinytest2} provides a streamlined toolkit for unit testing Shiny applications

  • Next generation of {shinytest}
  • Tightly coupled with {testthat}, used widely in package development
  • Powered by {chromote} to render applications in a headless Chrome browser