I am Christian Johansen. I make my living as a software developer. My hobbies include playing, recording and mixing music, baking, brewing, cooking, and board games. I write about software development, often with Clojure.

Blog posts

On keys and their usage

In Clojure, you can namespace your keys — a seemingly trivial detail with major implications. Let’s explore how this helps with data modeling.

An umlaut too far

Unicode is everywhere. But in some places, it’s still safest to use the good old ASCII character set, and in this post we’ll look at Unicode normalization as a way to get there.

A week with Tailwind CSS

Close to a decade after everyone else, I finally tried my hand at Tailwind CSS. I found some good ideas, some bad ones, and a surprise or two.

Continuously Indignant

Do pull requests conflict with continuous integration? Is continuous integration the same as CI? What about CI/CD? I try to clarify some confusion from my previous post about pull requests.

All PR is good PR?

Pull requests are ubiquitous, even among in-house product teams. They’re so common as to be practically synonymous with using git. Is that a good thing? Should every change come through a pull request? I’m not so sure.

Some letters are more equal than others

In the previous post, we looked at how full-text search works, treating all symbols in the index as equally important. But that’s not always how it works in practice — for instance, matches on whole words are usually better than matches on word fragments. This can be solved with weighting, which is today’s topic.

Fulltext search from scratch

Imagine, all of Shakespeare’s collected works hidden in a box of alphabet biscuits. That’s roughly the approach we’ll take as we build a tiny search engine in JavaScript to understand how full-text search works.

How I learned to stop worrying and love the API

As a follow-up to my post on backward compatibility, I’m sharing some practical tips today on how to design HTTP APIs that provide a great user experience over time.

Stop Breaking My Stuff

The IT industry seems to love redoing old things. In our endless chase for the perfect API, we throw out things that work just fine, just to serve up something that looks different on the surface but does basically the same thing underneath. It’s more trouble than it’s worth.

Stateless, data-driven UIs

A practical example of how to write stateless, data-driven UIs

First-Class Analytics

Web analytics for 100% of users without dreadful consent dialogs is possible — here’s how.

Simpler and Better Modals

All modern browsers now include a built-in building block that helps us create accessible modals with less code. If you, like me, had no idea this existed, then this post is for you.

Walking is good for you

There’s a lot to enjoy in Clojure: pure functions, immutability, and the REPL, to name some of the big things. Today, let’s instead look at two tiny but very useful functions.

What's the domain of the frontend?

A prerequisite for hitting the mark with software design is having good control over the domain you operate in. But what exactly is the domain of your frontend code?

What Exactly Is a REPL?

The REPL breathes life into your program and lets you develop it from inside the running process. Join me as I try to explain exactly why a REPL is the essential tool you might not know you’re missing in your (work) life.

Zero downtime Kubernetes deployments

When you deploy your app to that spaceship of a rig called Kubernetes, it happens without any form of downtime, right? Bad news: unless you have actively worked for it, your services most likely have some downtime during deployment. But why?

Continuous Delivery on the Frontend

You have a Single Page Application (SPA). Users typically keep the app open in their browser for a long time - many days, or even weeks. At the same time, you’re pushing out new versions several times a day. How on earth do you ensure that people don’t end up stuck on an old frontend that may have bugs you’ve already fixed, or are using an outdated API client? Well, here’s one suggestion.

Achieve more by doing less

A short story about how a new feature in an open source library was scaled down and yet became more useful.

Partitioning data

Functions like map, filter, and reduce are useful tools that many developers keep in their toolbox. partition may not be as commonly known, but in this post I’ll show you why it should be.

Proper URLs for your SPA on S3 behind Cloudfront

In this post I’ll show you how to use Lambda@Edge to give JavaScript frontends (“Single Page Applications”) on AWS S3 behind Cloudfront proper URLs even when all you have is a single HTML file and some JavaScript.

Editing for cleaner merges

As we add new code to existing files, it feels natural to append – add new functions at the end of the file, new requires at the end of the list of requires, and so on. This approach introduces some friction, and in this post I’ll share some pointers for improved editing and git workflow.

Devops! Dev? Ops!

There is currently no shortage of companies in the IT world boasting about doing Devops. But are they really? If the solution is a “devops team” or job ads for “a devopser,” unfortunately the chances of getting the best that devops has to offer are slim.

JavaScript Coercion 101

Developers love pointing out the madness in JavaScript, like [] + 2 === "2", but if your job is to write code in this language, or languages that compile to JavaScript without hiding this behavior (for example TypeScript and ClojureScript), you will save a lot of time debugging and coding by understanding why things are the way they are.

When the AWS Bill Skyrockets

It’s easy to get up and running in the cloud. Unfortunately, it’s also much too easy to end up in a situation where you’re practically throwing money in Amazon’s direction. What do you do when you discover that the AWS bill is much higher than you expected?

AWS Free Tier

This is a short story about how EFS almost killed our Kubernetes cluster, and how you can avoid ending up in the same pickle — even if you don’t use EFS.

CSS Grid

CSS grids have finally given us a simple and flexible model for web layout. With just a few properties, you can pretty much retire float, gain full control over source order, and get a powerful tool for responsive design in the bargain.

Clojure in Production with tools.deps

A lean and fast setup for packaging Clojure applications for production using tools.deps

tools.deps, figwheel-main, Devcards, and Emacs

A primer on setting up a ClojureScript project with tools.deps, figwheel.main, devcards, and optionally Emacs.

A Unified Specification

An approach to describing the structure of data in ClojureScript applications in one place, and using it to power Datascript schemas, specs, and coercions for data from external sources.

Git Subtree for Multiple Directories

How to split Git repos.

Processing data with Clojure and Go

Porting some recent Go code to Clojure, and musing a little about the difference between these two languages when it comes to data processing (performance, typing, etc).

A Better Playlist Shuffle with Go

Shuffling music playlists with less random and more cleverness, using Go.

Webslides Syntax Highlighting with Prism

Adding Prism.js syntax highlighting to webslides.

Optimized Optimus Asset Paths from ClojureScript

How to write a Clojure macro that exposes Optimus’ optimized paths to the client-side ClojureScript build.

Securing HAProxy sites with Let's Encrypt TLS Certificates

A step by step howto on setting up Let’s Encrypt TLS certificates with HAProxy.

Setting up an Api Gateway Proxy Resource using Cloudformation

How to configure an AWS Api Gateway catch-all endpoint to proxy to another HTTP service with Cloudformation.

Idempotent Cloudformation Updates

A guide to making Cloudformation updates idempotent.

Querying across Datomic databases

Among its many, many unique and interesting features, Datomic supports datalog queries across multiple databases. I recently had a chance to actually use this feature, and thought I’d share an actual example of it.

Annotating Datomic transactions

Datomic creates a transaction entity every time you transact data. These entities can be freely extended for a multitude of use cases.

Referentially transparent CRUD

Managing side-effects functionally with Datomic’s transaction data.

Clojure to die for

A selection of the details that makes Clojure such an enjoyable language to work with.

Building static sites in Clojure with Stasis

An in-depth code-along guide to building static web sites powered by the Stasis library.

An introduction to Emacs Lisp

A long, thorough introduction to programming in Lisp in general, and Emacs Lisp in particular