GeistHaus
log in · sign up

Gabriel Volpe

Part of gvolpe.com

Recent content on Gabriel Volpe

stories primary
Immich Photos on S3 object storage

As someone who loves going for adventures abroad, the memories I’ve captured behind the lens have become extremely valuable to me. I’ve learned to appreciate that I can still cherish those memories many years later, regardless of whether the source was a DSLR, a smartphone, or a GoPro. The feelings these precious memories rekindle are priceless; as a tech person, it’s only reasonable to seek out a ‘safe haven’ for them.

https://gvolpe.com/blog/immich-photos/
The perfect tiling window manager

XMonad has been my main driver for years, and I still think it’s the best X11 window manager ever. However, the X11 windowing system is quite dated, having originated about 40 years ago. Its number of limitations, among other things, has led to the creation of the Wayland protocol.

This is a modern protocol that allows compositors to operate in a more efficient and lightweight manner. Since its inception in 2008, it has gained popularity to the point where prominent display managers such as GNOME and KDE have adopted it — Mutter and KWin, respectively.

https://gvolpe.com/blog/niri/
Unison: Forex API & Caching

I have been following the Unison programming language for as long as I can remember, given that its authors are very well-known in the Scala ecosystem. Though, it took me a good few years to finally learn it by immersing myself into their amazing documentation and tutorials.

TL;DR: I love it more and more every single day!

The language itself is easy to learn for anyone coming from a functional programming background. Even their implementation of algebraic effects — called abilities — are quite straightforward. What sets the language apart from others is their interactive approach to writing code.

https://gvolpe.com/blog/unison-forex/
Home Manager: dotfiles management
What is Home Manager?

Quoting the official description from their website:

.quote::before { content: var(--quote-emoji); } Home Manager

"This project provides a basic system for managing a user environment using the Nix package manager together with the Nix libraries found in Nixpkgs. It allows declarative configuration of user specific (non-global) packages and dotfiles."

Wait a minute! If you had been following my blog for a while, you know a lot has been written about Home Manager already, so why am I going back to basics? Mainly because I noticed plenty of confusion out in the wild, thus I would like to demystify some of the misconceptions that exist, and provide you with ideas and examples so that you can reap the benefits of this magnificent tool.

https://gvolpe.com/blog/home-manager-dotfiles-management/
NixOS server up in minutes!
Introduction

The folks at Garnix have done it again! You can now deploy a NixOS server in minutes, just by defining your system on a flake.nix and git push‘ing your changes (Garnix needs to be enabled for the repo).

In their latest blog post Hands-on NixOS servers, they explain all the necessary steps to deploy your own server, so I won’t repeat things over. Furthermore, there’s official documentation.

Instead, I will explain how I used this opportunity to set up a web analytics server for this blog.

https://gvolpe.com/blog/nixos-server/
Flake Schemas

Flake schemas were introduced by Determinate Systems (written by Eelco Dolstra — creator of Nix) about half a year ago now (August 2023), which is quite a promising feature, but what is the current status? Is it usable yet?

The PR that introduces flake schemas was submitted to NixOS/nix the same day the announcement was made, and it sadly remains in DRAFT mode until today. However, if you look at the comments, some expert users reported using this feature successfully, so I thought it was about time to give it a shot myself.

https://gvolpe.com/blog/flake-schemas/
Private Nix flake 🔒
Introduction

I blogged about Garnix before, and it’s the solution I’ve been using ever since for continuous integration. However, one thing I was missing was that private flakes were unsupported, so I had to live with a private local flake that I was commenting out on my public flake for a long time.

Github Actions does support building private flakes by providing an access token, but it’s not very secure if your builds end up on a public cache anyway (not my case, though)… Garnix recently added support for private inputs, but it comes with some limitations (mainly due to security), so I could not take advantage of this new feature.

https://gvolpe.com/blog/private-flake/
Nix remote builds

Remote builds enable interesting use cases and experiments. Besides building for different architectures, another use case that comes to mind would be having a low-resource machine building a derivation that would require heavy CPU usage (e.g. a Rust application) on the fly, without having to rely on CI builds or binary caches, effectively used as a development environment.

Here’s what the NixOS official documentation has to say on the topic:

.quote::before { content: var(--quote-emoji); } Remote Builds

"Nix supports remote builds, where a local Nix installation can forward Nix builds to other machines. This allows multiple builds to be performed in parallel and allows Nix to perform multi-platform builds in a semi-transparent way. For instance, if you perform a build for a 86_64-darwin on an i686-linux machine, Nix can automatically forward the build to a x86_64-darwin machine, if available."

https://gvolpe.com/blog/nix-remote-builds/
Garnix CI

Garnix is a continuous integration (CI) service for Nix flakes that has been in Beta for a while.

.quote::before { content: var(--quote-emoji); } In their own words

"With Nix-specific optimizations, Garnix makes CI with Nix fast — a few seconds for no-op changes. Easy to setup, too — if you have a flake.nix, you are ready to go. And we provide the build results as a cache, so you don't have to build things locally. To top it all up, we run on 100% renewable energy. Because CI should bring you peace of mind." Notice the extensions we had to enable to make this compile.

https://gvolpe.com/blog/garnix/
Neovim meets Nix flakes

It is no secret that Neovim is my favorite text editor. I use it on a daily basis for multiple purposes:

  • To write Scala code (and the occasional Typescript) for $work.
  • To write the extensive text and code for my books.
  • To fine-tune my ever-changing NixOS configuration.
  • To write blog posts such as this one.
  • For the casual Haskell and Rust code I sometimes need to write.
  • Literally for any other text file I need to explore and modify.

All this functionality is enabled by many plugins configured and tailored to my needs. Now there exist a bunch of plugin managers to handle the installation of plugins, from the classic vim-plug to the more esoteric lazy.nvim.

https://gvolpe.com/blog/neovim-meets-nix-flakes/
Scala 3: the missing compiler plugin

If you have read this post when it first came out and felt offended by its catchy title, let me apologize for it. It caused some controversy, so I decided to change the title completely to highlight more what this post was about in the first place. Hope this time folks read to the end before drawing any conclusion :)


Scala 3 has been around for a while now, but not many people are using it in production just yet. There’s a lot of skepticism in the community when starting out a new project.

https://gvolpe.com/blog/scala3-missing-compiler-plugin/
Scala 3: Error handling in FP land
Introduction

Scala 3 introduces union types. Straight from the official documentation, a union type A | B has as values all values of type A and also all values of type B.

So the following code snippet compiles performing an exhaustive pattern-matching.

def foo(x: Int | Long): Unit =
 x match
 case _: Int => println("Int!!!")
 case _: Long => println("Long!!!")

However, you are not here for boring examples, are you? :)

Error types

Union types are the perfect feature to model error types. In Scala 2, we could represent the presence of errors via the Either monad. E.g.

https://gvolpe.com/blog/error-handling-scala3/
Flakes: NixOS and Home Manager migration

I have recently migrated my entire NixOS and Home Manager (HM) configuration — including programs, services, dotfiles, etc — over to the new kid on the block: Nix flakes.

It was not as difficult as I thought it would be but there were a lot of things I had to figure out on my own or by asking more experienced folks on the NixOS matrix channel.

So let me tell you the important bits of this migration story in this short blog post ;)

https://gvolpe.com/blog/nix-flakes/
NixOS: build your system on Github actions!

What if I told you that you can save plenty of time and CPU-power by pre-building your entire NixOS configuration on Github actions? Fresh installations could be super fast and pre-validated on a CI build!

Well, it’s possible, and it’s what I’m currently doing with my NixOS and Home Manager configurations.

badges

Besides hosting your configuration on Github, you’ll need a binary cache where the results of your build can be pushed to be re-used later on. One of the best free alternatives is Cachix, offering up to 10GB on their basic tier.

https://gvolpe.com/blog/nixos-binary-cache-ci/
Finite-State Machines + FS2 streams: A match made in heaven

As the title says, finite-state machines and Fs2 streams are a match made in heaven! To demonstrate it, I’ll make up a compelling problem to solve and we will get to the final solution step by step. Here’s a sneak-peek of the solution.

trait Ticker[F[_]] {
 def get: F[Tick]
 def merge(timerTick: Tick, count: Count): F[(Tick, Count)]
 def ticks: Stream[F, Tick]
}

case class Engine[F[_]: Concurrent: Parallel: Time: Timer](
 publish: Summary => F[Unit],
 ticker: Ticker[F]
) {
 private val fsm = Engine.fsm[F](ticker)

 def run: Pipe[F, Event, Unit] =
 _.noneTerminate
 .zip(ticker.ticks)
 .evalMapAccumulate(Map.empty[PlayerId, Agg] -> 0)(fsm.run)
 .collect { case (_, (out, Tick.On)) => out }
 .evalMap { m =>
 F.timestamp.flatMap { ts =>
 m.toList.parTraverse_ {
 case (pid, agg) => publish(agg.summary(pid, ts))
 }
 }
 }
}

Interested in seeing more? Continue reading or browse the source code on your own :)

https://gvolpe.com/blog/fsm-fs2-a-match-made-in-heaven/
XMonad + Polybar on NixOS

I’ve been a Gnome user for a long time and I have never cared about using a Window Manager ever before but I recently switched to using XMonad full-time. Why? For a couple of reasons.

One of the reasons is that I’ve been wanting to try a lightweight window manager for a while. However, the main reason is that Gnome leaks memory, unfortunately, and it seems to be an issue that’s been around forever. Although it has been announced as allegedly solved, I have been experiencing a similar issue in Gnome 3.36 on NixOS.

https://gvolpe.com/blog/xmonad-polybar-nixos/
Nix at Chatroulette @ Nixcon 2020 - Online 🌎

Showcasing the ways we leverage Nix at work: dev shells, CI/CD, software packaging, etc. Furthermore, showing examples of our OSS contributions.

https://gvolpe.com/talks/nixcon-2020/
Gnome 3 on NixOS

NixOS can be configured to run any desktop environment you want and Gnome 3 is not an exception. However, it comes with some caveats so keep reading if you are interested in making this duo work seamlessly.

Users who enjoy a graphical environment normally like to tweak it with their own preferences as well. E.g. installing new extensions, changing the background image, changing the dock, etc. These are some of the tasks that Gnome Tweaks makes possible in Gnome 3.

https://gvolpe.com/blog/gnome3-on-nixos/
Github actions powered by Nix Shell & Cachix

The more I learn about Nix — a purely functional package manager — the more I am convinced this is the way forward. Even if there’s still room for big improvements.

Today I’d like to share with y’all what I’ve been up-to lately. Though, you could imagine I’ve been Nixifying more than one project ;)

Nix shell

Nix shell is a great tool to create reproducible development environments. For example, we could create a shell where the redis package is available, without installing it in our system.

https://gvolpe.com/blog/github-actions-nix-cachix-dhall/
Parallel typeclass for Haskell

As I’m preparing a talk about refinement types I will be giving this Thursday at the Functional Tricity Meetup, and I’ve recently given a similar talk using the Scala language as well, I realized there is a missing typeclass in Haskell.

In the following sections, I will be providing examples and use cases for this typeclass to showcase why it would be great to have it in Haskell. Oh, yes… I love refinement types as well!

https://gvolpe.com/blog/parallel-typeclass-for-haskell/
Setting up Ghcide in Ubuntu with Nixpkgs

If you use Ubuntu or any other Linux distribution (AKA distro) together with Nixpkgs, you might have noticed things don’t play so well together. Nixpkgs has been mainly designed to work seamlessly in Nix OS; other distros are second class citizens.

Quoting the Ghcide repository, it is defined as:

.quote::before { content: var(--quote-emoji); } Quote

"A library for building Haskell IDE tooling"

It is not defined as an IDE, because it only has a subset of the features HIE (Haskell IDE Engine) has. However, the good news is that the HIE and Ghcide teams are joining forces to create One Haskell IDE to rule them all!

https://gvolpe.com/blog/setting-up-ghcide-nixpkgs-ubuntu/
The art of interviewing engineers

These past few weeks I’ve been interviewing with a few companies, as I’m actively on the lookout for a new challenge, and the number of flaws I have encountered in some hiring processes has disturbed me.

Interviewing is hard; interviewing Software Engineers is a work of art.

interview

Let’s be honest. Software Engineers, especially in the functional programming space, are a scarce resource. So the better the interview process, the bigger the chances you have of hiring great engineers.

https://gvolpe.com/blog/the-art-of-interviewing-engineers/
Functional Dependencies & Type Families

In the past few months I have learnt a lot! Probably the coolest stuff has been about Functional Dependencies and Type Families, so this is my attempt to explain it in order to gain a better understanding and hopefully help someone else out there as well.

So please be kind if you see any mistake, let me know and I’ll try to fix it 🙂

A motivating example

One of the fun applications I’ve worked on is exchange-rates, which uses the RIO Monad (basically ReaderT + IO).

https://gvolpe.com/blog/functional-dependencies-and-type-families/
Lessons learned while writing a Haskell application

Having introduced Haskell at my last job I wanted to put into practice all the stuff I learned: take the good, leave the bad. So I started working on an exchange rates API using a few libraries I haven’t used before, exclusively for fun and learning purposes.

In this blog post I’ll try to share what I have identified as good practice so far and what are my personal recommendations when writing a Haskell application.

https://gvolpe.com/blog/lessons-learned-while-writing-a-haskell-app/
Context bound vs Implicit evidence: Performance

In a recent pull request review at work I suggested using context bound to declare effect capabilities instead of implicit values as this is what I see the most in OSS projects and it has also been my preference for a while. It makes the code look nicer even though the latter approach is equivalent. Context bound constraints get translated into implicits values at compile time.

Context bound
def p1[F[_]: Applicative: Console]: F[Unit] =
 Console[F].putStrLn("a") *>
 Console[F].putStrLn("b") *>
 Console[F].putStrLn("c")
Implicit values
def p2[F[_]](implicit ev: Applicative[F], c: Console[F]): F[Unit] =
 c.putStrLn("a") *>
 c.putStrLn("b") *>
 c.putStrLn("c")

Every time we call Console[F] what we are doing is invoking the “summoner” method normally defined as follows:

https://gvolpe.com/blog/context-bound-vs-implicit-evidence/
Cats Effect: Tagless Final & Beyond! @ Scala eXchange 2018 - London, UK 🇬🇧

Since the first introduction of Cats Effect, many things have changed and this has taken its design and performance to a whole new level, making complex problems seemingly trivial in production systems.

thumbnail

Join Gabriel to learn how to deal with side effects in a pure functional way while abstracting over the effect type to take composition to the next level. Starting with a review of the basic concepts, you will explore the most important features, such as synchronous and asynchronous computations, error handling, safe resource management, concurrency, parallelism and cancellation.

https://gvolpe.com/talks/scala-exchange-2018/