Documenting modules and other constructs within a shiny app


#1

Hello everyone! Lately I’ve been creating applications comprised of many shiny modules and often each of them have some or many reactives to streamline processing. Most of the modules are still application specific, so they won’t likely be converted to an internal R package. With that said, how do others developing large-scale applications document their modules and other components? I’ve thought about using the Roxygen style to document the modules, although my reactives aren’t constructed with input parameters.


#2

Hi Eric, can you elaborate on “my reactives aren’t constructed with input parameters”?


#3

Sure, sorry I was not clear. What I meant by input parameters is more around typical R function parameters, not the specific inputs available in a shiny app. I typically have a lot of reactives within each of the modules, and they constructed much like this:

# important reactive to create processed result
reactive({ 
  # a bunch of R code lines that do something important
  return(some_object)
})

The only parameter I define explicitly in reactive is of course the expression of R code. Contrast that with the typical module UI and server functions such as coolModuleUI <- function(id, param1, param2, <etc>) { # ui code } and coolModule <- function(input, output, session, param1, param2, <etc>) { # server-side code } that have obvious parameters and hence can be documented in a similar way as say any R function in a package with Roxygen or other means. So I’m just struggling with how to ensure that the rest of the developers on my complex apps can fully grasp the intent and purpose of all of these reactives inside the modules, and finding an effective way of documenting those in addition to documenting the module functions themselves. Hope that makes more sense!


#4

Maybe have the reactive parts be wrappers for functions defined and documented elsewhere? Like:

#' Do some stuff
#' @param a A nice description
#' @param b A great description
#' @return Final stuff
do_stuff <- function(a, b) {
  # Important stuff done
  some_object
}


reactive({
  do_stuff(input$param1, input$param2)
})

#5

@nwerth that’s a nice approach and likely the most accessible means of documenting reactives, as long as I can convert the underlying processing to reusable functions. What would be really cool is if I do end up using ROxygen style documentation throughout app, then be able to compile a reference manual (similar to any R package) of all of these functions so I could have that as a reference in my app’s repository. I wonder of such a thing is possible?


#6

You might benefit a lot by creating a package with your Shiny application. Packages don’t need to be generalized or called elsewhere. They’re a great way to share a large amount interdependent objects with documentation.

I maintain an internal dashboard using an R package. It doesn’t affect what the user sees, but it helps me keep track of everything. And when I pass it on to the next guy, he/she won’t be totally lost.


#7

It does seem like that’s the best direction to take, especially for massive shiny apps. The hardest part will be adhering to the structure from the start! But the benefits would make it worth the effort.


#8

This is something I’ve been thinking about recently, too. The way I see it I have two options:

  1. Write a separate document (something like a vignette) that contains documentation for each reactive or
  2. Create wrapper functions for each reactive (some of mine have that already) and then document those in the “normal” manner using an R package/roxygen2 comments. You could even wrap the app up in the package, similar to how @daattali describes creating an example app for a package here.

The first option is perhaps a good short-term solution for a simple app that you just need to describe to others at a high level. I lean towards the second option for more complex apps, or one where you have collaborators (even future-you!) who will need to understand more of the detail.


When to use modules
#9

Excellent points @jim89. For my biggest production app I’ve gone with option 1 but I think my next version will go the package route. I’m glad I am not the only one who’s thinking of these issues!