Real Programmers
13 May 2025
There’s been an explosion of tools for software development. At the same time there’s a growing sense that software quality isn’t what it used to be—or that developers these days don’t understand what it takes to be a “real” programmer, whatever that means. I’m not that old, but I have some old-school tool preferences. Some tools I really like; in other cases I feel that by not adopting particular habits, I’ve gained or retained an edge over others in the software development space.
Notice: This is a rough-and-raw dump of some ideas that were ratting around in my head. Read at your own risk.
Graybeard #
I learned programming from a command line with nothing but a few books and some man
pages to guide me. I am extremely comfortable navigating and controlling my computer via the terminal.
Most college kids these days will start their programming journey with an IDE and Python Or C++ if they’re unlucky. and they learn nothing about how the operating system works under the hood. This is why things like MIT’s course “The Missing Semester of Your CS Education” exist: to get programmers up to speed on the tooling developed over the past several decades.
The thing is, there are a lot of new-fangled tools that programers have been picking up: instead of Emacs or Vim they use VS Code or Cursor. Instead of the git
CLI they use the VS Code Git client. Instead of grep
and perl
they… I don’t know what they do to replace those tools honestly. Maybe they look for an NPM package that purports to do what they want.
A lot of the new tools have less friction than old tools. But that typically comes at the cost of being further away from the underlying infrastructure. Tools like VS Code, etc. are less inspectable and understandable than Emacs and the like. GUIs—sometimes labeled “point-and-grunt interfaces”—almost always expose a smaller set of operations than comparable text-based interfaces to the user. Command line tools win by being composable; GUIs are very hard to plug together quickly in an ad-hoc way.
The value of friction #
I believe it is important that every serious user of a computer—CS students especially—get familiar and comfortable with the command line. Our computers are rickety contraptions that frequently break or have novel requests made of them. Knowing the constituent components that make up an operating system, as well as some of the fundamental tools around software development (e.g. Make, Git, etc.) can help you get used to gluing generic utilities together to create perfectly-tailored workflows or one-off tools.
I have been able to perform acts of astonishing wizardry—relative to the “average” computer-user—because I knew how to glue together a few command line utilities to process a huge amount of data in a short amount of time. Likewise, I am a capable programmer and have been able to effect some extraordinary refactors because I know how to make Emacs do my bidding in ways that would make your average VS Coder weep. Big respect out there for all the hard-core Vim users too. Vim is the gold standard for text editing efficiency.
Being able to “pop the hood” on your computer and figure out what is going wrong lets you build more, better. When something goes wrong, you have a better mental model of how to fix it. When some new task comes up that no developer has ever encountered—it happens more than you think—you have the tools you need to create a novel solution.
The value of abstraction #
And yet, I do not know how my car works. I drive an automatic. Computers are becoming increasingly a commodity like a car—is it so bad that more people don’t know how the innards work?
Two points: first, I believe that it is good that most people do not have to know how a file system functions to get work done on the computer. Second, I believe that any craftsperson understand their tools to the fullest extent—for race car drivers, this would be understanding how an engine works, and for programmers, the operating system.
To the first point: most people have high-level tasks that they want to accomplish. They want a friend to see a picture that they took, so they load it up in an email or messaging service and send it off. They don’t need to know about image encoding, network routing, etc. to get this done. This is good.
Programmers, too, often have high-level things that they want to accomplish. Consider editing a code base: when reading some code, I often want to jump from where a function is called to where it is defined. This task is more semantically meaningful to me than carefully crafting a regex for grep
to show me where I might want to go. The less friction in this process, the better: it lets me stay more in flow and helps me get my work done.
The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.
I learned how to use Git via the CLI. Now I use Magit. This is because Magit walks a delicate line: it makes common operations much easier than the CLI, yet at the same time it doesn’t baby me—it actually helps with discoverability—and it can compose Git commands at times to accomplish higher-level functions.
Example: there are commands to “spin off” a series of unpushed commits into a new branch. It does this by creating a new branch, then reverting the old branch to point to whatever its upstream remote was. Super helpful when you start development work and realize after the fact that you should probably be working on a new branch.
Moreover, I can see how it works under the hood: Magit can show you all the git
commands it’s running to do what you want.
I think we need more tools like Magit: things like lazygit, lazydocker, tldr, LSP, etc. all extend users’ understanding of systems whilst not keeping them too far from the source.
The gift of choice #
I think it’s valuable to be able to choose the level of abstraction to work on. I’m never far away from a command prompt while I’m working on my computer. Yet, most of the time I do my Git work via Magit. Magit is powerful enough that I typically don’t need to resort to the command line, yet sometimes I do for things like setting configuration variables.
I think that it is good that we have tools that operate at higher levels of abstraction—GUIs even—because these can help us stay more rooted in the semantics of our problem domains. At the same time, I think it is crucial that software engineers get comfortable with understanding the fundamentals of operating systems, version control, text editing, scripting, etc. so that they can build new abstractions when the need arises.
Computers are still in their infancy. They’re just barely taking their first steps. I see no reason to use exclusively decades-old command line tools when we have some fantastic new utilities that aid our ability to build more and better software. Yet we must not forget the basics, lest we loose the ability to take steps on our own.