Hello all: I'm trying something new that might do my career some favours and writing a book! It's primarily aimed at R users who want to improve their software engineering skills, whether that's to help them into an industry career, improve the quality of their research skills or just for the fun of it. I'll be posting up chapters on my blog as I write them, and when I think the book is mostly done, I'll pull them all together into an e-book and maybe even set up a distinct website for it. In the interim, I would love feedback on anything I've written here.
Introduction
R is a statistical programming language developed at the University of Auckland by Robert Gentleman and Ross Ihaka, with the initial version being published in 1993. It has since become a very popular tool for statistical analysis across a wide swathe of industry and academia. An awful lot of R code has been written since that year, and it has made massive contributions to research in quantitative fields the world over and has generally had significant, positive impacts on the way the world works. The quality of the code, however, often leaves something to be desired.
The reason is obvious: the code is written by statisticians. It's almost always extremely capable from a statistical standpoint: the ecosystem, after all, contains a lot of deeply useful tools. A statistician, however, is not a software engineer. Those of us in the field of software engineering have significant experience in writing maintainable code that behaves in reproducible ways that your average person using R for stats simply doesn't have available to them. The statisticians, by contrast, know how to do stats in ways that put your average software engineer to shame.
Neither side, on the whole, seems willing to speak the others' language, much less help the other develop the skills that they have. This seems to me like a bit of a loss, and so I've chosen to write this damned thing: a guide for R users who wish to develop the skills to write R code in the same way that a software engineer would.
This book aims to take an R user who may or may not know how to program and help them develop the skills that they need to program in R (and maybe even other languages) with confidence. This includes learning the tools and supporting skills needed to write code like a software engineer would, learning how to use R to write sophisticated programs that are more complex than your usual script and above all learning how to use R to solve problems beyond those that are purely statistical in nature.
Whom this book is for
Writing a book about doing software engineering for experienced R users might be considered to be an odd choice. After all, R is a language for statisticians, and even computational statisticians tend to do things day-to-day that are quite different from what software engineers tend to do. However, it is still software, and it still brings with it software problems: dependency management, environment management, performance, hosting and all of those things. If you're a person who uses R primarily as a statistician you'll probably have tripped over these problems occasionally (and most likely caused them for other people): code doesn't work on other people's systems, packages overwrite each other, you don't really track versions and all in all it becomes really easy for an R project to turn into a complete, irretrievable rat's nest of defects and error messages.
Some of this, to be fair, is a question of design decisions being made that I don't think we'd make in a modern language. R is pretty old, after all (older than I am), and S, which it's modelled on, is even older. The expectation that a lot of system and project management tasks are done from within an interactive R session rather than the command line, for example, is definitely a choice. That being said, the fact that most R code is written by statisticians isn't great either. To be clear, this isn't a slight at statisticians, but the fact remains that most statisticians have not had a great deal of software engineering training. Unfortunately, software engineers do not generally tend to make for good statisticians, and the thought then becomes that if we teach statisticians how to write code good, this would probably be a good way to improve the overall quality of R code out there.
In this year of our lord 2025, transferable skills are also important. Writing and working with R as a statistician fits you for a decent variety of work: writing and working with R as a software engineer, with all of the supporting skills that entails will fit you for a much wider range of work, some of it quite a bit more lucrative than simply doing stats. And that's all without even learning another programming language. Learning R as a programming language, doing programming-type things in it and using it as a springboard to learn other languages (HTML/CSS, JavaScript and Python are probably the obvious options here) expands your options even further.
If any of the following points relate to you, then this might be the book for you:
- You're a researcher that cares about reproducibility. The fact of the matter is that most research code really struggles to be reproduced, even in 2025. Most journals still don't require that you publish your code at all, and even if they do, standards around version control and suchlike are often pretty terrible. Shifting this is going to take quite a bit of time, but one thing that individuals can do is set a good example. If you work through this book, you'll be able to write reproducible, version-controlled, tested code that anyone can run in exactly the same conditions that you ran it in, which I think would be very good for the scientific process.
- You're a postgrad or postdoc working with R who's looking at an industry career. Academia is, let's face it, kinda fucked. There's limited funding, there are few tenure-track positions, the pay is awful and the working conditions are often downright abusive. While at the time of writing the outlook for industry is also kinda bleak, it's probably still better than the outlook in academia. If you want to compete effectively for industry jobs then, it really is incumbent upon you that you be able to write code like an engineer, which is what this text aims to teach.
- You're an academic who wants your students to do well. Your job as a teacher is to prepare all of your students to excel wherever they end up, be that academia or industry. In either case, your students writing good software is an important part of this, and a good way to teach your students to do this is, unsurprisingly, to set a good example, and do it yourself.
- You work with R in industry and want an easier time dealing with the language. As much as R is a brilliant statistical tool, it's also consistently a source of some real technical headaches. Learning how to handle R in a way that at least brings it in line with most software tools, then, is probably a good idea.
This book's educational philosophy
Many teaching documents take a pattern of going in-depth on one particular field, then going in-depth on a second once the first field's been mastered and so on and so forth. In a lot of fields, this works pretty well: unfortunately, in my experience, it's not the best for teaching software engineering. When writing a text primarily aimed at cross-training people who are already skilled in a field, it's doubly ineffective.
To use an analogy from physical craft, what we're teaching here is primarily the use of tools to make useful things. In such a situation, the issue with the "go deep on one thing" pattern is obvious: while there's quite a lot that you can do when you have basic knowledge of how to use a few tools, deep specialist knowledge of only one tool is quite a lot more limited in what it can do. A carpenter who specialised solely in the use of the plane at the expense of every other tool would be a pretty bad carpenter, after all.
I have rather elected to write this text in accordance with Leonard Susskind's philosophy for teaching maths and physics in The Theoretical Minimum: I give the minimum amount of knowledge that you need to move onto the next thing. The idea is that we can show you the minimum level of knowledge that you need to do something useful with a specific tool, and give you that minimal knowledge for a number of tools that, taken together, will let you build a strong understanding of these basic skills. With repetition and practice, the skills will hopefully take, and then we can build on that foundation to add a little more to each skill each time. This takes, I suppose, some level of trust on the part of a reader: trust that I'm not leading you up a garden path, trust that some things that are obscure now will make sense later. I hope, as always, that the reader is willing to give me this trust.
How to learn effectively
While, as with anything that you learn, there is some information to commit to memory in this book, the bulk of what this book aims to teach is fluency with tools. To develop fluency with tools, repeated practice is essential, and there really is no avoiding the fact that to get properly good at most of the things in this book, you're going to have to use the tools quite a lot. I've written exercises that help with getting this practice, but it's probably not going to be enough to just work through them (though you definitely should). You're going to need extra practice.
The best way to get this extra practice is to find ways to integrate the new tools and their use into the work that you do day-to-day. The command line, for example, can be good for running updates, navigating through your system and installing software even when you aren't writing code. The next time you need some software then, why not try installing it through the command line rather than trying to find a download on the internet or using the app store (the side benefit of this is, of course, that cli package installs are usually a bit more secure than random internet downloads). If you're writing a document, why not version control it? If you're writing some software for your work, you should definitely make sure to set up basic version control and a development container image, and if you wanted to stretch yourself even further, you could even write your code in a command line editor. It might be a bit more difficult than doing it the way you're used to at first, but it will quickly become second nature, which is what we want.
In any case, I've written enough faintly tedious introductory stuff for now. On to the first chapter!
Chapter 0: setting up a software development environment
It is worth noting from the very beginning that a software engineer's work doesn't start with writing code, but with setting up the development environment and the tools that they need to write code effectively. Good tooling can make the difference between you writing clean, tight, maintainable code on the one hand and creating an unmaintainable abomination on the other. This entire first chapter, then, is dedicated to setting up a development environment that lets you build things in R in a consistent, reproducible and easy to fix or revert way. We'll start with basic command line skills, move on to version control and then finally discuss containerisation and the setting up of a development container for your project.
While you work through the chapters of this book, you will be building a basic R project that you could use as a portfolio piece or similar. I'll be maintaining my own version of this project as I write, so that you can compare what you have to what I've written. Example code for this chapter can be found at https://gitlab.com/irishenceaway/r.the.software.way. The commit for this chapter is tagged as chapter0: to get a local copy of the example code, you can run
git clone https://gitlab.com/irishenceaway/r.the.software.way
followed by
git checkout -b <branch-name> chapter0.
Using the command line
While R is a programming language, it's often something that we interact with primarily through tools like RStudio and other graphical interfaces. This is probably fine for research, and so forth (though I still believe that it's less than ideal), and it has the significant advantage of presenting less-technical users with a familiar interface.
To be an effective software engineer, however, mastery of the command line is essential. A lot of tasks that are a real pain to do via the GUI (say, copying all files matching a certain naming convention from one directory to another) are much easier to do via the command line than through a graphical interface, and once you've gotten used to it, it gives you a much more fluid, efficient way of communicating with the machine. The first thing you'll want to learn in your software engineering journey, then, is some basic command line skills.
This guide is written for Linux environments, with bash or a similar POSIX-compliant shell. R really does work best in Linux environments and a lot of packages will either refuse to work or behave strangely in Windows environments. I'd strongly suggest that you work on a Linux system if at all possible (Mint and Ubuntu are held to be good beginner distros, and given that you're working with R, Fedora might also be an option to consider). If you're stuck on Windows, you might consider using the Windows Subsystem for Linux instead, which lets you access a Windows development environment on a Linux machine. Of course, we will be setting things up in such a way that your R code will be running inside a Linux container anyway, but even so, this is very much worth doing: Linux usage and systems administration are useful skills to have in most technical jobs.
Having gained access, one way or another, to a Linux command line, you'll probably want to do something with it. There are many very sophisticated things you can do with the command line, but, as with everything, we need to start with the basic building blocks.
Basic commands
These are basic commands that are useful for navigating your system through the command line and performing some basic tasks. Having these committed to memory and knowing how they work will carry you an awfully long way.
ls: lists all files and directories in the current directory. ls -a will show hidden directories as well.
cd: changes the directory you're in to the directory specified by the path you pass to the command. cd .. will change the directory to the parent directory of your current location ( .. in general refers to the directory above your current one, while . refers to your current directory), and cd ~ will change your directory to your home directory.
mkdir: creates a new directory at your current location.
rmdir: removes a directory.
touch: creates a new file with a given name at your current location.
rm: deletes a file (be very careful with this: you can do some pretty weird things to your system in the process. In particular, running rm -rf * in your root directory will nuke your Linux install).
mv: moves a file or directory from one location to another.
cp: copies a file or directory from one location to another.
cat: outputs the contents of a file to the command line. This command can also be used to concatenate multiple files.
less: less allows you to read the contents of a file or buffer with a simple scrolling interface. This is primarily useful when you wish to read a large file or the output of a command without accidentally editing or otherwise damaging it. Quit out from less by pressing q.
echo: prints the input of the command to the command line. This is primarily useful when writing shell scripts or when you want to pass stuff to a command using a pipe (see below for more on pipes)
locate: locate allows you to find the location of files and directories on your system.
apt, dnf, pacman, brew...: the system you'll be working with likely has a package manager installed that you can use to install software via the command line. The exact command will depend on the system that you have installed, but in general, command-line package installs will save you a lot of headaches.
Tips and tricks
These are a few tips and tricks that can make your life a bit easier when working with the command line.
Nano
Nano is a basic text editor that allows you to create and edit files directly from the command line. nano file-name will open an existing file in nano, while nano with no arguments will open a new file buffer. Important commands are listed at the bottom left of the terminal, but the most important one of the bunch is Ctrl + x, which exits the editor. If you've edited the file, you'll be asked whether you want to save your changes first.
Man pages
If you're unfamiliar with a command or a utility, rather than leaving the terminal to look it up online, you can use the man command to display the system manual for a given command.
Pipes and redirects
Pipes are a very powerful feature of bash that allows you to redirect command output to a file or another command. To redirect command output to another command, use |. For example, to read the git documentation in the terminal in a way that's a bit more tolerable than scrolling through the terminal normally, you might execute man git | less, which will let you read the git manual page in less.
To redirect to a file, use >. For example, if you wished to write the contents of the git manual to a text file for whatever reason, you could execute man git > git.txt, which would create a file in your active directory called git.txt and write the manual page to it.
Pipes and redirects can be extremely useful for creating some quite complex and powerful tools, and understanding when and how to use them is really important for getting the most out of bash.
The best way to get good at using the command line is to use it at every possible opportunity, especially for systems management tasks that you'd usually do via the GUI. If there's something that you don't know how to do, do some research and figure it out. Given time and repeated effort, you will build fluidity.
Exercise: Set up a project directory
These tasks should all be doable with the basic commands I've discussed above, plus Nano.
Using your command line:
- Locate a directory where you want your R projects to live.
- Create a subdirectory in that directory called
R.software.way.projector something similar, and change your active directory to that directory. Make sure to follow the CRAN package name requirements, as this will be important later. - Create an empty file called
README.md - Open
README.mdusing Nano and add some notes about the project to it. You'll note that I've created it as a Markdown file: Markdown is a simple, pretty basic Markup language that lets you write documents with basic hierarchical structure and formatting. Learning a bit of basic Markdown isn't a terrible idea. - Start an interactive R session in your project directory: while we will for the most part be using a development container for working with R, there are a bunch of utilities we'll want to be able to run locally. If you don't have R installed, you'll want to install that first.
- Install the
devtoolsR package locally: this can sometimes be a bit tricky for two reasons. Firstly, dependency resolution for the defaultinstall.packagestool can be a bit tricky. I'd thus suggest usingpakfor installing packages on your system, which you can install withinstall.packages('pak'). You can then install devtools withpak::pkg_install("devtools"). The second potential hiccup here is that bothpakanddevtoolshave the development version of libcurl as a dependency, and you'll have to install this using your OS package manager rather than . Finding the right version can be a little tricky, butapt-get install -y libcurl4-openssl-devseems to get the correct version for Debian-based systems. - Finally, attach
devtoolsto your current session and runusethis::create_package(".")in your project directory. This scaffolds a basic package structure for your R code, and as we'll discuss further in the next chapter, you should write almost all of your code as packages. You'll usually use a slightly different workflow for this, but right now, we're practising using the command line, so doing the whole thing from within R would defeat the purpose a bit.
A better IDE than RStudio
RStudio is a decent IDE, I suppose. It does the job well enough, it's tailored to R in some helpful ways and it provides a consistent project structure that benefits people using R for mostly statistical purposes. You will, however, probably find it somewhat frustrating to work with when doing work that's more like software engineering than statistics. For a start, most projects these days use multiple languages, some of which RStudio won't support. RStudio also isn't very extensible: while there is some functionality for add-ins and suchlike, RStudio is fundamentally the thing that it is. While you probably could become a very effective software engineer working exclusively in RStudio, then, it will be frustrating and choosing a more flexible, extensible code editor that can handle multiple different languages and workflows would be a good idea.
There are a whole lot of general-purpose IDEs out there, both terminal-based and GUI-based: however, I tend to keep defaulting to VSCodium, which is an Open Source and Free version of VS Code that rips out a bunch of Microsoft's telemetry and the default inclusion of Copilot (I should mention here that if you actually want to learn anything, you will wish to avoid LLMs like the plague throughout this book).
Exercise: Install and familiarise yourself with VSCodium
To install new software via the command line, you'll wish to use your system's package manager. This tends to be apt for Debian-based systems such as Ubuntu or Mint and dnf for Red Hat based systems such as Fedora. For Windows, you might have to install the package manager first.
The command to install VSCodium then tends to look something like sudo apt-get install codium: you can find detailed instructions here.
Thus, using your command line:
- Install VSCodium
- Open the directory you created earlier in VSCodium
- Familiarise yourself with the general layout of the IDE and where you can find the things you rely on
- Find out how to open the integrated terminal in VSCodium
- In the extensions tab in VSCodium, find and install the R language extension
Version control
Alright, so we have a project and a way to edit it that isn't entirely terminal-based (many very strong engineers work entirely in the terminal: I'm not personally sold on this, as we have at least some evidence to suggest that GUI code editors really do increase efficiency, but it is very much possible). The next step is to version control our code, which we'll be doing with git.
I'm sure you've all been somewhat familiar with the unpleasant experience of editing or losing a draft or accidentally deleting a code file and being unable to retrieve it and having to reconstruct it from first principles, which may or may not work. In software engineering, we use version control tools to prevent this from happening, the most popular of which is git. Git was developed by Linus Torvalds to version control the Linux source code, and it's a very capable piece of software. There's a lot to learn about it, and if you want to do so you can read the book Pro Git, which would be an excellent use of your time. For now, however, you only need to know a very few commands
It's likely that git will already be installed on your system: if it isn't, you might have to figure out how to install it. Before you begin using git, you'll need to set up your user details using the following:
1
git config --global user.name "Die Hardman"
git config --global user.email [email protected]
In any case, with git installed on your system, you can begin using git by running, in a terminal in your project directory, the command git init. This creates a .git subdirectory which contains your repository skeleton. You are currently not tracking any files: to add a file so that modifications are tracked by git, you'll need to run the command git add, followed by the name or names of the files you wish to track. For example, git add * will tell git to track all files in the directory, while git add README.md will only add the README.md file that you created earlier. You can then run git commit -m "Initial commit" to commit your changes. What this means is that git has taken a snapshot of your directory in its current state and created a pointer to it. You can then, at any point in the future, roll back changes that you've made to your codebase but haven't committed and restore your project to the snapshotted state. You can then do some more work on your project, and once you're happy with the progress you've made, you can run git add and then git commit -m <commit-message> to commit your new changes and update the snapshot. It's worth noting that writing good, informative commit messages is an art in itself: you'll pick up how to write good ones in time, but for now it's worth noting that writing messages that are just "fixed bugs" or similar isn't a good idea.
As an aside, the default branch created after running git init is called "master". We tend to no longer call default branches that unless we wish to be performatively racist or otherwise a bit awful, so to change the name of the default branch to something nicer, you can run git branch -m "main" immediately after initiating to rename your initial branch to "main".
Local version control already helps you avoid a lot of pain if you do it consistently. However, it's also, in general, worth setting up a remote repository somewhere, so that if you lose your computer's storage to a drive failure, you still have your code somewhere else. This is also, by-the-by, good for collaboration and sharing your code, which I really wish researchers would do more of, so this isn't just a "do this for your own sake thing", it's a "please do this for my sanity" thing.
The most famous remote repository is Github, but for a variety of reasons, I wouldn't recommend using it. Gitlab and Codeberg are good alternatives for hosting a remote version of your repository, and I use both of them for various things. To set up a remote repository, you'll have to sign up with the service of your choice and then create a blank project with the same name as your local repository. It's important to make sure you create a completely blank project: many providers will create a README file in the repository by default, but as you intend to push a local repository that already has files in it to the remote, creating a README in the remote repository will make the remote throw an error when you try and push it.
You'll also need to authenticate to the remote locally in order to push to the repository. You can do this with either ssh or with some flavour of https authentication: to set up ssh, you'll simply need to copy over your ssh public key to the remote repository, which the provider will give you instructions for. https authentication is probably best handled by the Gitlab or Codeberg extension for VSCodium, which will likewise step you through the steps you need to do to make this work.
Having authenticated, you'll then push your local code to the remote by running git remote add origin [email protected]:irishenceaway/ \ <project-name>.git (project-name will be replaced by your project name), then running git push origin main to push the local repository's main branch to your remote repository. You now have a version of your project stored remotely in case you lose it locally, and that you can share with fellow researchers, reviewers, people reading your papers and anyone else who might be interested.
Basic commands
git init: This command initialises the current directory as a git repository
git clone: This command clones a remote repository and creates a copy of it on your system
git add: This command tells git to start tracking a new file or add changes from a file to staging
git commit: This command commits all of your staged changes and creates a snapshot of the current repository state
git push: This command pushes all locally committed changes to your remote repository
git restore: This command discards all staged and otherwise untracked changes and restores the state of your local repository to the state it was in at the time of your last commit
git status: Finally, this command prints a certain level of useful information about the current state of your repository
Exercise: set up a remote repository
In your project directory:
- Initialise the directory as a git repository
- Make your first commit
- Set up a remote repository on your choice of service and push your changes to it via command line
- Make some changes to your
README.mdfile - Make another commit. Write a descriptive message
- Push your changes to the remote repository again
In a different directory:
- Clone the version of the repository that I've listed at the top of this chapter, have a look through it, and compare it to the work you've done so far
Package management and containerisation
Alright, we're almost there: there's only one more thing you really need to know in order to start writing R in the way that a software engineer (or well, a good one anyway) would.
I'd normally wait quite a bit longer to introduce containerisation as a concept, if I'm to be honest: it's not exactly the kind of thing you see in Intro to Software courses. Unfortunately, we're working with R, and for the many merits of the language, it is not very portable. Scripts and packages that run on one version or operating system will often just not run on another, versioning is a real headache and in general trying to get one person's code to run on another person's system is a real pain. For researchers, that's a real problem: if other researchers can't easily run your code, they can't very well participate effectively in the research process.
Containerisation neatly sidesteps this issue. A container image is a representation of a complete userspace (so lighter than a full virtual machine, as it doesn't attempt to virtualise hardware), with whatever operating system you want, set versions of all your packages and everything just as you want it. If you then publish that image on a container registry, anyone, on any operating system, who has a container engine installed can pull that image, start up a container using it and run your scripts with exactly the same versions, environment and everything that you were using when you published it. It will consistently work, no matter what.
Even locally, working in a container as opposed to your machine has its advantages. As I'm sure you're familiar with, R installs libraries and packages globally: any scripts and projects you write, by default, use the same version of the library installed on your system. While you can get package reproducibility with renv, we've already tripped over a couple of situations where R packages depend on packages installed via the operating system that aren't R packages at all, and then you're shit out of luck. renv also doesn't track the actual R version being used at all, which can be a real problem given how many breaking changes R tends to ship.
renvis a very useful tool, especially if you don't want to go to all the trouble of setting up a development container, and you can quite easily use it alongside a development image: I'll demonstrate a pattern for doing so down the line (once I've settled on what the best pattern for this is). For now I've elected simply to usepakto install packages globally in the development image, but learning how to handlerenvwould be very much worth your while if you have a spare moment and want something to do.
While there are a whole lot of different containerisation systems on the market, Docker remains the one that everyone knows. For our purposes, then, we'll just use Docker and cover the bare minimum of containerisation that you need to create a properly isolated, reproducible environment for all your R projects.
To create a containerised environment, then, the first thing you'll need to do is install Docker. This is, unfortunately, a slightly involved process, but there are some decent instructions for doing this that you can find here. I would generally advise against trying to install Docker Desktop: in my experience it's always been a bit more trouble than it's worth, but there may be reasons for doing it that I can't judge.
In any case, having installed Docker, you'll now want to build a custom image to do your work in. We do this by using a Dockerfile: a simple one for our purposes might look like this:
1
FROM rocker/r-ver:4.5.2 as base
WORKDIR /r-software-engineering
COPY "packages.R" "packages.R"
RUN apt-get update
RUN apt-get install -y libcurl4-openssl-dev
RUN R -e "install.packages('pak')"
RUN R -e "library('pak')"
RUN R -e "source('packages.R')"
We start by specifying which container image we want to base our image on: in this case we're deriving our image from the official R base image, which is the simplest approach. If you want to specify a certain version of R to use with your project, you can specify that as your image; the Rocker Project maintains versioned R base images for precisely that purpose.
We then create a working directory in the image: this is strictly speaking optional as you can basically do everything you want in the container root, but it's good practice to create a project directory. That being done, we copy a file called "packages.R" in your project directory over to the image. "packages.R" is simply an R file containing a list of all the packages that you wish to install in your image. A simple version of it might look like this:
1
pak::pkg_install("devtools")
In this example, we're installing dplyr and ggplot2, which are two fairly commonly used R packages. As for why we use this pattern rather than the usual way we install packages, toolchains in the general software world usually have you install packages in the OS cli rather than in an interactive console, and the tool you use will usually create a lockfile to store information about what packages you've installed and what the version number for those packages is. R, however, insists that you install in an interactive console, and unless you deliberately make it happen, you won't get a lockfile. Having a separate file with all your package installs brings R's behaviour a little closer to what a software engineer would work with.
We then install the development version of libcurl in the image: a number of the tools we're using rely on libcurl as a dependency, so we'll need it in our image. Note that we do this with the package manager for the (ubuntu-based) image here rather than using R tools.
Having done this, we then install and attach the package manager pak. We do this because you'll almost certainly have experienced significant issues with dependency resolution when using the standard install.packages tool: pak has, in my personal opinion, the most effective way of resolving and installing the dependencies that a given package has and it's given me far less trouble than the other tools I've tried.
Finally, we install the packages we want by sourcing the packages.R script. With this Dockerfile in place, we can run the command
sudo docker build -t <image-name> .
To build our custom image. It's important to specify an image name as otherwise the image will only be available via its UUID, and while this works, it's also a pain in the behind and requires you to know more about Docker than you probably want to at the moment. In any case, if you then run the command
sudo docker run --rm -ti <image-name>
you should, if all went well, find yourself in an interactive R session with exactly the version of R that you want and all of the packages that you want, in whatever version, available to you.
There's a rather pleasant fringe benefit of doing everything this way. R packages, as I'm sure you're familiar, take quite some time to download and install: you need to find a working repository, and everything is just generally inefficient. When you build an image, though, you only have to do all of the installation once per build. Spinning up an image can then be done in milliseconds.
And with that, you have the basics of setting up a reproducible development environment for R. This currently probably feels like you've done a lot of work for not much purpose, and that's probably fair at the moment. However, once you've done this for two or three projects, it'll begin to feel much more natural, and you'll begin to understand why all this is worth the effort.
In the next chapter, we'll look at actually writing some R code (and we mean code, not just using functions.) We'll cover loops, conditionals, custom functions and basic unit testing, and in the process we'll learn a few more handy things about git, the command line and container technology.
Basic commands
docker images: This command lists all the images that you have available on your local system
docker rmi: This command removes an image with a specified name from your local system
docker image prune: This command removes all unused images from your local system (this can be quite useful, as too many container images will eventually take up quite a bit of disk space)
docker build -t <image-name> .: This command builds a docker image from a Dockerfile in your active directory
docker pull: This command pulls a container image from a remote repository.
docker run: This command runs a container from an image that exists locally. If the image doesn't exist locally, docker will attempt to pull it from a repository first.
docker ps: This command lists containers that are currently running on your system
docker start/stop: These commands start or stop an existing container
docker rm: This command removes a stopped container on your system
docker exec -it <container_name> sh: This command opens a command shell inside a running container: you'll note that the image you'll set up in the next section drops you into an interactive R session by default. While that's usually what you want, sometimes you might actually want to dig around inside your container, and being able to open a proper command shell is very useful in this case.
Exercise
Working with your project directory:
- Install docker engine on your system
- Write a basic Dockerfile for your development environment using the template I've given as a base
- Build and run a development container from your Dockerfile
- Confirm that the environment you've made available conforms to the specification that you've given

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.