Setting up igraph for success in the next decade
One year ago, a small group of us at cynkra submitted a project proposal to the R Consortium’s ISC, which got approved. We are very grateful for this support. In this post we shall explain what the motivation for our project was, what we accomplished… and what we hope to work on next!
Why did igraph need some dedicated maintenance?
The first version of the igraph R package was published on CRAN in 2006. Since then, the igraph C library that forms the core of the R package, and the R package itself, have been further developed and widely used. Over the years, the R package has also accrued a bit of documentation debt and technical debt, that we wanted to tackle to set up igraph for success in the next decade. Both aspects had the potential to simplify further updates of the package.
Adopting the lifecycle system
To provide a more consistent interface, part of igraph functions or arguments are slowly but consistently being deprecated. Some of them used to be deprecated using custom solutions or base R deprecations. In contrast, now all deprecations happen through the lifecycle package. On manual pages, deprecation badges indicate the maintenance status of functions or arguments.
library("igraph")
#>
#> Attaching package: 'igraph'
#> The following objects are masked from 'package:stats':
#>
#> decompose, spectrum
#> The following object is masked from 'package:base':
#>
#> union
<- sample_gnp(10, 0.5)
g graph.density(g)
#> Warning: `graph.density()` was deprecated in igraph 2.0.0.
#> ℹ Please use `edge_density()` instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
#> [1] 0.5111111
Having everything in the “lifecycle system” now means the interface and documentation is consistent for users, and also that we can more easily increase deprecation levels over time by searching for lifecycle calls. Last, but not least, all deprecations are listed in a vignette.
Documentation improvements
Besides the documentation of lifecycle, we created and used a custom roxygen2 tags to link to the C docs from manual pages. Example.
Fewer errors, better errors
We have made a conscious effort to port errors from base R to cli, at the same time improving phrasing of errors. For instance,
stop("invalid value supplied for `weighted' argument, please see docs.")
became
::cli_abort(c(
cli"{.arg weighted} can't be {.obj_type_friendly {weighted}}.",
i = "See {.help graph_from_biadjacency_matrix}'s manual page."
))
which is more informative about the invalid value supplied, and which directly links to the manual page.
We have also fixed some bugs ( example).
Work on the internals
We did a lot of refactoring! Most of it was focussed on tests, as previously explained on this blog: merging some test files to ensure alignment between R scripts and test files, refactoring test files for better readability and future debugging, updating the testthat usage by removing old expectations. We also worked in the R/
folder, for instance we replaced the usage of an embedded version of lazyeval with rlang calls. ( PR 1, PR 2)
Conclusion
We are proud of the progress made in the igraph codebase but we don’t want to stop here! In particular, we’d really like to do more work on open issues to improve the state of the issue tracker and to ensure easier future triage ; to better describe and execute the scope differences between the C and R libraries ; and to make the documentation more complete and clearer.