Kasim Tuman recently wrote that Emacs is like a workbench. It evolves as you get better with your work – or changes as your works changes. I think that is a great metaphor of not just Emacs, but software development tools in general. So this post is about my evolving workbench. My workflow has changed a lot in the last few months to a year because of different tools I discovered and have put into practice. This came as I switched from Java to Python as my primary language. Some of these changes are Emacs-related and some are not. Yet everything kinda coalesces together into one harmonious system and suddenly things become a lot easier.
As I said above, I've been using Python almost exclusively in the past year. I haven't fired up Intellij in months and, frankly, I haven't missed it. Yes a full IDE would give me things like refactoring support but in Emacs I can open up many files and look (and switch to them) with ease – something that Intellij never did for me. It's effort in the JetBrain's world – in Emacs, I do it with muscle memory and routinely am looking at 4 files at once. One time a co-worker was working with me on something and I quickly deleted some files with Dired and he stopped talking. I asked him if I messed something up and he said, "No I just saw you manipulate files while inside Emacs and I'm still recovering from that."
Anyway my independence from Intellij has freed me up to explore other tools to help me with my software development work and I like what I have built up.
Just as a development tool, things get a lot easier with Docker. Setup a
docker-compose.yml file for a database and another other extra services for my projects and suddenly I have a solid local development environment where I don't have to sweat if it will work on a server. You can setup multiple services in one Docker file (I had PostgreSQL and RabbitMQ in one file, for example). It's really as easy as a google search for "docker <service you want>", click one of the first links, and put their snippet into a
docker-compose.yml file, and then run
docker-compose up -d.
Tmux has been in a my tool bench for a long time, but I have started using it with a renewed fervor. Mostly because I have 2-3 projects (if not more) going on at once. It's hard switching CLI's back to that and having a config for it. direnv helps a lot, but doesn't give everything. I found tmux-ressurect, which saves the state of my Tmux prompts. So now when I need to switch a project, I just go to my Tmux-powered prompt and switch. Forced to reboot? I just start Tmux and run my tmux-ressurect command (
Ctrl-\ Ctrl-r) and I have everything back from before the reboot.
I will say that I've been using the zsh less and less lately, mostly because Projectile has been taking most of my shell usage away from me. I have been using eshell a lot lately and that is good enough for simple things. The Emacs terminals like
ansi-term just fail on REPLs, etc. I played a bit with the vterm module and it shows promise but has a ways to go for my usual workflow. I like that tmux is always there and switches contexts with few problems. It's hard giving up years and years of aliases that you are used to. See my tmux config to see how I set things up.
If Emacs is my IDE, then direnv runs my config file that the IDE reads. So as the
.idea folder is for Intellij IDEA, so is my
.envrc for my Emacs/shell setup.
I use direnv for project-specific environment variables (like
AWS_PROFILE and even custom
PATH). But you can do more than that: I talked about this on my employers blog but I use it to manage my Python environments as well. It took me a bit to find it, but emacs-direnv makes Emacs read it and follow it. Then Emacs knows all about which Python environment I'm using. That makes a lot of things easier. All I have to do is open the project in Emacs and poof it's pointing at the proper Python environment. My only real complaint about direnv is that it doesn't have a parent structure – that I can't declare environment variables on the top level (like AWS account info) and have that go into the direnv-enabled folders below. Recently I started doing
source /path/to/some/common/file and that works – you need to use the fully-qualified name to make sure it works. Not quite as nice as just using a parent folder, but it works really well.
Yes, Emacs needs it's own list of things. This part of my workbench is always evolving but I got into a group of tools that have been fairly consistent lately. You can see my Emacs shortcuts here, which give you an idea of what kinds of things that I use.
I've had Projectile in my Emacs config for a long file, but haven't used it until the last eight months of so. It has now become the general way I interface with files and buffers in Emacs. Everything is a project (which is easy – it just has to have a
.git folder in it). Then I can find files in the project, switch buffers in the project, search files in the project, and compile (or run) the project from any buffer opened in the project. This integrates with ease with direnv and Helm. So, I can find a file in the project via Helm and the search project results buffer is also in Helm.
Let's also not forget that Projectile comes bundled with Prelude, which is a really nice little Emacs starter. My favorite part is that you can put your own Emacs configs under
~/.emacs.d/personal.d where you put your own configs… not having my mess with the main Prelude/Projectile part is nice.
My newest Emacs addition and, honestly, I'm not sure how I got by without it. I tried to use it before but I didn't get the hang of it. As I mentioned above, Projectile can use it and that got me going with it again. Now I flip through buffers and filenames with ease. So easy to switch to another file. And the interfacing it with
M-x to find functions is great I find useful functions I didn't know existed – like
pytest-all, which now I use all the time.
When I first started using Magit, I found it confusing and didn't know what the hype was about. I stuck with it, and figured out how it was structured and the way that it wanted me to work. I found that it's way of dealing with git was smarter than my way. It has now became my preferred way to deal with Git – not just committing, pushing and fetching, but also looking at logs and branching and everything else. I never would have believed I would have given up the command line with git, but yet I have.
I'm enjoying this freedom from in my current set of tools. I find it much quicker to get a lot of things done, switch projects, etc. Some of these things have been kind of "set it and forget it", which is nice until you need to setup it again.
A big question – how will this work when I go back to Java development? Not real sure that this setup is good for 100% Java… but I could see myself using both this sort of setup with Intellij… use the strength of both. Of course, maybe I will find a different list of things to be using a different list of tools from this list by then.