My 2023 dotfiles setup
Update: April 2023
Some of this is no longer valid as of April; my 'work dotfiles' are now private, and I use them at home too
I reformatted my Windows 11 partition to Pop!_OS to focus more on coding, and as such can share my work and personal dotfiles more (same OS)
Realizing that "keeping the world updated" on little tweaks to my internal systems makes little sense and generates noise; from now on I'll revert to my original rule of thumb, which is that it's mainly my finished code projects that make sense to be public repos
My focus since my last post has been work-life balance; less coding during my free time. It helps that my day job is open-source and displayed on my GitHub profile (I like my work to be visible).
I wanted to develop a coherent mental model for dotfiles, to reflect on some of these ideas:
- Keep work and home dotfiles separate
- Don't break your home dotfiles, but break your work dotfiles
- Learn new things on work time
- Learn new things by scratching your own itches
- Learn new things to scratch your own itches
- Track learning goals on work dotfiles
- Break up stagnation by switching between learning and doing phases
- Selectively sync work and home dotfiles
1. Keep work and home dotfiles separate
I want my work dotfiles to be public; this is my toolbox, an overview of the methods I use to accomplish my goals, and a reference for me to hit the ground running with my professional toolbox and skillset in the future at any company I work at.
I want my personal dotfiles to stay personal and private; I don't want people to know what I do in the comfort of my own home. It's in fact nobody's business,* while my public work-facing toolbox is the basis of my career.
*: this statement might seem at odds with all the personal code I've published from the comfort of my own home; but I think the mental model still holds, that you don't really know how I wrote those things, just that I wrote them
I've tried some variations of running my own homelab Git host for my personal dotfiles (private Gitea, which is easy to run), but I went to the extreme of isolation and have stored it on a local filesystem only, because I only have one personal workstation right now (from another work-life-balance idea of mine which is "no more laptops").
To support my dual boot setup (Linux + Windows 11 with WSL2 Linux), I have a shared NTFS drive. This is where I store my local dotfiles:
# in WSL (where I wrote this post) $ git -C ~/dotfiles/ remote get-url origin /mnt/d/dotfiles.git
Of course, I also back it up to divers locations to avoid catastrophes. This local-only setup has several benefits:
- My personal dotfiles activity is not reflected to my GitHub contribution graph
- I can store all kinds of private and personal files; GPG keys, SSH keys, financial documents, personal planner and organizer
- An abrupt context-switch between work and home, so that the separation is more severe (better for your health!)
2. Don't break your home dotfiles, but break your work dotfiles
I don't do zero coding at home; I have a few scripts and tools here and there, and I'm not opposed to improving those to improve my life. The core of my home dotfiles (from around 2017) is terse and minimal:
- Bash (just a few PATH settings, no aliases)
- Vim with just a handful of settings for Rust, Python, Yaml, Go, and TeX - no plugins
- Git configs (your usual e-mail, name, GPG key, etc.)
- Tmux config with some custom keyboard split-pane bindings
It's robust because I rarely fuck with it and uses almost no third-party dependencies; because a broken and unstable dev environment is the worst.
Things breaking on work time is totally fine: "oh, I got my Python environment fucked up by mixing up pyenv and conda and because Ubuntu's
apt install python3-venv doesn't work properly and pip is broken because
ensurepip is missing." This sounds like a nightmare, but it can easily be reality, and remember: it's not your fault. You didn't create the fragmentation in the Python ecosystem, you didn't split up the mandate of different semi-official Python organizations such that none can agree on a single tool (pypa, pypi, pypy, pipi, poopoo). In fact, the only reason you're messing with your Python dev environment in the first place is because work needs you to. So, at work, break whatever you want; that's your job!
At home, keep things sane, sanitary, and stable.
3. Learn new things on work time
As professional engineers, we should be learning our craft on work time. You're not only paid to produce, but to evolve your methods of production; debugging, investigating, linting, testing, environment setup, all knowledge is valuable.
It doesn't mean "deploy your first Rust hello-world project straight to production," but you can always find a way to explore new languages or tools in a private exploration phase or small task.
If you have a boss or lead that will push back, it's because this sort of thing is better left omitted. Sure, if you have a conscientious boss and team who are humane, you can say "today I'm going to work on our S3 bucket cleanup task, but first I'm going to spend a few hours installing and learning Golang and mess with the S3 API a bit," they'll say "good luck" or give you a tip or two. If you're in a toxic work environment, nobody will "OK" your decision to learn Go; do it anyway.
An unspoken part of project estimation is to include as much margins you need for your own personal development, because otherwise nobody will do that for you (unless you really have a good manager that's planning your learning; which I've been lucky to have in some of my junior years).
4. Learn new things by scratching your own itches
This is not a new idea; I hear it mostly when people describe their really popular open-source projects: "I didn't aim for it to become huge, I just solved my own problem and other people liked it."
An organic real-world application that is useful to you is the perfect introduction to a new tool. The shallowest learning is from exercism.io or some other in-vogue project idea (wordle solver, IRC bouncer, shell, OS, ray tracer, blah blah) - or, God forbid, some made-up problem like how to get Santa's Elves to efficiently load Santa's sleigh if there are 5 gift-wrapping elves who can only wrap a gift left-handed.
If you don't believe in the problem you're solving, you will get nothing out the process. Solve your personal itches first.
5. Learn new things to scratch your own itches
Subtly different from the previous point, don't learn things that don't help you. Cargo-culting tools for the sake of an aesthetic take you far from your goal as an engineer: to translate your personal touch of problem solving and personality to solving a specific need for an organization.
You do this by using tools that let you express yourself. Don't use popular tools like Zettelkasten or Emacs or Obsidian just because some online communities love to talk about them. Ask yourself what inefficiency or problem you have now, and what tool can solve it. Maybe note down what tools the zeitgeist finds interesting, but approach with caution.
If you're happy with grep, don't install ripgrep (I love ripgrep though). For example, one day I got tired of writing
grep -Iirnw /dir/ -e pat and that's when I switched to ripgrep.
On a related note, avoid "oh-my-awesome-wtf-bbq" 10-billion-stars-on-github things. In the past, I've gone overboard (Spacemacs, Doom Emacs, Oh-My-Zsh) and generally end up regretting it; adding complexity to my personal dev tool kit, which is intended to solve complexity, merely makes my problems worse. It fits in this point; if oh-my-zsh or Spacemacs don't solve an immediate itch of yours (and I don't see how anything with 10,000 LoC can solve an itch rather than cause 10,000 new itches), don't install them.
6. Track learning goals on work dotfiles
Speaking of noting down tools that are popular in the zeitgeist, I like to include the tools I want to learn or recently learned to the README of my work dotfiles repo.
It's good to write down things that come onto my radar, and generally once I have it written down, there's a post-filtering step that lets me figure out if I really needed it, or I just got overexcited after reading one enthusiastic comment online, but there was no real substance to the desire.
For example, I had Julia on my to-learn languages list. I'm sure it's a language with great merits, but on reflection, there was nothing Julia would do for me except to tick a checkbox that says "faffed around with Julia for 2 hours on a random Thursday." That's not to say it's not worth learning; just that my reasons for writing it down on my list weren't very good.
On the other hand, I had Nim on my to-learn languages, because I liked that it has a similar high-level syntax to Python that could compile into native binaries (to avoid Python packaging woes). I'm glad I followed through with writing a low/medium-complexity program with Nim, because I now have 3 languages with modern tooling and package managers to choose from for compiling native binaries; Rust, Go, and Nim. It doesn't mean I'm a Nimgod or anything (nor am I a Rustacean or Gopher); just that I have the beginnings of a legitimately useful new tool in my toolbox.
I also try to learn at most one new thing at a time; one cli tool and one programming language. Right now, I'm trying to replace my terminal usage of
fd. This also actually forces me to learn and move on; if I installed all of the new tools at once (
fd), it's probably a recipe for not doing justice to any of them.
7. Break up stagnation by switching between learning and doing phases
Sometimes, the project has enough juice to keep me fully occupied; for example, writing my deep learning model xumx-sliCQ and associated thesis for grad school were complete beasts of work that I accomplished with the bare minimum of tools; essentially just using Python tools (conda, venv) and LaTeX tools (latexmk, texlive-full) as they were intended without much personalizations, and 2 lines in my .vimrc:
autocmd FileType python,markdown setlocal ts=4 sts=4 sw=4 expandtab autocmd FileType tex,latex,markdown setlocal spelllang=en_us spell
These were amazing projects and I'm happy to have worked on them. Focusing on the meta-tooling would have been the wrong approach. However, it's not as if my personal dev flow was perfect at the time, and I had a lot of inefficiencies I dealt with.
I find that I do need to run up against a problem multiple times before it's worth it to scratch the itch; I want to get right up close to the itch, figure out what the problem is. I have the same mindset for anything; encounter the problem many times to get familiar, then work on solutions. For me, the question of "how do I avoid venv hell?" without experiencing venv hell is pointless. It's like asking how you can avoid segfaults before ever causing one. Not to say it's a good thing to get fucked by mistakes, but that pre-emptively solving for mistakes or inefficiencies you aren't even suffering from or familiar with yet is a big waste of your time.
Now I have a new plan for xumx-sliCQ-V2 that's going to be awesome, because of the many issues of xumx-sliCQ that I have learned to deal with better during the learning phase after the original doing phase.
8. Selectively sync work and home dotfiles
I mention above that I want to work on a new variant of my (personal project) deep learning model xumx-sliCQ. I do want to incorporate new strategies that I've been using at work, as part of my new work dotfiles:
- Mamba envs for clean isolated Python versions, orthogonal to per-project poetry or venv or pip requirements.txt or pipenv files
- Dockerfiles with the nvidia-docker2 runtime for even better reproduceability
It will be a manual process of copying what I need to incorporate mamba (newly added for managing my Python dev env at work) into my personal dotfiles; however, the very act of manually sitting down and eyeballing and copy-pasting configs line-by-line contributes to the conscious separation of work and life that I'm enforcing.
I learned something new at work, it proved itself during the "alpha and beta tests," and now I'm ready to incorporate it into my stable home dotfiles.