Chat is the least interesting interface to LLMs Large language models are an amazing tool for working with prose inputs and outputs (with chat interfaces being the prototypical example). In fact, they are so good at working with prose that advocates often forget that prose is actually a pretty crappy user interface on almost every other dimension: users tend to prefer structured inputs (e.g.…
Prompting 101: Show, don’t tell A really common mistake I see people make when writing prompts is starting the prompt with something like: You are a Staff+ Software Architect with 40 years of experience designing distributed systems at Google, Meta, and NASA. Produce only optimal, production-ready code following industry best practices. This is an example of a prompt that tells the large language…
Nix Steering Committee vote of no confidence Earlier this week I proposed a vote of no confidence for the Nix Steering Committee , which would have ended the terms of all currently serving members and put all seven positions up for election in November. That vote failed with 3 out of 6 votes (4 were necessary) and I’m writing up a post-mortem on why I proposed and voted in favor of the vote of no…
Steering Committee Retrospective I am voluntarily ending my Nix Steering Committee term early (I am only serving out a one-year term instead of two) and I wanted to document the reasons for my early exit. The short version is: I believe the Nix Steering Committee is in need of reform in order to be effective and in its present state it does not set up the Nix community for success nor does it set…
Type inference for plain data using Monoids The context behind this post is that my partner asked me how to implement type inference for plain data structures (e.g. JSON or YAML) which was awfully convenient because this is something I’ve done a couple of times already and there is a pretty elegant trick for this I wanted to share. Now, normally type inference and unification are a bit tricky to…
Prompt chaining reimagined with type inference At work I’ve been researching how to improve the ergonomics of prompt engineering and I wanted to share and open source some of what I’ve done. This initial post is about how I’ve been experimenting with using bidirectional type inference to streamline prompt chaining . “Prompt chaining” is a prompt engineering technique that splits a larger…
The Haskell inlining and specialization FAQ This is a post is an FAQ answering the most common questions people ask me related to inlining and specialization. I’ve also structured it as a blog post that you can read from top to bottom. What is inlining? “Inlining” means a compiler substituting a function call or a variable with its definition when compiling code. A really simple example of…
Firewall rules: not as secure as you think This post introduces some tricks for jailbreaking hosts behind “secure” enterprise firewalls in order to enable arbitrary inbound and outbound requests over any protocol. You’ll probably find the tricks outlined in the post useful if you need to deploy software in a hostile networking environment. The motivation for these tricks is that you might be a…
Software engineers are not (and should not be) technicians I don’t actually think predictability is a good thing in software engineering. This will probably come as a surprise to some people (especially managers), but I’ll explain what I mean. In my view, a great software engineer is one who automates repetitive/manual labor. You would think that this is a pretty low bar to clear, right? Isn’t…
Quality and productivity are not necessarily mutually exclusive One of my pet peeves is when people pit quality and productivity against each other in engineering management discussions because I don’t always view them as competing priorities. And I don’t just mean that quality improves productivity in the long run by avoiding tech debt. I’m actually saying that a focus on quality can immediately…
My spiciest take on tech hiring … is that you only need to administer one technical interview and one non-technical interview (each no more than an hour long). In my opinion, any interview process longer than that is not only unnecessary but counterproductive. Obviously, this streamlined interview process is easier and less time-consuming to administer, but there are other benefits that might not…
Prefer do notation over Applicative operators when assembling records This is a short post explaining why you should prefer do notation when assembling a record, instead of using Applicative operators (i.e. (<$>) / (<*>) ). This advice applies both for type constructors that implement Monad (e.g. IO ) and also for type constructors that implement Applicative but not Monad (e.g. the Parser type…
All error messages are necessarily bad to some degree This is something I feel like enough people don’t appreciate. One of the ways I like to explain this is by this old tweet of mine : The evolution of an error message: No error message A one-line message “Expected: … / Actual: …” “Here’s what went wrong: …” “Here’s what you should do: …” I automated away what you should do The invalid state is…
The siren song of domain-specific languages I’ve seen a lot of engineering teams mistakenly believe that they can author domain-specific languages for less technical users on a budget. In particular they seem to believe that if they create this domain-specific language then the less technical users will be able to thoughtlessly churn out a bunch of code in that language and there won’t be any…
Unification-free ("keyword") type checking From my perspective, one of the biggest open problems in implementing programming languages is how to add a type system to the language without significantly complicating the implementation. For example, in my tutorial Fall-from-Grace implementation the type checker logic accounts for over half of the code. In the following lines of code report I’ve…
A GHC plugin for OpenTelemetry build metrics This post is about a new OpenTelemetry plugin for GHC that I’ve been building for work that we’re open sourcing because I think it might be broadly useful to others. If all you want to do is use the plugin then you can find it on Hackage , which includes more detailed usage instructions. This post will focus more on the motivation and background behind…
My views on NeoHaskell Recently Nick Seagull has announced a NeoHaskell project which (I believe) has generated some controversy. My first run-in with NeoHaskell was this post on cohost criticizing the NeoHaskell project and a few of my friends within the Haskell community have expressed concern about the NeoHaskell project. My gut reaction is also critical, but I wanted to do a more thorough…
GHC plugin for HLint At work I was recently experimenting with running hlint (the widely used Haskell linting program) as a GHC plugin . One reason why I was interested in this is because we have a large (6000+ module) Haskell codebase at work, and I wanted to see if this would make it cheaper to run hlint on our codebase. Ultimately it did not work out but I built something that we could open…
Ergonomic newtypes for Haskell strings and numbers This blog post summarizes a very brief trick I commonly recommend whenever I see something like this: {-# LANGUAGE OverloadedStrings #-} import Data.Text ( Text ) import Numeric.Natural ( Natural ) newtype Name = Name { getName :: Text } deriving ( Show ) newtype Age = Age { getAge :: Natural } deriving ( Show ) data Person = Person { name :: Name…
The "open source native" principle for software design This post summarizes a software design principle I call the “open source native” principle which I’ve invoked a few times as a technical lead. I wanted to write this down so that I could easily reference this post in the future. The “open source native” principle is simple to state: Design proprietary software as if you intended to open source…
terraform-nixos-ng: Modern terraform support for NixOS Recently I’ve been working on writing a “NixOS in Production” book and one of the chapters I’m writing is on deploying NixOS using terraform . However, one of the issues I ran across was the poor NixOS support for terraform . I’ve already gone through the nix.dev post explaining how to use the terraform-nixos project but I ran into several…
Announcing nixos-rebuild: a "new" deployment tool for NixOS The title of this post is tongue-in-cheek; nixos-rebuild is a tool that has been around for a long time and there’s nothing new about it. However, I believe that not enough people know how capable this tool is for building and deploying remote NixOS systems. In other words, nixos-rebuild is actually a decent alternative to tools like…
macos-builder I recently upstreamed a derivation for a Linux builder into Nixpkgs that’s easy to deploy on macOS. The significance of this work is that you can now run the following command on macOS: $ nix run nixpkgs#darwin.builder … and that will launch a Linux builder that you can delegate builds to. For full details, read the corresponding section of the Nixpkgs manual . In this post, I wanted…
incremental The context for this post is that at work I recently implemented Nix ecosystem support for “incrementally” building Haskell packages. By “incrementally” I mean that these Nix builds only need to build what changed since the last full build of the package so that the package doesn’t need to be built from scratch every time. The pull requests implementing this feature have not yet been…
caching Professional Nix users often create a shared cache of Nix build products so that they can reuse build products created by continuous integration (CI). For example, CI might build Nix products for each main development branch of their project or even for every pull request and it would be nice if those build products could be shared with all developers via a cache. However, uploading build…