Join the R Community at ShinyConf 2023

Rhino R package for Shiny Developers in Enterprise - Top 5 Software Engineering Skills Rhino Brings to Shiny

Rhino for Shiny Developers: Top 5 Must-Have Software Engineering Skills


There are easier ways to build R Shiny apps, and the Rhino package is our solution for software engineers. In short, Rhino allows you to create Shiny apps like a full-stack software engineer by applying best practices, modularizing your code, testing it, making the UI beautiful, and providing a focus on user adoption from line one.

Rhino is developed in-house by the Appsilon team. The package focuses on best practices and development tools. The aim is to save time, avoid repetitive tasks, unify the application’s architecture, and automate and codify our best practices.

R Shiny Application Layouts are Changing – Make sure you’re up to date with the most recent changes.

Today you’ll see the 5 software engineering skills that Rhino incorporates into R Shiny. For a hands-on use case in Rhino, please stay tuned to the Appsilon blog – the use case will go live shortly.

Table of contents:

This article is co-authored by – Dario Radečić.


#1 – System Design and Large-scale Shiny Applications

It’s easy to make a small application with a couple of charts and not worry about system architecture. But what about large-scale applications? As your app gets larger, it will require thoughtful design, or your productivity as a developer will plummet. It’s essential to organize your code into modules with a well-defined purpose and clear interface – something we call separation of concerns.

Some programming languages have features to support modularization at various levels. For example, the latest versions of Sass and JavaScript do this pretty well. Vanilla R is lacking in this regard, but Rhino has several features to address it. Let’s cover them next.

Box modules in R

Rhino uses the box R package for all application code. It allows for organizing R code in a more modular way.

Each R file forms a module with its own namespace, and each object must be explicitly exported to be visible outside the module (encapsulation). A directory structure can be used to organize the modules, which isn’t the case with R packages.

Logic and view separation

Wait, what are logic and view? Here’s a simple explanation:

  • Logic: Code that can be expressed without Shiny.
  • View: Code that defines the UI and wires its elements together with reactivity.

At Appsilon, we found that separating these two is beneficial in our R Shiny applications because the code which does not rely on reactivity (logic) is more reusable and testable.

The Rhino package encourages logic-view separation but does not enforce it. You’re free to choose an architecture that will work best for your specific use case.

Read more about logic and view separation with code examples.

Shiny modules

Rhino encourages you to structure your UI code using Shiny modules for two reasons:

  1. They make it easier to understand the big-picture structure of your app.
  2. They let you avoid ID crashes in apps with a large number of inputs and outputs.

Even the top-level UI and server form a Shiny module. We find this results in more consistent and easier-to-refactor Shiny apps.

It’s also worth mentioning that Shiny modules play nicely with the box package. A typical box and Shiny module will export ui and server objects, resulting in much more readable code.

Learn more about Shiny modules in a free online Mastering Shiny book.

#2 – Writing Robust and Reproducible Code with Rhino

In R projects, it’s common to use library() call to import packages into a global namespace. It’s an easy and intuitive way to do it, so what’s the problem?

While it’s good for interactive and quick prototyping, it has a couple of serious drawbacks:

  • Brittleness: An update to a direct or transitive dependency can change the behavior of your app or crash it entirely.
  • Lack of isolation: There’s no way to use different package versions among different projects, which is sometimes required.
  • Name clashes and namespace pollution: It can be especially severe in long-term projects with multiple collaborators.

So, what does Rhino bring to the table? It brings explicit dependency management to your R shiny apps. At a project level, it uses the renv package with its lockfile, and at a file level, it uses the box package with its explicit imports and exports.

#3 – Rhino Testing Framework

Programming is not just about pumping out new features. Developers spend a large portion of their time testing existing features and making sure they work in all possible scenarios. Designing your code with testability in mind will typically lead to better overall architecture.

It’s crucial to ensure your code works correctly in a production environment, and what better way to achieve this than automated tests.

You need tests at different granularity levels, perfectly captured by the testing pyramid you can see below:

Image 1 - Testing pyramid (Credit: https://www.symbio.com/solutions/quality-assurance/test-automation/)

Image 1 – Testing pyramid (Credit: https://www.symbio.com/solutions/quality-assurance/test-automation/)

In reality, it’s difficult to set up a testing framework and ensure tests run regularly. That’s where Rhino chimes in with a complete setup out of the box:

#4 – Using Sass and JavaScript in Shiny

There’s no denying you can do amazing things with R and all of the packages it has to offer. Still, that’s not enough in some cases. Sometimes R won’t be flexible enough to meet the needs of your project.

JavaScript and Sass aren’t like that, and they allow for complete control over your application.

Rhino comes in with a project setup for JavaScript and Sass out of the box. Both are compiled and minified to offer you the latest features and maximum performance.

Want to learn more about Sass in R? See how to make CSS awesome in your R projects.

#5 – Consistency in Shiny Development using Rhino

And last but not least, there’s consistency. Everyone has their preferred code-writing style, and it typically boils down to personal preference. But does personal preference have a role in a large, multi-developer project environment?

It’s essential to keep the code style consistent across the entire project, especially when collaborating. It’s important for two reasons:

  1. A consistent code writing style makes the code easier to read.
  2. You’ll spend less time on code styling issues during code reviews.

In a nutshell, you should have a style guide, and you need to enforce it. What better way to do it than automation?

Rhino comes with linters and formatters for R, JavaScript, and Sass. These linters can automatically detect improperly formatted code, and even fix it in many cases.

As a bonus point, Rhino lints all your code automatically via GitHub actions.


Summing up: Rhino package for Better R Software Engineering

Enterprise projects require higher-level practices and tools. Rhino makes it easy for any R programmer to bring these five must-have software engineering skills to R Shiny. We hope you’ve liked this concise overview because there’s more to come. Explore our blog and stay tuned to Shiny Weekly for articles covering basic to advanced Rhino use cases with hands-on examples.

What’s your favorite way of managing large-scale R Shiny projects? Have you tried Rhino already? Please let us know in the comment section below. If you like the value Rhino gives, be sure to give the Rhino package a star on GitHub. Also, don’t hesitate to move the discussion to Twitter – @appsilon. We’d love to hear from you.

Considering a career in R Shiny? Here’s how a typical day in life of a Shiny Developer looks like.