June 29, 2020
Establishing a Good, Portable Development Environment
As programmers, we all have a desire to be lazy. After all, that is why we write programs in the first place: to get our computers to work for us. Therefore, it is only natural that we should also be setting up our computers to help us with the more mundane parts of coding. This is where a development environment comes in.
One choice that beginner programmers often gravitate toward is the Integrated Development Environment (IDE), where one writes, builds, tests, debugs, commits, deploys code all in a single piece of software. Examples of this include IntelliJ and Eclipse for Java, PyCharm for Python, and Visual Studio for C and C++. While these tools are certainly powerful and useful, especially for developing applications that are tailored to specific platforms (development of Android applications would be greatly hindered if one were not to use Android Studio, a spin-off of IntelliJ specifically designed for Android development), they are also somewhat problematic in that they force you into using their predefined workflow. Often, this makes the coding environment highly non-portable; if you create a project in one IDE, you, as well as anyone you are working with and anyone who will have to work on this at a later date, might find it increasingly more difficult to move off of that IDE as the project grows. This is, of course, more than a little annoying.
Below, I will share with you a few methods that I use in establishing my development environments using mostly portable and preexisting tools.
Using Command-line Package Managers
npm, but most package managers for modern langauges should behave similarly.
For developers working in Python, the
pip tool is the main method for acquiring dependencies. To install a new package, one would simply type
pip install <package-name>, and
pip will install the package into your local python environment (which is hopefully a virtual environment that you have previously set up!). However,
pip also has an additional feature that allows one to specify a file (typically called
requirements.txt) which lists out package names one per line, and
pip will install all of the enumerated packages. This feature can be invoked using the
-r flag, as in
pip install -r requirements.txt. Therefore, what one could do is simply maintain a list of all of the dependencies of the project in this file and commit it to the code repository so that anyone else who would pick up this project in the future can get their own Python environments up to speed by simply running
pip install -r requirements.txt. I highly encourage anyone who is developing in Python to include such a requirements file.
npm is vastly more powerful than
npm, one can first create a local environment using
npm init, which creates a
package.json file in the local directory. Any subsequent installations done via
npm will be kept track of in the
package.json file automatically. To replicate a development environment, simply run
npm install in the same directory as the
The main difference between package managers like
npm and IDEs is that these package managers are highly portable. One can easily install
npm on virtually any computer. For Unix-based operating systems, it can be as easy as a single command in the terminal (
sudo apt-get install pip,
sudo apt-get install npm for Ubuntu).
Created by Stuart Feldman in 1977, the
make in their workflows. One key feature of
make that makes it extremely, even nowadays, is phony targets, i.e., targets for building that do not correspond to physical files. Traditionally, phony targets, such as
all, were used to build multiple physical targets at once (i.e. if a project consists of three executable files, then a single
make all command could be used to build all three).
However, as it turns out, since
make is general enough, one can use
make with phony targets to essentially run arbitrary code, which makes it useful in a variety of sitautions. One way in which I use
make in my personal projects is to start a local server to serve a web application for testing and debugging. Another way in which I use
make is to set up automated compilation in the background. Many build tools, particularly those that can be installed via
npm, come with a
--watch flag that will "watch" source files for changes and rebuild files upon detecting a change. These commands can be placed into a Makefile under a phony target, say,
watch, so that they can be easily invoked in the future via a simple
Development environments can often consist of many tools running simultaneously. There can be times where having to open and cycle through four or five terminal windows can get unwieldy. To solve this problem, one can use the terminal multiplexer
tmux, which allows one to run many different shells and programs in the same terminal session. Typically, I create a shell script called
dev_env in my project directory that, when invoked, sets up the
tmux environment with all of my background compilation and monitoring tools running. The cover photo of this article shows an example of this, where I have a Flask development server running in the top-left corner, and several compilation tools on watch mode in the other three panes. I do most of my coding in Sublime Text (as you can probably also see), and whenever I need to check whether my code is compiling correctly, I would simply Alt-Tab over to the Terminal window and see everything all at once. I also have a separate
tmux window (in the same Terminal) that has the local Python virtual environment loaded, and to access it I can simply press Ctrl-Shift-Right (this is a custom
tmux key binding) to switch windows. Like
tmux is freely available and can be easily instally on most Unix-based computers via a single command (
sudo apt-get install tmux on Ubuntu).
Regardless of how you choose to set up your development environments, remember to always take the time to do so early in the project in order to get the most out of them. At my university where I worked as a TA, I've helped many students on assignments that require a
Makefile, and I've found that so many of them wait until the last minute before submitting their assignments to write their
Makefiles, which completely defeats the purpose. Granted, for many of them, it was their first time learning about the wonders of
make, and so it was an excusable offence, but for those of us with more experience programming, there ought to be no excuse not to set up our tooling properly.
I hope that you will find what I have written this article useful in your own projects. Good hunting!
— Yanjun Yang (@coolfan)