Desenvolvendo um aplicativo R Shiny complexo – o bom, o ruim e o feio

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


[Esteartigofoipublicadopelaprimeiravezem[Thisarticlewasfirstpublishedon r-bloggers – Blog de ciência de dados WZB, e gentilmente contribuiu para os R-blogueiros]. (Você pode relatar um problema sobre o conteúdo desta página aqui)


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.

Juntamente com Clara Bicalho (UC Berkeley) e Sisi Huang (WZB), desenvolvi recentemente um aplicativo Web que funciona como uma interface conveniente para o pacote DeclareDesign R e seu repositório de projetos de pesquisa, DesignLibrary. Esse aplicativo da web, que chamamos de Assistente de DeclareDesign, permite aos usuários investigar e personalizar projetos de pesquisa em seu navegador. Usamos o R Shiny para implementá-lo e, como esse foi o meu primeiro grande projeto do Shiny, eu queria refletir um pouco sobre o processo de desenvolvimento e dizer em que partes o Shiny brilhou e em que não.

Histórico do projeto – DeclareDesign e o aplicativo “Wizard”

No começo, gostaria de fornecer algumas informações básicas sobre o projeto. Nosso aplicativo foi desenvolvido para (e com) a estrutura DeclareDesign (DD). O objetivo do DD é permitir que os pesquisadores descrevam seus projetos de pesquisa em código R, executem simulações por meio dessa definição de projeto e avaliem as propriedades dos estimadores de projeto, por exemplo. seu poder, preconceito ou outro diagnosticands. Ao usar R e um conjunto de “etapas de construção do design”, o DD é uma ferramenta bastante versátil – no entanto, também exige que o pesquisador esteja familiarizado com R. É aqui que nosso aplicativo DeclareDesign Wizard entra em cena. Existem vários projetos de pesquisa bem estabelecidos e o pessoal da DD os implementou na DesignLibrary como projetos parametrizados. Isso significa que você pode selecionar um design, por exemplo, uma experiência com dois braços, defina seus parâmetros (por exemplo, tamanho da amostra N ou desvio padrão no grupo de tratamento treatment_sd) e investigue propriedades como RMSE ou power, simulando o design.

O Assistente de DeclareDesign permite selecionar e personalizar os designs da DesignLibrary usando uma interface da Web conveniente. Em uma segunda etapa, você pode interrogar (ou diagnosticar) o design executando simulações para um intervalo de diferentes valores de parâmetros e plotando os resultados. Por exemplo, você pode variar N e treatment_sd e ver diretamente como eles afetam um diagnóstico e como o RMSE para um estimador em particular (fig. 1).

Fig. 1: Diagnosticando um projeto de pesquisa de dois braços para diferentes conjuntos de parâmetros.

Para saber mais sobre o aplicativo Assistente, consulte esta postagem do blog. Você pode experimentar o Assistente e enviar-nos um feedback, se quiser, ou relatar um problema no GitHub, se houver algum.

No restante deste artigo, focarei em minhas experiências com o Shiny durante o desenvolvimento do aplicativo.

O bom

O projeto começou com prototipagem rápida para um único design. O Shiny é ótimo para isso, pois você pode criar uma interface interativa para o código R existente com muita facilidade. No entanto, as coisas rapidamente se tornam complicadas quando você cria interfaces dinâmicas de usuário (UIs). No nosso caso, a maior parte da interface do usuário é criada on-the-fly. Quando um design de pesquisa é carregado da biblioteca, as propriedades desse design (por exemplo, os parâmetros que ele aceita, os diagnósticos disponíveis para ele etc.) determinam os campos de entrada que são criados. Não foi uma escolha predefinida para os elementos da interface do usuário para cada design e exibi-los seletivamente, devido ao grande número de designs com conjuntos de parâmetros muito específicos. Por exemplo, um design de dois braços aceita parâmetros para tamanho da amostra, probabilidade de atribuição ao tratamento e muito mais, enquanto em um design de dois braços de cluster de bloco você pode especificar o número de blocos, o número de clusters em cada bloco e o número de unidades em cada cluster. Alguns parâmetros aceitam apenas números inteiros, outros números reais e outros aceitam vetores de números (por exemplo, o design fatorial). A criação imediata dos elementos da interface do usuário também facilita a extensão do aplicativo, para que você possa adicionar novos designs com facilidade.

Embora a construção de uma interface de usuário dinâmica seja consideravelmente mais complicada, ela ainda pode ser implementada com eficiência com o Shiny, porque todos os elementos de entrada, como numericInput, textInput, etc. podem ser criados dinamicamente a partir do código. No entanto, existem vários desafios com essa abordagem: primeiro, toda a natureza assíncrona do front-end do Shiny cria a “linha do tempo” de quando determinadas ações são executadas imprevisíveis, especialmente quando você usa uma interface de usuário dinâmica. Por exemplo, tivemos que implementar um hack via JavaScript que indicaria que o aplicativo está atualmente mudando de um design para outro e que a interface do usuário desse novo design ainda não está totalmente carregada. Essa era a única maneira de impedir que alguma parte do código carregasse prematuramente valores da interface do usuário “antiga” (com valores do design anterior) e tentasse aplicá-lo ao novo design, o que obviamente falharia. Além disso, a complexidade adicional apresenta problemas com testes e depuração, que abordarei mais adiante. O próximo livro “Mastering Shiny” (H. Wickham, anunciado para o final de 2020) tem uma seção sobre como criar elementos de interface do usuário dinamicamente com código e acho que esse é um tópico importante para muitos desenvolvedores do Shiny.

Leia Também  Crie e implante um serviço preditivo do Custom Vision no R com o AzureVision

Começamos o desenvolvimento como um aplicativo Shiny de arquivo único com um número cada vez maior ui e server código. Ficou claro rapidamente que, de alguma forma, precisávamos reestruturar o código para mantê-lo sustentável. Felizmente, o Shiny fornece módulos e namespaces, que eu acho que são obrigatórios para aplicativos complexos. Criamos dois módulos – o módulo “design” e o “diagnosticar” (internamente: “inspecionar”), cada um representando uma fase do fluxo de trabalho e uma guia da interface do usuário no aplicativo Wizard e cada um com seu arquivo de código-fonte separado.

Em geral, o conceito de modularização Shiny funciona muito bem, embora a implementação da comunicação entre os módulos seja um desafio inicialmente e existam algumas peculiaridades que você precisa ter em mente ao programar. Por exemplo, você deve se lembrar de sempre declarar elementos da interface do usuário com espaços para nome no código da interface do usuário, mas na maioria das vezes você não usa espaços para nome no código do servidor (ou seja, quando você acessa um valor de entrada via input$...) Exceções notáveis ​​são a atualização de valores (por exemplo, o uso de updateTextInput()), criando dinamicamente novos elementos da interface do usuário e também abordando elementos da interface do usuário com shinyjs.

Outro recurso muito útil que nos poupou muito tempo, porque não precisávamos implementá-lo, é o recurso de favoritos. Isso nos permitiu implementar rapidamente um botão “compartilhar”. Com isso, os usuários podem carregar e ajustar um projeto de pesquisa e compartilhá-lo rapidamente com colegas. O recurso de favoritos garante que o estado do aplicativo, como é exibido atualmente no navegador, seja restaurado sempre que você visitar o link compartilhado. Nosso uso intenso de elementos dinâmicos da interface do usuário e objetos de estado personalizados tornou a implementação desse recurso não tão simples como é mostrado na documentação (devido a dificuldades relacionadas à natureza assíncrona já mencionada dos aplicativos Shiny), mas no geral funcionou muito bem.

Outro grande aspecto positivo do ecossistema Shiny é a documentação extensa e bem escrita e a grande comunidade ao seu redor que fornece bibliotecas de suporte e extensão. Usamos várias bibliotecas desenvolvidas pela comunidade, como shinyjs, shinymaterial ou shinyBS.

O mal

“Depurar aplicativos brilhantes pode ser um desafio”. Estas são as primeiras palavras da documentação do Shiny sobre depuração, que é uma leitura obrigatória absoluta para quem cria mais do que protótipos ou exemplos de brinquedos com o Shiny. Essas palavras são muito verdadeiras, como experimentei por conta própria.

Antes de tudo, eu estava acostumado a desenvolver aplicativos da Web com estruturas como Django (uma estrutura da Web Python) e um IDE como o PyCharm e esperava que o depurador funcionasse normalmente: você define um ponto de interrupção em algum lugar do código por meio da interface do IDE. Você executa o código no modo de depuração. O depurador entra no ponto de interrupção quando esta linha de código está prestes a ser executada e você pode investigar a situação.

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

Não é assim com Shiny resistente. Como a documentação mencionada diz: “Por razões técnicas, os pontos de interrupção só podem ser usados ​​dentro do shinyServer função. Você não pode usá-los no código em outros arquivos .R “. Portanto, desde que colocamos nosso código em vários arquivos .R, essa maneira de depurar é impossível para nós, a menos que desejemos depurar algo na central app.R Arquivo. Felizmente, há resgate para esta situação: você pode usar browser() onde quer que você coloque um ponto de interrupção, isso fará com que o depurador entre nesse ponto, não importa em qual arquivo você o esteja usando. No entanto, lembre-se sempre de remover o browser() quando você confirma seu código em um repositório.

Leia Também  Mesmo período do ano que vem: análise de dados do PubMed

Antes que eu soubesse sobre browser()Eu escrevia print() declarações em vez disso, que pareciam um anacronismo e me lembraram os dias em que conheci a programação. Ainda preciso recorrer a esse anacronismo de tempos em tempos, porque você nem sempre quer interromper a execução do programa como browser() faz.

Também há mais ferramentas de depuração disponíveis para o Shiny: o modo Mostrar mostra as partes do seu código que são executadas enquanto você interage com seu aplicativo. Infelizmente, o recurso de destaque travou o RStudio ao testá-lo com o aplicativo Assistente no meu computador. De qualquer forma, acredito que não é tão útil, pois você não vê os valores de suas variáveis ​​durante o tempo de execução.

Finalmente, há o reactlog que registra e visualiza os estados reativos de um aplicativo Shiny como um gráfico de dependência dinâmico. Devo admitir que experimentei apenas um pouco, pois já estava vislumbrado pela complexidade do gráfico gerado ao clicar apenas no botão “Carregar design” do nosso aplicativo (fig. 2). Também não consegui encontrar uma maneira de aumentar o zoom no gráfico, exceto selecionar aleatoriamente um nó (aleatoriamente porque os rótulos são ilegíveis), que mostra um gráfico parcial. Eu acho que é provavelmente uma ferramenta muito útil, pois pode ajudar a entender a estrutura de reatividade muito complexa de um aplicativo Shiny que geralmente parece uma “caixa preta”, mas a ferramenta em si requer uma quantidade considerável de treinamento.

Fig. 2: Saída do reactlog após clicar em “Carregar design”. Não, também não consegui identificar os rótulos.

Portanto, existem várias abordagens para depurar aplicativos Shiny, mas não estou totalmente satisfeito com nenhum deles. Não importa qual técnica de depuração eu use, a maior frustração para mim é ter que “repetir” manualmente várias etapas do aplicativo, por exemplo, clicando em certos botões, inserindo certos valores etc. para alcançar um estado que eu quero depurar. Você não pode simplesmente executar um script como faria com o código R comum. Ainda não encontrei uma ferramenta para ajudar com esse problema.

O feio

O teste automatizado é essencial ao desenvolver qualquer outra coisa, exceto protótipo de software. Ele garante que você não introduza novamente os erros que você já corrigiu ou que seu aplicativo seja interrompido quando você atualizar uma dependência. Acelera o desenvolvimento porque você não precisa clicar nas mesmas coisas repetidamente para verificar se o aplicativo funciona conforme o esperado após a alteração de algum código.

Portanto, para um aplicativo Shiny complexo como o nosso, precisávamos de testes automatizados também. Para testar o código R, geralmente você pode usar testthat ou RUnit. No entanto, ao desenvolver um aplicativo brilhante, isso não vai muito longe. Com isso, você não poderá testar o aplicativo interativo real, mas apenas certas funções (auxiliares) que são na sua maioria independentes das entradas interativas e brilhantes.

É aqui que o pacote shinytest é útil (pelo menos teoricamente). Funciona de maneira bastante diferente em comparação às abordagens de teste tradicionais: com o teste mais brilhante, você registro um determinado estado do aplicativo (do qual você sabe que funciona conforme o esperado) enquanto interage com ele. Esse estado é salvo no disco (por meio de capturas de tela e dados de entrada / saída gravados) e pode ser “reproduzido” a qualquer momento. Depois de reproduzi-lo (por exemplo, após alterar algum código), o aplicativo recebe as mesmas entradas (ou seja, clica nos mesmos botões, mesmos valores de entrada etc.) e o teste mais brilhante compara se a saída (ou seja, as capturas de tela e os dados de saída) mudou. Obviamente, ele também percebe quando uma exceção ocorre durante o “replay”.

Além das limitações óbvias (por exemplo, você precisa gravar todos os testes novamente depois de fazer alterações na interface do usuário porque as capturas de tela são alteradas), isso pode ser uma ferramenta realmente útil. Infelizmente, não conseguimos rodar por causa de um bug já conhecido no teste mais brilhante. Portanto, pelo menos para nós, o teste automatizado está disponível apenas parcialmente (implementamos alguns testes do RUnit para funções auxiliares), o que atrasa o desenvolvimento e é bastante frustrante, porque você precisa executar várias tarefas de teste super repetitivas manualmente.

Leia Também  Orçamento da União e seu plano financeiro?

Conclusão

Em suma, o Shiny é um pacote de software extremamente útil que não ajuda apenas a comunicar resultados de pesquisa ou fatos e conceitos em ciências (por exemplo, como uma ferramenta para o ensino). Conforme mostrado em nosso aplicativo, também pode ajudar a preencher a lacuna entre um público-alvo R e não-R para o seu pacote R existente. Pessoas que não estão familiarizadas com o R agora também podem usar partes do DeclareDesign para descrever, personalizar e interrogar projetos de pesquisa. Como nosso aplicativo também fornece código R gerado para criar o design especificado e plotar seus resultados de diagnóstico, o “público não-R” obtém uma primeira impressão e motivação para ajustar o código R e talvez até uma motivação para aprender R.

A grande vantagem de usar o Shiny no nosso caso foi que poderíamos usar diretamente o pacote DeclareDesign R para criar uma interface da Web sem nenhuma camada adicional e até mesmo uma linguagem de programação diferente. Pode haver estruturas da Web interativas mais avançadas, que podem ser mais rápidas, ter menos problemas com relação a testes e depuração automatizados e parecer menos uma “caixa preta”. No entanto, se tivéssemos usado, por exemplo, um front-end do React.js e um back-end do Django REST, precisaríamos interagir com o R do Python e usar pelo menos três linguagens de programação diferentes, e duvido que a depuração seja mais fácil nesse caso.

O que torna frustrante o desenvolvimento de aplicativos Shiny às vezes é a falta de uma boa ferramenta de teste automatizada, os relacionamentos extremamente complexos e dinâmicos entre vários componentes de entrada e saída para aplicativos grandes e o desafiador procedimento de depuração que acompanha essa complexidade. Eu acho que é difícil depurar a natureza de qualquer sistema interativo, por isso não surpreende que Shiny também lute com isso. No entanto, um primeiro passo seria comunicar com mais clareza que a depuração com pontos de interrupção não funciona com aplicativos Shiny (a menos que você tenha todos código em um único arquivo) e que você precisa browser() em vez de. Em seguida, deve haver uma maneira fácil de gravar e reproduzir as interações que você executa com seu aplicativo, para que você não precise repetir o clique aqui e ali para que o aplicativo atinja o estado necessário para a depuração. Acho que a base para isso já existe, já que o shinytest também faz isso, mas não visa a depuração e nem sempre parece funcionar como experimentamos com nosso aplicativo. Um sonho seria algo como o Reverb, que permite gravar, reproduzir e até alterar o estado atual durante a depuração (“depuração especulativa”), mas isso ainda é uma pesquisa.

Para testes automatizados, seria bom ter uma opção para gravar apenas o que é exibido e não como é exibido quando você constrói casos de teste com o teste brilhante. No momento, o teste mais brilhante compara o resultado do teste atual e esperado com as capturas de tela, mas acho que um teste não deve falhar quando você altera deliberadamente a cor de um título. Em vez disso, deve falhar quando o título diz algo diferente do que foi registrado no caso de teste. Caso contrário, você terá que recriar todos casos de teste após cada pequena alteração visual no seu aplicativo.

Dito isso, não me arrependo de termos usado o Shiny para desenvolver o aplicativo Assistente do DeclareDesign e espero que, no futuro, o Shiny se torne uma ferramenta ainda mais produtiva ao criar aplicativos complexos.

var vglnk = {key: ‘949efb41171ac6ec1bf7f206d57e90b8’};

(função (d, t) {
var s = d.createElement
s.src = ‘//cdn.viglink.com/api/vglnk.js’;
var r = d.getElementsByTagName
} (documento, ‘script’));

Para Deixe um comentário para o autor, siga o link e comente no blog: r-bloggers – Blog de ciência de dados WZB.

R-bloggers.com oferece atualizações diárias por email sobre notícias e tutoriais do R sobre o aprendizado do R e muitos outros tópicos. Clique aqui se você deseja publicar ou encontrar um emprego em ciência da dados / R.


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.



cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br