DevOps, Open Source, platform, Programming

In Praise of Low Tech DevEx

When I started my career as an engineer in the early noughties, I was very keen on developer experience (devex).

So when I joined a company whose chosen language was TCL (no, really), I decided to ask the engineering mailing list what IDEs they used. Surely the senior engineers, with all their wisdom and experience, would tell which of the many IDEs available at the time made them the most productive? This was decades before ‘developer experience’ had a name, but nonetheless it was exactly what I was talking about, and what people fretted about.

Minutes later, I received a terse one-word missive from the CTO:

From: CTO
Subject: IDEs

> Which IDEs do people recommend using here? Thanks,
> Ian

vim

Being young and full of precocious wisdom, I ignored this advice for a while. I installed Eclipse (which took up more RAM than my machine had, and quickly crashed it), and settled on Kate (do people still use Kate?). But eventually I twigged that I was no more productive than those around me that used vim.

So, dear reader, I married vim. That marriage is still going strong twenty years later, and our love is deeper than ever.

This pattern has been repeated multiple times with various tools:

  • see the fancy new GUI
  • try it
  • gradually realise that the command-line, text-only, steep-learning-curve, low-tech approach is the most productive

Some time ago it got to the point where when someone shows me the GUI, I ask where the command-line version is, as I’d rather use that. I often get funny looks at both this, and when I say I’d rather not use Visual Studio if possible.

I also find looking at gvim makes me feel a bit queasy, like seeing your dad dancing at a wedding.

This is not a vim vs not-vim post. Vim is just one of the oldest and most enduring examples of an approach which I’ve found has served me better as I’ve got older.

I call this approach ‘low-tech devex’, or ‘LTD’. It prefers:

  • Long-standing, battle-hardened tools that have stood the test of time
  • Tools with stable histories
  • Small tools with relatively few dependencies
  • Text-based input and output
  • Command-line approaches that exemplify unix principles
  • Tools that don’t require daemons/engines to run

LTD also is an abbreviation of ‘limited’, which seems appropriate…

How Is Low-Tech Devex Better?

All LTD tools arguably reflect the aims and principles of the UNIX philosophy, which has been summarised as:

Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

Portability

LTD is generally very portable. If you can use vim, it will work in a variety of situations, both friendly and hostile. vim, for example can easily be run on Windows, MacOS, Linux, or even that old HPUX server which doesn’t even run bash, yet does run your mission-critical database.

Speed

These tools tend to run fast when doing their work, and take little time to start up. This can make a big difference if you are in a ‘flow’ state when coding. They also tend to offer fewer distractions as you’re working. I just started up VSCode on my M2 Mac in a random folder with one file in it, and it took over 30 seconds until I could start typing.

Power

Although the learning curve can be steep, these tools tend to allow you to do extremely powerful things. The return on the investment, after an initial dip, is steep and long-lasting. Just ask any emacs user.

Composability / Embeddability

Because these tools have fewer dependencies, they tend to be more easily composable with – or embeddable in – one another. This is a consequence of the Unix philosophy.

For example, using vim inside a running Docker container is no problem, but if you want to exec onto your Ubuntu container running in production and run VSCode quickly and easily, good luck with all that. (Admittedly, VSCode is a tool I do use occasionally, as it’s very powerful for certain use cases, very widely used, and seems designed to make engineers’ lives easier rather than collect a fee. But I do so under duress, usually.)

And because they use also typically use standard *nix conventions, these tools can be chained together to produce more and more bespoke solutions quickly and flexibly.

Users’ Needs Are Emphasised

LTD tools are generally written by and for the user’s needs, rather than any purchaser’s needs. Purchasers like fancy GUIs and point-and-click interfaces, and ‘new’ tools. Prettiness and novelty don’t help the user in the long term.

More Sustainable

These tools have been around for decades (in most cases), and are highly unlikely to go away. Once you’ve picked one for a task, it’s unlikely you’ll need a new one.

More Maintainable

Again, because these tools have been around for a long time, they tend to have a very stable interface and feature set. There’s little more annoying than picking up an old project and discovering you have to upgrade a bunch of dependencies and even rewrite code to get your project fired up again (I’m looking at you, node).

How We Use LTD

Here’s an edited example of a project I wrote for myself which mirrors some of the projects we have built for our more engineering-focussed clients.

Developer experience starts with a Makefile. Traditionally, Makefiles were used for compiling binaries efficiently and accounting for dependencies that may or may not need updating.

In the ‘modern’ world of software delivery, they can be used to provide a useful interface for the engineer for what the project can do. As the team works on the project they can add commands to the list for tasks that they often perform.

help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

docker_build: ## Build the docker image to run in
docker build -t data-scraper . | tee /tmp/data-scraper-docker-build
docker tag data-scraper:latest docker.io/imiell/data-scraper

get_latest: docker_build ## Get latest data
@docker run \
-w="/data-scraper" \
--user="$(shell id -u):$(shell id -g)" \
--volume="$(PWD):/data-scraper" \
--volume="$(HOME)/.local:/home/imiell/.local" \
-- volume="$(HOME)/.bash_history:/home/imiell/.bash_history" \
--volume="/etc/group:/etc/group:ro" \
--volume="/etc/passwd:/etc/passwd:ro" \
--volume="/etc/shadow:/etc/shadow:ro" \
--network="host" \
--name=get_latest_priority \
data-scraper \
./src/get-latest.sh

It's a great way of sharing 'best practice' within a team.

I then have a make.sh script which wraps calls to make with features such as capturing logs in a standard format and cleaning up any left-over files once a task is done. I then use that script in a crontab in production like this:

*/5 * * * * imiell run-one /home/imiell/git/data-scraper/src/make.sh \
get_latest

Using run-one and cron I can effectively have a daemon running on my server with very little overhead.

A challenge with make is that it has quite a steep learning curve for most engineers to write, and an idiosyncratic syntax (to younger eyes, at least).

However, while it can seem tricky to write Makefiles, it’s relatively easy to use them, which makes them quite a useful tool for getting new team members onboarded quickly. And for my personal projects - given enough time - new team members can mean me! If I return to a project after a time, I just run make help and I can see instantly what my developer workflow looks like.

Here’s an example make help on a project I’m working on:

This means if I have to onboard a new engineer, they can just run make help to determine what actions they can perform, and because most of the tasks run in containers or use standard tooling, it should work anywhere the command line and Docker is available.

This idea is similar to Dagger, which seeks to be a portable CI/CD engine where steps run in containers. However, running Dagger on Kubernetes requires privileged access and carries with it a Dagger engine, which requires installation and maintenance. make requires none of these moving parts, which makes maintenance and installation significantly simpler. The primitives used in Make can be used in your CI/CD tool of choice to create a similar effect.

What Low-Tech Devex Tools Should You Know About?

Here is a highly opinionated list of LTD tooling that you should know:

shell

Mastery of shells are essential to LTD; they underpin almost all of them.

vim/emacs

Already mentioned above, vim is available everywhere and is very powerful and flexible. Other similar editors are available and inspire similar levels of religious fervour.

make

Make is the cockroach of build tools: it just won’t die. Others have come and gone, some are still here, but make is always there, does the job, and can’t go out of fashion because it’s always been out of fashion.

However, as noted above, the learning curve is rather steep. It also has its limits in terms of whizz-bang features.

Docker

The trendiest of these. I could talk instead of chroot jails and how they can improve devex and delivery a lot on their own, but I won’t go there, as Docker is now relatively ubiquitous and mature. Docker is best enjoyed as a command line interface (CLI) tool, and it’s speed and flexibility composed with some makefiles or shell scripts can improve developer experience enormously.

tmux / screen

When your annoying neighbour bangs on about how the terminal can’t give you the multi-window joy of a GUI IDE, crack your knuckles and show them one of these tools. Not only can they give you windowing capabilities, they can be manipulated faster than someone can move a mouse.

I adore tmux and key sequences like :movew -r and CTRL+B z CTRL+B SPACE are second nature to me now.

git

Distributed source control at the command line. ’nuff said.

curl

cURL is one of my favs. I prefer to use it over GUI tools like Postman, as you can just save command lines in Markdown files for how-to guides and playbooks. And it’s super useful when you want to debug a network request by ‘exporting as cURL command’ from Chrome devtools.

cloud shell

Cloud providers provide in-browser terminals with the provider’s CLI installed. This avoids the need to configure keys (if you are already logged in) and worry about the versioning or dependencies of the CLI. I agree with @hibri here.

ssh

Why bother with the faffs of remote desktops when you have ssh and tmux? If you depend on GUIs, that’s the problem you need to solve.

Finally, special mentions to these text user interfaces (TUIs) and dev-friendly tools:

  • k9s – text user interface (TUI) for Kubernetes
  • top/htop/ctop etc – monitoring tools
  • sar – monitoring/performance analysis tool
  • entr – run commands when specific files change. Get rapid feedback in dev.
  • nnn – file browser
Comments
Leave your Comment