Let's talk about development environment
Published on May 8, 2019 under the tag nixos, emacs, xmonad
If you are a developer, then you probably value the software stack that you use for your daily tasks. I am not talking about specific programming language that you use to develop the next gen product X in your shiny startup Y. I am talking about more basic software. The operating system, the desktop GUI environment, the code editor and a set of productivity tools that you select to make your life easier.
For me the journey to build my software stack was full of tries and errors and I am still in the middle of it waiting for new adventures.
The first big discovery for me was focusing on Emacs
as the one and only editor for me.
I was familiar with Emacs
from my lisp studies in university but then I was using
it in vanilla form without any customizations. One day I observed a power user
working in XEmacs
(at that time XEmacs
project was superior to the gnu Emacs
project).
It was amazing. Working in complete state of “flow” without constantly switching windows,
clicking buttons or even moving the mouse. It was fast and powerful and it had
everything inside (terminal, file manager, man pages). I started using XEmacs
first with the power configuration I borrowed from that guy and later
I built my own configuration which I maintain and update to this date. Since then
the gnu Emacs
project came back to life and I switched to gnu Emacs
which was now
delivering new releases in much faster iterations.
Switching to Emacs
gave me great power and full control of my coding workflow. I was
able to overcome any obstacles by programming Emacs
in lisp or by searching
for extensions online. Still my desktop environment was not perfect.
When I started programming I was using windows desktop. Since most of my work was
on a linux environment, I was running X server from cygwin on my windows desktop
and then connecting to the linux through ssh and X forwarding Emacs
to my windows
desktop. Later I completely switched to linux and started running ubuntu distribution
as my main desktop client both at home and at work.
I started to maintain repository of notes with recipes of how to install ubuntu system from scratch with all the software I use and all the desktop customization I want. Installing system from scratch required to walk step by step through my notes and configuring keyboard shortcuts, fonts, display settings, installing all the programs I use and then configuring them. At the same time ubuntu was growing and publishing new releases. The default desktop changed to unity but I didn’t like the new design. The GUI felt heavy and not responsive on my home pc (which was not the latest and greatest hardware). At first I switched to gnome classic but in later releases this option was removed and I decided to try xubuntu which was the same ubuntu distribution but with the light xfce desktop environment.
Working on xubuntu was ok. It was light and fast and I customized it exactly as I wanted.
At the same time I started to learn about functional programming and taking a special
interest in Haskell programming language. As I became more fluent in writing code in Haskell,
I started to explore the Haskell applications ecosystem. I stumbled upon Xmonad
,
which is a tilling windows manager which is very customizable and can be programmed in Haskell.
It reminded me Emacs
which is also very customizable and can be programmed in Lisp. The concept
of tiling windows manager was new for me but I have always hated the constant need to adjust and
switch between floating windows.
I installed Xmonad
and configured it as new xsession on the xubuntu system. I worked with
existing Xmonad
configurations that I’ve found on github and modified them to match my own
preferences. The result was fast and customizable desktop experience. With shortcuts and
modifications matching my work flow. Each time I wanted to change something all I needed to do
was to update my Xmonad
configuration with several lines of Haskell code.
Installing new software on my dekstop was always big issue for me. I wanted to avoid “polluting”
my distribution, but at the same time I wanted to try new software. The solution was to use
virtual machines through kvm or containers through docker. One day I read about new way to manage
software packages through software called Nix
which was very popular among haskell developers.
The idea of Nix
is to replace the global installation locations (/lib, /bin, etc.), with per
package unique locations. These locations include unique hash which computed based on the
package dependencies and it’s contents. The bottom line is that you can easily install new versions
of software (even versions that rely on different versions of the same library - no dll hell).
Additionally it allows you to easily revert back if the new package doesn’t work or even try the
new package inside isolated environment (nix-shell).
There are two ways to work with Nix
. At first I used it as additional package manager together with
the default apt/dpkg to handle ubuntu packages. But Nix
has it’s own linux distribution called
Nixos
. It uses Nix
package manager to configure the software and boot linux kernel. Everything
can be configured in descriptive way using the Nix
expression language and all the advantages
of Nix
package manager can be applied to the whole system. For example you can switch to new
kernel by changing configuration line and if the system doesn’t work as expected you can easily
revert to old version. Switching to Nixos
solved for me two problems. The first was the problem of
installing all my software including os from scratch in deterministic way. Now I have
configuration of all my software and after bootstrapping Nixos
I can just apply my configuration and
I am getting all my software configured and ready. The second problem was of installing new software
without “polluting” the distribution. Since Nix
doesn’t have global state and each package can coexist
with each other package, trying new things is easy and after I am done I can invoke nix-collect-garbage
to get rid of leftovers.
So today my development environment is based on Emacs
, Xmonad
and Nixos
. Configuration of each component
is maintained in separate github repository