Software engineers all require some sort of tooling to do their job. Even the realest of real programmers, and the vibiest of vibe coders have something that they use to write code with. I have yet to find someone who is capable of creating something in the programming world by just thinking it into existence. We as humans have to rely on something (or rather a collection of several things) to serve as the medium to which we take our ideas and make them some form of relatiy, even if that reality is in the digital space.
As such, our dev tools play a significant role in our functions as software engineers. It can be pretty easy to discount the value of dev tools, but both having the right tools and knowing how to effectively use them can have a large impact on our productivity and overall experience as developers. It’s also important to not only know how to use tools effectively, but also to have some idea of what the tools are actually helping with. I’ve watched the content of the Netflix engineer ThePrimeagen
for some time, and one of the things that Prime repeatedly emphasizes is the importance of knowing what your tools are doing, often pushing engineers to have an idea of what the “green play button” in their editor actually does, so that they can fix issues if and when they arise.
With all of that in mind, I figured it could be interesting to share what my current developer setup looks like, touch a bit on what changes I’ve made along the way, and show what I like to think is a decent balance between high-level convenience with lower-level general understanding. Odds are there will be at least one thing that you think I’m silly for using, but it is what it is.
Operating System
For development, I most ofen find myself (and prefer) using Linux. Talking about Linux distro preferences or dislikes can be it’s own lengthy and opinionated subject, so to avoid going too deep into that, I’ve worked with both the Debian family (really Ubuntu), and RHEL/CentOS/Rocky systems professionally, and am running Pop!_OS at home. The biggest thing that I look for in a linux distro currently is general stability and ability to follow some form of externally known convention. As fun as it would be to contsantly be updating stuff to the bleeding edge like in Arch or Gentoo, I really don’t have the time to be troubleshooting why my OS is causing me troubles when I’m sitting down to program (especially on my own time!). I also find the 6 motnh update schedule of something like fedora to be just a bit too often for me, so the ability to stick to a 2 year LTS verison is pretty compelling, though with PoP!_OS I historically tried to keep up with the 6 month releases, that is until they froze OS updates to go work on cosmic.
I also personally prefer to have a known convention for how stuff works. Sure, the near-infinite cusomization of Linux is really nice, but I tend to not want to go down the cusomization path much. The way FHS is supposed to be set up is an admitted weak point in my developer knowledge (as in, the difference between /bin
and /sbin
/ and /usr/bin
, etc.), but I know a handful of things, and I often want my OS to help guide me down the path of putting things in teh right spots, and having enough in place so that I don’t have to think about “is this the right spot for this binary?” or if it is “what do I have to configure in my OS to have it correctly idntify this convention?” So far, Ubuntu and firends has done this well enough for me, and Pop! has been a fun variant to work with.
What about MacOS?
Historically, I haven’t used MacOS much. Part of that might just be I’m too cheap to pay for a macbook. But, last year I finally pulled a trigger on an M3 MacBook Air to tinker around with MacOS, and to work on building iOS things, but other than that I just feel more comfortable in Linux.
WSL is Linux Right???
While WSL is technically linux, I’ve often felt more restricted using it. The terminal app just feels off for some reason. That, and some of the other tools that I use don’t work as well with it.
CLI
The terminal is arguably one of the most important tools a developer can have, especially one that seeks to have an understanding of what is actually going on. Doing things in the terminal can mean that a developer has a lot more to do in order to perform tasks like building and running your app, interacting with git, etc. But, it’s important to note that having more to do does not mean it’s either slower or worse. There are times where the terminal can be the right intuitive choice. There are times even when cli tools are faster than large-scale production systems in the right contexts.
I find myself spending a lot of time in the terminal as a developer. Anecdotally more than some of my peers, as I’ve at times been dubbed the “CLI guy” on my team. While I personally would be quick to say it’s my specialty, there are a handful of things I’ve used to make my developer experience a lot better.
Shell Type
For the longest time, I just used bash
. After all, it is the default on most Linux systems, meaning I had less to do, and didn’t want have to worry about the potentially subtle differences between shells.
But then, I gave oh-my-zsh a try.
I don’t even remeber why I have it a try. Maybe it was just curiosity? But the amount of stuff that comes in OMZ was super helpful. Plus, the project had a whole repository of out-of-the-box plugins, as well as some others that were really easy to set up. This meant that I could have configurations for a lot of the other CLI tools I used without having to figure out if ~/.bashrc
, ~/.profile
, ~/.bash_profile
, or whatever was the right spot for my customization; it all just lived in the plugins
section of ~/.zshrc
. Sure, one could replicate all the same behavior in a potentially more-performant way, but it worked well enough for me and was very simple to enable, so I became hooked.
Terminal Emulator
Again, like my shell, I just used the default. On most of my systems, that was gnomet
. While I find myself in the terminal a decent bit, I never felt consumed by the need to have the fastest or most feature-rich terminal.
But then, once again, I tried out ghostty.
Of course, ghostty
is still super new, but I’ve been liking it a lot. I still barely configure it (just enough to have a slightly different theme than the default), but I’ve appreicated the increased consistency that exists across Linux and MacOs, as well as the fact that it bundles my preferred font:
Fonts and Ligatures
I’m personally a fan of JetBrains Mono. It feels pretty versatile accross the different platforms and tools I’ve worked in, and I often find that it’s easier to read than other common monospace fonts. Maybe that’s the fact that it claims to be taller than other fonts, or just the fact that it feels less “curvy” than something like fira code - I’m not sure.
When fonts come up, I feel like there is also often a discussion around programming ligatures. For the unfamiliar, ligatures are the combination of multiple characters to render them as a single semantic “token.”
I’ve gone back and forth on ligatures. Sometimes they seem fun and different, other times I worry about how they might muddle visual calrity. Currently though, I’ve been trying them out again, and have been enjoying them.
Everyday CLI Tools
This could probably be a whole post in itself. There’s certainly a large number of CLI tools that exist, and I use a fair share of them. With that said, here are the ones that I find myself using the most often:
git
As a developer, using git is the de-facto choice for source control at this point. However, I think that there are a number of developers who don’t often use git
from the command line as much. Most of the editors that developers use (including the ones that I use) have some sort of git integration that allows for committing, pusing, pulling, branching, merging, or whatever other git operations there are to be done with the click of a button. However, I’ve personally found that I greatly prefer to perform almost all git operations from the command line. I’m not sure if that’s a consequence of how I got started as a developer, or if I just feel more “in control” by performing all the operations on the cli, or if it’s just a desire to get closer to knowing what’s actually going on behind a git operation, but running from the command line feels right, whereas using IDE tools for git operations feels unnatural to me, even if they help other developers be more effective.
asdf
asdf
is awesome. I find myself using a lot of different programming languages and versions of said programming languages both in work as well as various supporting tools for languages as well. asdf
is similar to various other version-manager tools such as nvm
, rvm
, pyenv
, SDKMAN!, and probably more for other languages. The nice thing about asdf
, however, is that is provides a single tool with a consistent interface to be able to manage all of the versions of these different tools, and does so in a way such that they automatically switch when going into different directories (something that at least nvm
doesn’t support since the last time I’ve used it). asdf
is great for a developer who is working on a project across multiple computers, as it helps to make sure that the languages and tools used to build the project are consistent without having to pay the DevX overhead of developing code in a docker container. It also shines when working on a team, as all team members can have the exact same versions of things, helping to avoid issues of hard-to-identify breakages based on environment inconsistencies.
zoxide
zoxide
is a tool that took me a while to get used to, but now I consider it to be nearly essential to my cli workflow. I had a coworker trying to convince me to use it for months, before I took the plunge, and now I understand why.
The top of zoxide
’s README does a pretty good job at exmplaining what it does:
zoxide is a smarter cd command, inspired by z and autojump.
It remembers which directories you use most frequently, so you can “jump” to them in just a few keystrokes.
zoxide
keeps track of directories you’ve been in before, and then will allow you to go to that directory again by just typing the first few characters of the directory name. You don’t even need to tab complete. That means, I can be anywhere in the terminal, and if I wanted to go and check something in my ~/Downloads
directory I can be as lazy as just typing z dow
and zoxide
will resolve that to ~/Downloads
automagically.
I’ve personally found that collisions are very rare, at least for how I end up navigating directories in the terminal. I also still find myself reaching for cd
most of the time, and then using zoxide
to navigate quickly when it’s needed/convenient. There was even a point on my main work system where I rebound cd
to use zoxide
becuase I like it so much. I haven’t gotten around to doing that on any other system (not because of it being undesirable, but rather I’ve just been too lazy to change to it). I find it that good that I would want to use it for almost every directory-navigating opration and would if I didn’t have using cd
as entrenched in my brain as I did.
ripgrep
ripgrep
is the current iteration of a cli file content search tool that I’ve used. In the past, I would use ag
(a.k.a The Silver Searcher
) for the same thing but found that ripgrep
performed better. ripgrep
and ag
differ from classical grep
in that they are optimized for searching in source code. This means that ripgrep
gets a number of handy things “for free:”
- It respects
.gitignore
(and a number of other.*ignore
file types) - It provides context such as the file and line number of matches
- It has a bunch of presets for files of different programming languages, allowing you to search for matches for only a single language in a polyglot codebase.
- You can output matches in a JSON format
- Also a lot more!
Editors
Everyting up until this point are nice additions to a developer’s environment, but the editor is the most important part. An editor is the tools that the developer will always use when working with code, and so understanding it well leads to outsized benefits in effectiveness. I find myself using three editors: one most of the time if I can get away with it, and the other two being situational depending on circumstances:
IntelliJ
Perhaps this may come as a surprise (or with great outrage for some), but I find IntelliJ to be my editor of choice. People will argue that it is slow/bloated/dated/expensive/whatever, but I really find myself being most productive when I’m using it. Maybe it’s because most of my early career was in the JVM world, but there’s a few things that it really stands out for me in:
- The debugging experience (especially on the JVM) feels second-to-none
- IntelliJ has really good autocomplete (again for JVM at the very least) out of the box.
- Along with the above, there is this awesome feature where a file or class or whatever can be selected by just typing out the capital letters in a camel-case string, meaning I can fill out larger sections of text with just a couple of keystrokes
- IntelliJ has a lot of really small features that Just Work (tm) and Fell Intuitive (tm), like auto-closing HTML tags, and refactoring both tags if one is renamed.
- It has a really nice pane for visualizing docker deployments, including one-click ways of spinning up compose configurations, seeing logs for individual containers, and one-click solutions for dropping into a terminal in one of those containers.
All of that said, there are a ton of features that I actually don’t use. Part of that is because they don’t fit into my use-cases, but a fair number of them are also because I find that’s it’s better to not use them. Most of these come in the form of git integrations and run configurations. As mentioned earlier on, I think it is really important to understand how things work, and this includes the build tooling one uses for development. As a result, I specifically avoid using things like run configurations in IntelliJ (at least at first), until I have a good understanding of how a project is built and run on the command line, and then will maybe move to using the run configurations if there is a benefit to it. If not, I still just drop into a ghostty terminal and run the commands to build/test/run the app from there.
As great as I find IntelliJ, it has a few weaknesses. I’ll freely admit that it is a heavy editor, and also struggles in remote development and devcontainer workloads. When I have these situations, I reach for my other alternatives:
VS Code
VS Code is probably my second-most used editor at the moment. A lot of that is because there are a number of scenarios where I am either working on a remote server, or heavily utilizing the devcontainer workflow. There’s certainly a lot to like about VS Code, and I can understand why it is as popular as it is, but to me it always kindof feels like it’s stuck in the middle; it’s not quite as feature-rich as IntelliJ, but in order to feel really productive in it in most cases you need enough plugins where it starts to feel a little to heavy to be a “true” text editor. That’s where my final editor comes in:
(neo)vim
I definitely use (neo)vim the least, but it’s also the one I wish I was good enough to use the most. It took me a long time to get into vim; I was first expored to it (in the form of vi
) in middle school, but wasn’t at a level of understanding of computers and programming to where I found it actually useful. In college most people used emacs, with those that were on top of things reaching for Sublime, Atom, or VS Code once it came out, but there was always one or two students who would try to convince their peers to use vim. Then, when I started writing code professionally, there were a few people on my team who would fly around the codebase in vim, trying to convince me and other members on the team that it was the One True Editor.
It took me a long time from that first time in middle school to get “working knowledge” in vim, and it came with a few false starts. However, once I got the basics down vimtutor, it really started to make sense. Not to the point where I had fully drank the coolaid and installed IdeaVim, but certainly enough where if I needed to edit a commit message, config file, or a quick single-file script, vim is my go-to without a question.
At the start of this year, I finally installed neovim, in part because I want to try and build out more of my vim setup, and neovim seems to be taking over as the industry standard vi* tool.
What about AI?
This could probably be a full article itself, but in short my current workflow doesn’t involve much AI. I mostly find myself using it as a different form of Google search, and it has been really helpful in the discovery and initial research phase of solving certain problems. But, I only really use it’s code generating capabilities for throwaway scripts and very small things that I would take longer to write than I would to prompt my way to.
Conclusion
This certainly was a long article, maybe long enough to where I should have made it several smaller articles. There’s a lot that I use that I didn’t add, but I think if nothing else it covers the basics of the tools I regularly am using today.
The goal of this is most certainly not to tell you that this is the right developer environment to have, but rather to show some tools that some may not know as much about, and to really emphasize that it’s important for a developer to take a moment to consider what tools they are using, and to consider if those tools are providing the right balance of giving greater understanding of how to develop software while also provding the benefits and convenience that the modern developer is afforded. Too much in one direction or the other can result in lower productivity and/or a lower understanding of our projects and the lower-level parts that make them work. The balance looks different for everyone, but it is important for all to find what that balance is to help them build what it is they want to.