Best practices for version-controlled shiny modules

What are lessons-learned and best-practices for version control of modules and use with production shiny apps?

It seems to me that the "most proper" method would be to use packages for everything: combine closely-related modules into one package, then reference that package within the shiny app; perhaps even follow Mango's (Mark Sellors') discussion on Packaging Shiny applications: A deep dive for the app itself.

But this is not without difficulty, as non-CRAN package management can be non-intuitive or non-trivial for some enterprise installations (perhaps remedied by RStudio's Package Manager, I have no experience with it). I tend to use a local repo for my RSC server, but because of needing to pierce two firewalls to get to it, copying files there takes extra steps that are not easily generalized.

Compromises/alternatives include much simpler directory/repo structures, perhaps just an app.R and my_module.R in individual repos. However, module dependency then needs to discuss git submodules or git subtree (comparison at Git subtree: the alternative to Git submodule at Atlassian).

For those who have tried extensive use of packages (the app and/or the modules), what are your lessons learned? Is using packages (with larger less-trivial apps) beneficial enough? Is there anything that is prohibitively difficult in using packages? ... in not using packages?

3 Likes

There is a new package to help with shinyapp development. It uses the package structure to better develop, document and test shinyapp, using modules along the way.

A blog post present the why of this :package: : Having a Framework to stick closely to a working worflow

There is also a book in writing

You may find some help and or answer in this

5 Likes

Those are great tutorials, thank you for sharing, @cderv! I learned several nice tricks in there that I will likely incorporate into my habit patterns.

The theme of formal package development is consistent in those docs. I don't know that it was obvious in the OP, but my specific question is in developing shiny modules to be used among multiple apps (i.e., any problems in doing so), so the golem:: package does not add anything specific to the use of shiny modules defined elsewhere. (It is apparent, though, that if those modules are in a separate package, just load that package ...)

Perhaps nobody will come forward with production-problems with developing shiny modules in packages, which would make sense, I think.

Thanks!

2 Likes

There is another quite new new package to help with shinyapp development. It forces the developer to think about scoping and it uses modules for common functionality in apps like downloadable tables and plots.
It's a public package and on CRAN, so no problems with deployments. The developer just need to be sure to have the right package version installed alongside the apps

3 Likes

Thanks! I see this as another good reference for building standalone shiny apps, but I don't immediately see how it provides information on referencing externally-maintained modules. What am I missing?

The periscope package gives a structure for shiny apps indeed, but you could see it as well as an example of externally-maintained modules. In the README of the package there's a description on how you can use the modules in a shiny application.
I am aware that not everyone can make their work public on CRAN, so the deployment could be a bit more difficult with private/local packages. But once you have it installed, the usage in the app can work in a similar way

1 Like

Thanks for the link to periscope - it is a really amazing package. It reminds me a lot of a great scaffolding package in Java, jhipster https://www.jhipster.tech/

1 Like

Don't get me wrong, @ginberg, it's an interesting package. But while they do have suggestions on shiny modules to use, I don't see any discussion of how to incorporate/maintain modules that are version-controlled in repos other than the current app.

Let's say I have a version-controlled app named shinyAppA. If there is a module I want to use (say shinyModuleB from a company repository of modules maintained for branding/consistency) that is maintained in a separate git repo, it seems that I can do one of a few things:

  1. Copy the file directly into my current app. I can choose to track it in the local-app's git, but that does nothing to facilitate merging in upstream changes to the module; for that, I'd need to copy the whole file into place again and commit any changes. Granted, this is not hard, just seems odd. I think this workflow is why we have things like git submodule and git subtree (each with pros/cons).
  2. Reference the module upstream repo with git submodule or git subtree. The version of the module I'm currently using in shinyAppA is locked (i.e., it is not auto-updated ... a good thing, I think) but it is easy enough to update. Its changes are not tracked in my local-app's git logs, which is also a good thing.
  3. If the module is written as an R package, then I don't need to copy the file over at all: I can just reference the companymodules::shinyModuleB() package/function within the app (perhaps with library(companymodules)), and when I deploy with rsconnect::deployApp(...), it will look to install that package of modules onto the RSC server.

I'm thinking that number 3 is the best way to go (assuming the modules are available within packages). Since I'm currently in the position of writing both the app and modules to use across a spectrum of company shiny reports/dashboards, then I can control the package-ness of things.

Does that make sense? Am I missing something in periscope that discusses this aspect of shiny-app maintenance? I didn't read everything in the package, but the vignettes did not include key words/references that I was looking for with this topic in mind.

@r2evans It sounds like you are describing the workflow to create packages for both your modules and your shiny applications which I think is the best path forward. The applications would explicitly depend on a particular version of your shiny modules. The dependency requirement is well handled if you have access to a cran like repository that you can host your packages on such as https://www.rstudio.com/products/package-manager/ or http://dirk.eddelbuettel.com/code/drat.html

There is a lot of great tooling around packages, including the ability to test your packages so they don't break something, https://www.tidyverse.org/articles/2017/11/usethis-1.0.0/

@r2evans, re-reading your initial post, I think the best solution for you would to have a central repository to handle your packages - Rstudio package manager has worked very well for us.

@r2evans you are right, periscope does not include anything in particular about shiny-app maintenance. I thought it would be useful to give an example of how to use modules from a package in a shiny app. It works the same as your number 3 solution basically. Though your situation might be more complex with different repo's and/or with non-CRAN packages

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.