Rhino for Shiny Developers: Top 5 Must-Have Software Engineering Skills
There are <strong>easier ways to build R Shiny apps</strong>, and the <strong><a href="https://appsilon.github.io/rhino/" target="_blank" rel="noopener">Rhino</a></strong> package is <strong>our solution for software engineers</strong>. 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. <blockquote>R Shiny Application Layouts are Changing - <a href="https://appsilon.com/shiny-application-layouts/" target="_blank" rel="noopener">Make sure you're up to date with the most recent changes</a>.</blockquote> 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: <ul><li><a href="#skill-1">#1 - System Design</a></li><li><a href="#skill-2">#2 - Writing Robust and Reproducible Code with Rhino</a></li><li><a href="#skill-3">#3 - Testing</a></li><li><a href="#skill-4">#4 - Using Sass and JavaScript with Rhino</a></li><li><a href="#skill-5">#5 - Consistency</a></li><li><a href="#summary">Summing up Rhino Software Engineering Skills</a></li></ul> <i>This article is co-authored by - <a class="UserCard-module--linkName--ElcHI" href="https://appsilon.com/author/dario/" target="_blank" rel="noopener">Dario Radečić</a>.</i> <hr /> <h2 id="skill-1">#1 - System Design and Large-scale Shiny Applications</h2> It's easy to make a small application with a couple of charts and not worry about system architecture. <b>But what about large-scale applications?</b> 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 <b>separation of concerns</b>. 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. <h3>Box modules in R</h3> Rhino uses the <a href="https://github.com/klmr/box" target="_blank" rel="nofollow noopener">box</a> 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. <h3>Logic and view separation</h3> Wait, what are logic and view? Here's a simple explanation: <ul><li><b>Logic</b>: Code that can be expressed without Shiny.</li><li><b>View</b>: Code that defines the UI and wires its elements together with reactivity.</li></ul> 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 <a href="https://appsilon.github.io/rhino/articles/explanation/application-structure.html" target="_blank" rel="noopener">logic and view separation with code examples</a>. <h3>Shiny modules</h3> Rhino encourages you to structure your UI code using Shiny modules for two reasons: <ol><li>They make it <strong>easier to understand</strong> the big-picture structure of your app.</li><li>They let you <strong>avoid ID crashes</strong> in apps with a large number of inputs and outputs.</li></ol> Even the top-level UI and server form a Shiny module. We find this results in more <strong>consistent</strong> and <strong>easier-to-refactor Shiny apps</strong>. It's also worth mentioning that Shiny modules play nicely with the <code>box</code> package. A typical box and Shiny module will export <code>ui</code> and <code>server</code> objects, resulting in much more readable code. <a href="https://mastering-shiny.org/scaling-modules.html" target="_blank" rel="nofollow noopener">Learn more about Shiny modules in a free online Mastering Shiny book</a>. <h2 id="skill-2">#2 - Writing Robust and Reproducible Code with Rhino</h2> In R projects, it's common to use <code>library()</code> 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: <ul><li><b>Brittleness</b>: An update to a direct or transitive dependency can change the behavior of your app or crash it entirely.</li><li><b>Lack of isolation</b>: There's no way to use different package versions among different projects, which is sometimes required.</li><li><b>Name clashes and namespace pollution</b>: It can be especially severe in long-term projects with multiple collaborators.</li></ul> So, what does Rhino bring to the table? It brings <b>explicit dependency management</b> to your R shiny apps. At a project level, it uses the <a href="https://rstudio.github.io/renv/articles/renv.html" target="_blank" rel="nofollow noopener">renv</a> package with its lockfile, and at a file level, it uses the <a href="https://github.com/klmr/box" target="_blank" rel="nofollow noopener">box</a> package with its explicit imports and exports. <h2 id="skill-3">#3 - Rhino Testing Framework</h2> 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 <b>automated tests</b>. You need tests at different granularity levels, perfectly captured by the testing pyramid you can see below: <img class="size-full wp-image-16327" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d3187b3b084627442d22_6cd6e904_1-5.webp" alt="Image 1 - Testing pyramid (Credit: https://www.symbio.com/solutions/quality-assurance/test-automation/)" width="679" height="366" /> 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: <ul><li>Unit tests with R <a href="https://testthat.r-lib.org" target="_blank" rel="nofollow noopener">testthat</a> (R package).</li><li>E2E tests with <a href="https://docs.cypress.io/guides/getting-started/installing-cypress" target="_blank" rel="nofollow noopener">Cypress</a> (Node.js package).</li><li>Automated runs of both types of tests via <a href="https://docs.github.com/en/actions" target="_blank" rel="nofollow noopener">GitHub actions</a>.</li></ul> <h2 id="skill-4">#4 - Using Sass and JavaScript in Shiny</h2> 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. <blockquote>Want to learn more about Sass in R? See <a href="https://appsilon.com/how-to-make-your-css-awesome-with-sass/" target="_blank" rel="noopener">how to make CSS awesome in your R projects</a>.</blockquote> <h2 id="skill-5">#5 - Consistency in Shiny Development using Rhino</h2> And last but not least, there's consistency. Everyone has their preferred code-writing style, and it typically boils down to personal preference. <b>But does personal preference have a role in a large, multi-developer project environment?</b> It's essential to keep the code style consistent across the entire project, especially when collaborating. It's important for two reasons: <ol><li>A consistent code writing style <strong>makes the code easier to read</strong>.</li><li>You'll spend <strong>less time on code styling issues</strong> during code reviews.</li></ol> 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, <strong>Rhino lints all your code automatically</strong> via GitHub actions. <hr /> <h2 id="summary">Summing up: Rhino package for Better R Software Engineering</h2> 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. <i>What's your favorite way of managing large-scale R Shiny projects? Have you tried Rhino already?</i> Please let us know in the comment section below. If you like the value Rhino gives, be sure to <a href="https://github.com/Appsilon/rhino" target="_blank" rel="noopener">give the Rhino package a star</a> on GitHub. Also, don't hesitate to move the discussion to Twitter - <a href="http://twitter.com/appsilon" target="_blank" rel="noopener">@appsilon</a>. We'd love to hear from you. <blockquote>Considering a career in R Shiny? <a href="https://appsilon.com/a-day-in-life-of-an-r-shiny-developer/" target="_blank" rel="noopener">Here's how a typical day in life of a Shiny Developer looks like</a>.</blockquote>