This week we have JP Monetta on Apropos. He’s the creator of FlowStorm Debugger, which is a time traveling debugger for Clojure. Check it out! It is quite amazing.
Beginner Clojure, my video course, is better than ever. I recently completely rebuilt the Introduction to Clojure module. It’s the fastest way to get from zero to a deep, functional programming and data-driven programming experience. Go check it out to see why hundreds of people have enjoyed it. If you buy, you get lifetime access plus all updates. Planned future updates include VS Code with Calva, The Clojure Command-Line, and Shell Scripting with Babashka. The course already contains eight great modules, including JVM, Repl-Driven Development, and functional programming. Buy it today.
Crafting your environment
My Emacs setup is boring. So is my shell prompt. I’ve usually left things vanilla. Sometimes I look at other programmers and their awesome tooling setup and their colorful zsh prompts and feel superior. I tell myself that I am serious. I don’t waste time with silly things. Instead, I get to work. I’m very conservative.
But over time, I’ve heard of enough arguments for extreme configuration and seen enough examples of powerful IDE setups and missed enough tools that are now standard that I wonder if I’m wrong. Is it a waste of time? Or is it time invested? I’m starting to like the other side, though I’m still very bad at it.
Let’s start with the argument for why it’s not really worth your time to improve your tools.
Being slightly faster does not pay off
Sometimes I see a programmer obsessing over their setup. They’re spending hours reading forums and getting their Emacs config just the way they like it. They get into building their own keyboard. They figure out the best chair to sit in. It’s not so much that it doesn’t matter at all, it’s that it seems like a huge distraction. You want to be better at programming, so you spend hours 3D printing your keycaps? It seems to me like a big waste of time.
Let’s calculate it. If you spend 10 hours making a keyboard (which is very conservative), and it makes you 1% faster at typing, and we assume you spend 1 hour per day typing, you will need to type for 1,000 hours before you’ve made up the difference. That’s 2.7 years. That doesn’t seem worthwhile to me.
Typing speed is not the bottleneck
One of my friends put it this way: Typing speed is not the bottleneck in programming. They’re evoking a principle from the Theory of Constraints which is very popular in manufacturing circles. The principles says that every system has a bottleneck, and improvements to anything besides the bottleneck will not improve the overall productivity of the system. The bottleneck is the limiting factor. According to my friend, typing speed is not the the limiting factor to your effectiveness as a programmer.
All that time spent learning another vim command won’t really make your programming faster. You’re still limited by the bottleneck, which I agree is not typing speed.
Customization is not shareable
And just one more issue with ultra-customization. One time I was pairing with my coworker on his laptop. I was having trouble communicating something he should try, so he handed me the laptop. I put my hands on the keys. And every key I pressed surprised me. I was skilled at Emacs. And this was Emacs. But this was not the Emacs I knew.
He had customized the basic Emacs commands to different keys. And the official keys were remapped to other commands. They made sense to him, but I was useless on his keyboard. That really made me double down on leaving keys standard. With non-standard keys, sure, you may be faster, but nobody else can use your computer.
Do you agree with these? Are there other arguments?
I once agreed with these, but not any more. These three arguments are missing something important.
Being slightly faster is not the point
The reason the “efficiency argument” doesn’t hold water is that it’s not really about being faster. If all you’re looking at is productivity such as lines of code per second, you’re missing the main point. I talk about this a lot in The Surprising Benefits of Automation. We improve our tools and skills for agency and efficient use of cognitive resources, which we’ll talk about soon.
Typing is on the critical path
My friend evoked the concept of the bottleneck from manufacturing (note the efficiency mindset). Another concept from manufacturing and project management is the critical path. This is the path of sequential steps that affect the timeline of the project if they take more or less time. Typing might not be the bottleneck, but it is on the critical path, especially of iterative development practices like REPL-Driven Development (RDD).
I think what my friend meant when he said that typing is not the bottleneck is that programming is mostly about thinking. You might spend two hours thinking and ten minutes typing it in. Taking eleven minutes to type it in isn’t going to seriously change the timeline.
However, when I’m doing RDD, the speed I can type a piece of code, eval it, and understand its effect is part of the thinking process. With RDD, we extend our mental capacity with the REPL, just like a geometer extends their mental capacity with a compass and straightedge. The faster you can go through the loop, the better integrated your thinking and the REPL can be. Slowing down your typing can significantly affect that integration. And speeding it up with better configuration can help it, too.
And typing speed becomes more important the more iterative and incremental your process is. If you’re doing waterfall, your process is dominated by thinking, planning, design, and redesign. But if you’re working iteratively, you are typing a lot and learning from the result. The faster you type, the faster you learn.
Customization is not shareable
Well, this one I think is still huge. But as Juan Monetta opined on our recent episode of Apropos, that is much less important when we’re all programming on our own machines. We share a lot of development tooling: Linter configs, formatter configs, and tests. But do we need to share editor configurations? I’ve heard it both ways. I’ve heard people who love pairing and process argue that the team should be discovering as a group the best way to work as a team—meaning they should use the same editor configuration. But I’ve also worked at places that took an individualistic approach, so much so that the variance of productivity and understanding was huge. Some people knew how to run the code at the REPL, and others thought it was impossible. More on this later.
Now that we see that it’s not about speed but about cognitive resources, what are some arguments for configuration?
Energy and joy
Let’s say you open up a drawer in your kitchen. It’s filled with kitchen tools, but it’s a cluttered mess. It’s frustrating. You dig around, find the spoon you need, and close it. You get on with your cooking task. Or you could stop what you’re doing and organize the drawer. Toss out broken tools. Create sections and sort the tools that you still use. How do you feel afterwards? I bet you feel energized. The frustration has turned to joy.
The fact is, feeling control over your environment is important psychologically. That frustration is a signal that you want something to change. Ignoring that signal takes energy. Resigning yourself to live with frustration is a sure path to despair and burnout.
Energy is important. You can’t measure everything based on time efficiency. Time efficiency could be important, but it’s not everything. A programmer’s good energy improves their agency and their productivity. If a programmer feels like they can’t improve their environment, they’re more likely to zone out at work. You might as well use that zone-out time to make some improvements.
Cognitive resources are a bottleneck
My friend was correct that thinking is the bottleneck. Each of us is endowed with a certain amount of “cognitive resources” to work with. Research shows that this is a limited and shared resource—there’s only one pool of it. So if your roof is leaking and you’re worried about it, that will affect your programming at work. The bottleneck is the cognitive resource pool.
Your resources are also drained by tasks that take effort. Imagine if you had to search for the {
key on the keyboard each time you needed to type it. Sure, it would slow you down. But worse than the slowdown is that you would use up precious cognitive resources. You would have fewer resources to think about the problem. If it took you long enough, you might even forget what you were trying to do. In short, it’s not slow typing that is the problem, but typing that takes effort.
How many of your subskills take effort because you haven’t mastered them yet? Maybe you can type {
without thinking about it. But what about figuring out which braces to close? An easy solution is to use paredit—but that requires configuration and learning new keystrokes. Well worth it in my opinion. But what other packages could unlock similar improvements?
Experimentation and waste
I try to read a lot of books on programming. Learning from others is a great way to get better. Right now, I’m focused on books on software design. Unfortunately, most of the books on software design have bad advice. Does that mean it’s a waste of time to even look? Hour-for-hour, I don’t think it’s worth it. My software design skills could not have improved by that much. I have spent thousands of hours over my career reading programming advice. But it probably has not led me to ship everything thousands of hours faster (even in aggregate).
But how can we know? I certainly feel like the time spent reading was worth it, even considering that a lot of the advice was bad. When I look at my skill vs someone who doesn’t read, I can see the difference. When I look at my skill vs myself 10 years ago, having read fewer books, I can see the difference. But I can’t attribute any improvement to any particular piece of advice.
While you’re reading, you are absorbing other people’s experience. You’re organizing your own experiences. Even when you read something you don’t agree with, it could give you a new perspective on that idea. Reading alongside direct experience helps you learn.
Likewise, when I see someone building their fifth custom keyboard, it feels like a waste of time. Do you really think you’re going to get that much better this time? But they think it’s possible. And even if the keyboard doesn’t make them better, there’s something else going on: Engagement in the process. Building your own keyboard is a physical way to engage your brain. What keystrokes are important to my process? How do I want that key to feel when I press it? What fingers do I want to use? The learning transfers to configuration and typing.
You cannot program 100% of the time
Another misconception is that configuration time is eating away at programming time. If you’d give up that time spent configuring, you’d have more time to program. But that’s not how people work. We need breaks from the productive work. The productive work makes a mess, and we need to clean up. The productive work gives us ideas for doing our work better, and we can use those ideas to improve our work.
Permission to make small improvements
If you want to engender resentment and passivity in your programmers, tell them they can’t configure their tools. They’ll probably say they agree with you that it’s a waste of time. But you’ve also tapped into the efficiency-seeking part of the brain. That efficiency-seeking part of the brain isn’t looking to get more done with less. No, it’s about doing as little as they can get away with.
If you want to activate someone’s brain to look for ways to improve, encourage (or require!) them to make small changes daily. Some companies require each employee to make a change that could save them 2 seconds. Setting the bar low makes it achievable. But it also gets the mental balls rolling. With each small change, they develop a sense of ownership over their process and that engenders agency—which is probably what you want in an employee.
Improvements compound
Some tweak to your process might seem small. But over time, the work with each other to improve non-linearly.
Working at the right cognitive level
Again, typing speed is not the bottleneck, but thought is. If you are moving a cursor around, backspacing, and typing, you’re thinking about the cursor and characters. Another person, however, could be issuing higher-level commands, like rename symbol, if they had the right configuration and practice with the keystrokes. There is less distance between what they want done and the command to do it. It’s not about speed. It’s about the cognitive processing it takes to translate the desired action into editor commands.
Improvements reveal underlying problems
As workers at Toyota eliminated inventory between steps, the assembly line would start to break. They would say: “We told you that we need that inventory. Otherwise the process doesn’t run smoothly.”
Taiichi Ohno didn’t agree: “We are lowering the level of the water in the river (the inventory) to reveal the stones (the problems). The stones were always there, we just couldn’t see them.”
Taiichi Ohno knew that inventory tends to pile up before the bottleneck. Since the bottleneck is the slowest step in the process, the fast steps before it produce more than the bottleneck can handle. But when he looked around, there was inventory everywhere. By eliminating the easy piles of inventory, he could see where the real problems were.
We can do that in our tools, too. Our tools are full of frustration. We can start anywhere, fixing problems as we see them. This will make the process smoother up to a point. But the better our configuration is, the easier it is to see the parts that still frustrate us. Focusing on the bottleneck is good in theory, but it’s hard to recognize the bottleneck when everything feels frustrating.
Fixing our frustrations leads to new projects
If we don’t fix our frustrations, we have a tendency to become blind to them. We get used to them and work around them. But these frustrations can be very valuable. Frustration with existing debugging approaches (like println
) fueled the development of FlowStorm. And Tailwind CSS’s creator Adam Wathan credits his sensitivity to frustration for the development of Tailwind. If you’re feeling frustrated, chances are, other programmers do, too. Your solution could be valuable to them.
Discontinuous improvement
There’s a phrase “continuous improvement”, which sounds great. You’re making improvements all the time. But I also think there’s something like discontinuous improvement, too. You see, if our cognitive resources are the bottleneck, there’s a discontinuity at the edge of our cognitive capacity. Jobs just bigger than our capacity need some kind of process and externalization (like a todo list) to manage it. But jobs small enough to fit in our minds don’t. If you can cross that boundary with better skills and tooling, you’ve got a stepwise improvement.
Aesthetics are important
When I see people geeking out over their keyboards, it’s not just about function. People choose colors and lights and other design elements that please them. The same for a lovely shell prompt or a nice font in their editor. The aesthetics of your environment plays a noticeable role in your productivity. If your office is a dump, you’ll probably make trash software. But if you surround yourself with beautiful things, you’ll be inspired to do beautiful work.
Now let’s talk about some principles that can help make the most of this learning.
Manage resources
The most important principle is that we are trying to manage limited cognitive resources. You can:
Make a tool more pleasant so that it gives you more resources (e.g., make it have nice UX)
Use tools that operate with the right concepts (e.g., paredit)
Learn a skill better so that it takes fewer resources to perform (e.g., practicing paredit commands so they are muscle memory)
Choose your battles
Alan Kay talks about the problem with a good engineer is they are so dissatisfied with everything that they want to build it all themselves. It takes great discernment to choose what you build on top of. Likewise, improvements do have a cost. Are you really going to hand-craft your keyboard? Might you want to try one of the existing commercial ones first? It might get you 99% of the way there.
Configure away, but use standard keystrokes
Emacs has a set of keystrokes that come standard out of the box. They have been the same for decades. C-a
goes to the beginning of the line. C-e
goes to the end. C-x-f
opens a file. And, believe it or not, there are many packages for opening files. So while you can change the way you open files, most packages keep the same keystroke. Even though the behavior is different, someone familiar with the keystrokes can still use it. I recommend that approach.
Share when you can
I’m not as extreme as my friend who wanted everyone at the company to program with the same tools. But I also think most companies don’t encourage enough sharing of tooling and process. Pairing and watching people work can help spread the great tools and skills that people have set up. But you can also just talk about it. Have a monthly meeting where someone shows off their editor.
AI can help you configure
I don’t use AI to generate production code. But I’m leaning on AI now to help me configure my tools. Even though I’ve used Emacs for years, I’m terrible at programming it. I have to admit that it’s one of the reasons I haven’t done more configuration. Likewise for packages. There are just so many out there. I don’t have the patience to try them all. But with AI, I can ask for package recommendations and for tips to configure it how I like it. It’s really helping.
It's interesting that you mention shell prompts...
PS1="\n\[\e[34;1m\](\D{%F.%T})-(\w)\n\[\e[3\`if [[ \$? = 0 ]]; then echo 2; else echo 1; fi\`;1m\](!\!)-> \[\e[0m\]"
That shows (date.time)-(pwd) and (!history#)-> with the latter color-coded to green or red depending on the success of the previous command.
I tend to have at least four terminal windows open (plus whatever terminals I open in my editor), so being able to see at a glance when I last touched a terminal, where I am, and whether a command exited with 0 or not really helps me keep my bearings.
Overall, I agree with (mostly) keeping the core defaults for editors and so on -- if only so books and documentation (and AI helpers!) are all on the same page about how to drive your tools.
With Clojure, I think one thing that is core to productivity is figuring out a tight integration between your editor and the REPL, and also being able to do common things like running tests, all with easily memorized key bindings. I remember Stu Halloway talking about being bewildered by people who type directly into their REPL, or even copy'n'paste into their REPL, instead of having that evaluation hooked up directly to files and (comment ..) forms.