闪亮的代码设计——我应该把复杂的逻辑放在哪里?

Shiny code design - where should I put the complex logic?

致所有 R Shiny 专家:您会将以下三个服务器功能中的哪一个评为第一、第二和第三?为什么?

我今天就三种解决方案中哪一种最接近 "best practice" 闪亮的应用程序设计进行了深入讨论。 (虽然它们三个的工作原理相同。)

例如,版本 C 对我来说似乎很奇怪,因为不需要有条件地覆盖渲染函数(因为条件输出渲染是这些函数的用途)。

当然,原始应用程序在处理输入值时包含更多逻辑。我简化了示例以使差异显而易见。

library(shiny)

ui <- fluidPage(

  shiny::radioButtons(
    inputId = "some_input", 
    label = "Please choose:", 
    choices = c("something", "nothing")
  ),

  shiny::textOutput(
    outputId = "some_output"
  )  

)

# version A: all logic within rendering function
server <- function(input, output, session) {

   output$some_output <- shiny::renderText({

       if(input$some_input == "something"){
         # imagine some complex logic here
         "some value was chosen"
       } else {
         NULL
       }

   })

}

# version B: most logic within input observer, 
# using reactive session userData
server <- function(input, output, session) {

  session$userData$memory <- shiny::reactiveValues(
    "stored_value" = NULL
  )

  output$some_output <- shiny::renderText({
    session$userData$memory$stored_value
  })

  shiny::observeEvent({
    input$some_input
  }, {

    if(input$some_input == "something"){
      # imagine some complex logic here
      session$userData$memory$stored_value <- "some value was chosen"
    } else {
      session$userData$memory$stored_value <- NULL
    }
  })

}

# version C: all logic within observer, 
# setting the rendering function conditionally
server <- function(input, output, session) {

  shiny::observeEvent({
    input$some_input
  }, {

    if(input$some_input == "something"){
      # imagine some complex logic here
      output$some_output <- shiny::renderText({ "some value was chosen" })
    } else {
      output$some_output <- shiny::renderText({ NULL })
    }

  })

}

shinyApp(ui = ui, server = server)

我绝不是 Shiny 专家,但由于 "best" 未定义,我想我会根据我创建的应用程序发表意见(没有提供支持文档)。

从最好到最差的顺序:

  1. 一个
  2. B
  3. C

推理:

C:虽然在多个地方使用 output$some_output 是可行的,但这样做绝不是好的做法,只会在代码中造成混乱

B:observeEvent 是重复的,因为 renderText() 旨在观察反应变量何时发生变化。我知道你有一个更复杂的应用程序,但在这个例子中存储到 reactiveValues 是过度的,没有获得任何好处。

A:非常简单的基本代码,可以无缝运行。您也可以争辩说您可以将 if statementrenderText() 中取出并将其包装在 reactive() 中以保持其清洁,但它们完成同样的事情。

我很好奇是否有人会做时间研究或有一些实际文档来支持 "best" 到 "worst"。