- Poor Environment Reproducibility – slightly different configurations across and between dev, test and CI/CD environments result in “works on my machine” issues and time wasted reproducing bugs, delaying time to market.
- Supply Chain Security – installing prebuilt binary gems is convenient, but risky. On the other hand, building binary gems from source code can be time and resource intensive, as well as frustrating.
But with agile software development now the norm, the pressure to deliver code faster has increased, making creative workarounds for common gem and environment management shortcomings less and less viable.
This blog post can help you understand how to avoid these shortcomings and get back to coding faster.
Not all Ruby Package Managers Are The Same
In general, open source package managers have evolved and diversified over time, from:
- Simple Package Management, which focused mainly on installing and uninstalling packages.
- Dependency Management, which focuses on ensuring that the packages you install will all work together and avoid version/dependency conflicts.
- Bundler is a good example here, because it helps ensure that different projects can have a different version of the same gem.
- Environment Management, which focuses on ensuring consistent runtimes within and between deployment environments (dev, test, prod, etc).
- Typically, this takes the form of virtual environment managers like RVM (Ruby Version Manager), Chruby, and rbenv.
Additionally, there are a number of alternative package managers available from other ecosystems, such as apt and yum for Linux distributions. You can use Linux package management tools to manage gems and environments, and even resolve dependencies. But when it comes to managing virtual environments, you’re better off choosing a Ruby-native solution.
With such a diverse selection of package managers, Ruby developers have a number of options that can help them with their environment and dependency management tasks. However, when it comes to issues like dependency conflicts or troubleshooting “works on my machine” issues, today’s package managers leave developers to manually implement their own workarounds.
ActiveState for Ruby Package Management
ActiveState provides a universal package management solution for Windows, Linux and MacOS, including the ability to build and manage gems, dependencies and environments in a standard, reproducible way. The ActiveState Platform provides a web-based GUI to accomplish these tasks, while the accompanying State Tool provides developers with similar capabilities from the command line.
Ruby Gem Building
It should come as no surprise that most Ruby developers prefer to install prebuilt gems rather than build them from source code. Unfortunately, this practice can expose your organization to supply chain security threats like:
- Dependency confusion
- Open source code that contains malware, spyware, trojans, etc
The only way to mitigate these threats is to build all gems from source code. While pure Ruby gems are trivially easy to build from source, building and updating gems that feature linked C libraries are much more of a pain, and can end up being a huge time sink over the life of a project.
The ActiveState Platform provides a cloud-based build farm that will automatically build Ruby gems (as well as their dependencies) from source code, including any linked C libraries, and then package them for Windows and Linux. As a result, there’s no need to maintain a local build environment, or even a need for language or operating system expertise.
Ruby Dependency Resolution
Package managers will commonly resolve dependencies, and hopefully flag any conflicts, ensuring you don’t end up installing non-compatible dependencies. Unfortunately, when conflicts are found, most dependency managers can only point them out, rather than point to a solution or workaround. This leaves developers manually testing various gem versions, which can lead directly to dependency hell.
The ActiveState Platform’s dependency solver not only resolves dependencies, but also flags conflicts at multiple levels, including:
- Top level gem dependencies
- Linked C library dependencies
- Operating System (OS)-level dependencies
- This is key to avoiding errors when your project is deployed to multiple platforms.
- Shared libraries across multiple languages (ie., openSSL)
The ActiveState Platform is also unique in suggesting ways to solve a dependency conflict if it is unable to resolve the issue automatically. For example:
While the simplest solution is to ensure none of your gems are pinned to a specific version (thus the message “Set all versions to Auto”), you can also follow the reasoning provided by ActiveState’s solver, which recommends updating the railties gem to version 6.0.5 in order to resolve the conflict.
Ruby Environment Management
Ruby’s gemfile.lock files help ensure projects can be deployed in a consistent, reproducible manner. Of course, you still need to remember to update your gemfile.lock before deploying, but there are other issues, as well:
- The gemfile.lock configuration can get out of sync as team members update their local environment for their own purposes.
- Even when all team members are using identical Docker images or Virtual Machines (VMs), you still need to ensure that they have been built with the latest configuration.
- When developing on one OS but deploying on a different OS, you may be missing OS-level dependencies.
- DevOps is often left to resolve multiple conflicting code check-ins, leading to CI/CD environments that differ from development environments.
All of these issues lead to inconsistencies between environments, which results in developers wasting time trying to reproduce nonexistent code bugs.
In contrast, the ActiveState Platform takes a “shareable environment” approach to ensuring consistency and reproducibility by:
- Providing a central “source of truth” for the Ruby environment that all users/systems can pull to build their local environments, ensuring everyone is using a consistent configuration, no matter the OS or deployment system.
- Updates to the environment can be made centrally, and then updated locally with a single command.
Centrally managing and deploying your Ruby environments means that all teams remain in sync, eliminating “works on my machine” issues.
Conclusions – Build and Share Ruby Environments Securely
Most enterprise developers manage and maintain multiple package managers, build tools, environment management utilities, and other solutions in order to address the issues that a single tool – the ActiveState Platform –- can solve today.
By adopting the ActiveState Platform, developers can:
- Ensure the security of Ruby gems
- Secure your Ruby supply chain
- Eliminate dependency hell
- Reduce “works on my machine” issues
Ultimately, developers that are willing to adopt the ActiveState Platform will spend less time wrestling with tooling and more time focused on doing what they do best: coding.
Get better Ruby package management by creating a free ActiveState Platform, using your gemfile.lock to configure your environment and automatically build it from source code, and then invite all your colleagues to collaborate on it.
Read Similar Stories
Configure and automatically build a secure Rails environment from source code for Windows and Linux in a matter of minutes.