My Developer Setup (with Vim, Tmux, and Zsh)
Customizing your development environment can be both important and fun. This is how I got started with using Vim, Tmux, and Zsh.
Whether you're an industry veteran or a new coder, you should probably invest more time configuring your development environment. When you're staring at the same screen day after day, polishing that screen becomes one of the highest leverage tasks you can pick up in the long run.
In this blog post, I share what I've done to customize my development environment.
Why should you care?
While customization is a personal choice, I still believe every developer should toy around with configurations at least once. It pays dividends in a couple of ways:
- You work faster when you're familiar with the tools at your disposal.
- You enjoy your work more if you're working in a comfortable environment.
- Configurations force you to dig through some abstractions and understand the tools you're using.
(These are true from personal anecdote, at least.)
My development environment revolves around a zsh
/ vim
/ tmux
setup. Most of my choices were made to optimize for speed and portability. Everything happens in the terminal, so there's minimal context switching. Certain tools I use (like Vim) have a learning curve, meaning you'll struggle to pick it up at first. But once you've achieved a certain level of competence, you become very productive. Everything works in any POSIX environment, meaning that I can clone a repository and have a working environment in a single command.
The Terminal and Oh-My-Zsh (~/.zshrc
)
On POSIX-based machines, I use Zsh as my default shell. (If I ever need to do development on a Windows machine, I install the Windows Subsystem for Linux. Then I set my shell to Zsh.)
While most terminals default to Bash, Zsh stands out due to its exceptional plugin support. That makes Zsh a preferable choice if you intend on customizing your shell. There's a rather popular Zsh framework called Oh-My-Zsh that I use. It allows you to track things like the status of your git repository and Python virtual environment out of the box. You're also able to change themes at will, meaning you can get a pretty terminal with minimal effort. My Zsh theme of choice is called powerlevel10k. It allows me to have a terminal that looks like the screenshot below.
For my terminal color scheme, I use Solarized Dark. It's been sold as an "objectively better" color scheme since the color contrast was designed to be easier on the eyes. To my knowledge, no other color scheme makes any claims of objective superiority. Since I didn't have strong opinions on the color of my terminal background, I picked Solarized Dark. If its claim is true, then I've chosen the "best" color scheme. If not, I suffer no penalty. Either way, I'm no worse off than before.
Alternatives to Popular CLI Tools
Some of the core commands you run daily might have been written before you were born. While that generally implies that these are reliable tools, it also means they're old and there exist modern alternatives. I've included a table of my favorites below:
Purpose | Traditional Tool | My Alternative |
---|---|---|
List Directory | ls |
exa |
Display File Contents | cat |
bat |
General Search | grep |
rg |
File Search | find |
fd |
Diffing | diff |
delta |
For the most part, all you need to do is to install the replacement command and then alias it to your original command. It becomes a drop-in replacement, and your life becomes better without any additional effort.
alias ls="exa"
alias cat="bat"
# and so on...
Fuzzy Finder
One of the most underappreciated tools in the developer's arsenal is fuzzy searching. You type in approximately what you're looking for, and you get reasonable results. The specific tool I use for fuzzy searching is called fzf
. It's a general-purpose command-line fuzzy finder, so you can use it in conjunction with most shell operations. It's hard to explain without going into specifics, so I'll share a few ways I use fzf
.
Suppose I'm looking for active Chrome processes on a machine. I might list processes and pipe them into grep
(or rg
). The problem here is that I have to know exactly what to search for immediately. If we pipe it into fzf
instead, we can arbitrarily type search queries without having to reload the command.
ps aux | grep Chrome # grep is case sensitive
ps aux | rg chrome # For grep/ripgrep, we get a static result.
ps aux | fzf # With fzf, we can comb through results on demand!
Fuzzy searching isn't just for piping other commands. If working in a large git repository and want to open up a file in Vim, it's a pain to type in the specific file. Tab completion helps, but you still need to type in a majority of the path. Fortunately, fzf
comes with a few keyboard shortcuts. I can type vim <ctrl-t>
and fzf
will show me a list of candidate files to open. I type in the approximate path to the file, and it can locate what I want with minimal effort on my end. There are similar keyboard shortcuts for shell history search and directory search. I just type in approximately what I want, and fzf
does the rest.
Text Editing (~/.vimrc
)
I don't use IDEs or "modern" text editors when coding. Instead, I use Neovim as my preferred text editor. (It's a drop-in replacement for Vim with a few added benefits.) There two are reasons why it stands out above any alternatives: it's fast and it's portable. Notice how those are the exact features I'm looking for!
Vim has been infamous for its keyboard shortcuts. If you know how to operate the text editor, your hands never need to leave the keyboard. You can also create macros within the text editor, meaning it's possible to automate any repetitive typing tasks. Vim is also a lightweight program. It starts up in milliseconds and can support files that are too large for "modern" text editors to even open. Everything just works. Since Vim runs within the terminal, it's possible to have the same experience across machines, even if you're developing over SSH. Just make sure the program has been installed and you're done.
While many consider Vim an "old" text editor, it can support modern features such as plugins and language servers. For package management, I use vim-plug
to install general Vim plugins. For language server support, I use coc.nvim
. That way, if I need autocompletion or jump-to-definition for a language, I just need to type in a single command to install a new language server. Vim works well with fzf
too. If I want to open a new file, I can hit <ctrl-p>
and open a fzf
buffer. It allows me to find arbitrary files without knowing their paths or closing my editor.
Tmux (~/.tmux.conf
)
If you're a terminal-centric developer (like me), it makes sense to use a terminal multiplexer like tmux
. A terminal multiplexer allows you to split a terminal into multiple panes or create virtual tabs with new terminals. If you develop on a remote machine, terminal multiplexers become even more useful. You only need one SSH connection to maintain multiple terminals. Your tmux
session also lives independently of your SSH connection. If you choose to log off, you don't lose your work. Just detach from tmux
and reattach whenever you want to resume your work.
Version Control (~/.dotfiles
)
To wrap everything neatly in a bow, I keep all of my dotfile configurations under version control. There's a single git repository that holds all of my configuration files. Any local config file is just a symlink to a corresponding file within the git repository. If you're looking to get started, copying my dotfiles is a great way to get your feet wet.
Since we have everything under version control, it's simple to track incremental changes over time. Additionally, I'm free to make experimental changes without fear of regressions. Version control also trivializes migrating the configs to a new machine. All you need to do is to clone the git repository and run a setup script that creates symlinks to the files within the repository.
For my dotfiles, I've created the following one-liner that does all the repository cloning and setup. I run the command, wait a few seconds, and the new machine turns into a familiar environment. And that's it. You're done.
# This command is literally all you need to get started...
curl -L andrew.cloud/dotfiles.sh | sh
Final Thoughts
And that's all I have to share. Tinkering with configs has made me pickier, but it has also turned me into a better developer. We tend to have too much tolerance for default tooling, and that slows us down in the long run. A few years ago, I started to wonder why we didn't focus more on our development environments.
I hope reading this makes you question it as well.
Thanks for reading! If you want to read new blog posts like this, consider subscribing to be kept in the loop.