At Singlebrook, we use tools to expedite the creation of maintainable software. Maintainable software has the following primary characteristics:
- Developers new to the project can start working quickly.
- Features can be added and changed with a commensurate level of effort/cost.
- Security patches can be applied quickly and easily.
The following tools help to automate some aspects of maintenance by providing metrics for baseline levels of software quality. When our software falls below these metrics, we can quickly address maintenance needs, without impeding the development of the project.
libyear is a tool created by Singlebrook’s own Jared Beck to derive a simple metric for “dependency freshness”; that is, the extent to which an app’s dependencies are up-to-date. It is a simple measure of the time between the release date of the installed dependency and the release date of the newest version of the dependency. For example, a Rails 5.0.0 dependency (released June 30, 2016) is 1 libyear behind the 5.1.2 version (released June 26, 2017).
Applied to a whole Gemfile, libyear provides a single number for determining the maintenance burden of an app’s dependencies. For a baseline, we at Singlebrook endeavor to keep each of our client’s apps below 10 libyears. Though initially an arbitrary standard, it has been an ambitious goal while taking practical considerations such as aging vendored dependencies into account.
The inspiration for libyear comes from the technical report “Measuring Dependency Freshness in Software Systems” 1. Other metrics for determining dependency freshness outlined in the paper are available in libyear-bundler. The
--versions flag provides a metric for an installed dependency’s freshness relative to the newest release’s major, minor, and patch versions. Of course, this is most useful for dependencies that follow a consistent versioning scheme such as semver. The
--releases flag provides a metric for the number of releases between an installed version of dependency and the newest released version of the dependency.
Each metric has it’s own advantages and disadvantages, but each metric provides a concrete sense of the maintenance burden for an app. Taken together, they can help prioritize maintenance for an inherited app, or help maintain a baseline level of dependency freshness for an ongoing project.
rubocop is the first development dependency I install for any project, inherited or greenfield. As much as a well-defined database schema provides a foundation for an app’s informational structure, so a well-currated
robocop.yml provides a foundation for maintaining a codebase’s readability. These foundations are necessary for an app’s long-term health and maintainability by making it easier to onboard new developers, to add to and reorganize code, and to more readily spot insecure or otherwise frail feature implementations.
Tweaking rubocop’s configuration is akin to defining a style guide for a publication. The intention is to facilitate readability and comprehension, but also has the effect of giving a ‘voice’ to the codebase. The rubocop configuration is organized by ‘department’, which includes Style, Layout, Metrics, Performance, and more. Singlebook endeavors to adhere to rubocop’s default configuration, which represents a consensus of sorts amongst the Ruby community, but we also have our own conventions. Whatever the configuration setup, each commit to master is expected to have zero rubocop offenses. Inconsistency in the codebase can increase cognitive load, making software harder to maintain.
Code Climate is a third-party service we utilize to provide a GPA for our client’s projects. It has many engines to derive metrics for assessing the code quality of a codebase. We review Code Climate’s recommendations to help prioritize maintenance. Singlebrook endeavors to maintain a GPA of at least 3.5.
1: J. Cox, E. Bouwers, M. van Eekelen and J. Visser, Measuring Dependency Freshness in Software Systems. In Proceedings of the 37th International Conference on Software Engineering (ICSE 2015), May 2015 https://ericbouwers.github.io/papers/icse15.pdf