January 15th, 2026
Over the last several years I’ve been experimenting with small domain-specific languages for, amongst other things, building web applications. These projects were never intended to replace existing frameworks or tools for other developers. They were a way to explore ideas that felt awkward or overly indirect to express in the systems I was using at the time. Most importantly, I made them for myself in a manner that enhanced my daily workflow.
One of the earlier experiments was a language and runtime called WebDSL. The goal was to encode a complete web application stack directly into the language. Concepts like websites, pages, API endpoints, authentication, sessions, database access, and migrations were all represented explicitly. This reduced a large amount of boilerplate and made it possible to build small applications with very little surrounding infrastructure.
A minimal example in that system looked like this:
website {
port 3123
page {
route "/hello/:world"
pipeline {
jq { { world: .params.world } }
}
mustache {
<p>hello, {{world}}</p>
}
}
}
January 4th, 2026
I'm not sure if you've spent much time working with GraphQL but one of the trickier issues to solve out of the box is the N+1 problem. The N+1 problem arises when there are nested queries and a request is made per entity. Imagine a team with hundreds of employees. Retrieving teams and their employees necessitates first a query to retrieve the list of teams with IDs and then to make individual queries for each employee on a team. This is not very efficient!
The DataLoader pattern mitigates the issue. It's pretty basic in operation. When a GraphQL query comes in with a nested response, say asking for a list of all teams and their related employees, first a query is made for teams, then a DataLoader keyed by team IDs is called with a list of keys that represent those teams. The DataLoader then makes a single query with that list of keys, formats the response, and continues the GraphQL execution.
It's not too dissimilar to how N+1 problems are solved with other tools. For example, the ActiveRecord pattern typically introduces an "includes" method that follows the same general approach of taking a list of IDs and making a single additional query.
While the relationships between data are rather easy to express in ActiveRecord, it can be rather verbose and somewhat tedious to describe them in general-purpose languages like TypeScript.
January 3rd, 2026
Web Pipe is a DSL for creating web applications. It might be more useful to consider it more of a configuration language for a web server than anything else.
GET /hello/:world
|> jq: `{ world: .params.world }`
|> handlebars: `<p>hello, {{world}}</p>`
describe "hello, world"
it "calls the route"
let world = "world"
when calling GET /hello/{{world}}
then status is 200
and selector `p` text equals "hello, {{world}}"
The essence of the language is the pipeline. Each pipeline starts with an HTTP request parsed into a JSON representation, which is then passed along to individual steps. Each step consists of a middleware and a configuration block.
In the above example we define a handler for a GET request and a pipeline that consists of two steps. The first is a step that uses the JQ middleware and the second uses the Handlebars middleware. Their configuration blocks are JQ and Handlebars code, respectively.
May 18th, 2024
A Burrito is a monad...
type Meat = Chicken | Beef | Pork | Fish | Veggie
type Ingredient =
| Cheese | Rice | Beans | Salsa | Guacamole | SourCream | Lettuce
| Tomato | Onion | Cilantro | PicoDeGallo
type Burrito = Meat option * Ingredient list
let (>>=) burrito f =
match burrito with
| Some meat, ingredients -> f (Some meat, ingredients)
| None, _ -> None, []
let returnBurrito (meat, ingredients) = meat, ingredients
let tortilla = returnBurrito (Some Veggie, [])
let addMeat meat (m, ingredients) = Some meat, ingredients
let addIngredient ingredient (meat, ingredients) =
meat, ingredient :: ingredients
let addMissionBurritoIngredients (meat, ingredients) =
meat, Cheese :: Rice :: Beans :: ingredients
let holdThe ingredient (meat, ingredients) =
meat, List.filter (fun i -> i <> ingredient) ingredients
let burrito =
tortilla
>>= addMeat Chicken
>>= addMissionBurritoIngredients
>>= holdThe Cheese
>>= addIngredient PicoDeGallo
>>= addIngredient Salsa
>>= addIngredient Guacamole
>>= addIngredient SourCream
printfn "%A" burrito
It's got Some Chicken.
I'll see myself out...
April 20th, 2023
Using large-language models like OpenAI's GPT family for writing software has been one of the first successful uses for these tools. GitHub's Copilot can successfully implement a large number of software related tasks, from writing code, to tests or even documentation and has become somewhat of an indispensable tool to a large number of software engineers.
While Copilot and other tools that aid in writing code are here for the foreseeable future there are methods for using large-language models that move up the ladder of abstraction and allow for text instructions to update a user interface with interactive functionality.
An example of such an approach is seen in the browser-builder augmentation from the transynthetical-engine.
Here's a brief workflow of building a circle drawing application.
February 8th, 2023
Although primarily relegated to the dustbin of philosophy, the distinction between two kinds of propositions, analytic and synthetic, is useful once again in the context of interacting with a large language model like ChatGPT. Kantians, rejoice!
With complete disregard to the formalisms of analytic philosophy:
An analytic proposition is something like "All bachelors are unmarried." This is true by definition. We don't need to go looking for any other facts in order to verify this assertion.
In contrast, a synthetic proposition is something like "It is raining outside." Here the truthfulness of the assertion is contingent on outside facts. Literally. You have to look outside to see if it is raining or not.
February 7th, 2023
As outlined in The Tyranny of the Anonymous, anonymity on the internet is clearly beneficial in some cases and technically here to stay, but there are plenty of reasons for optional forums that do not allow anonymous participation
A rapidly accelerating use of anonymity is to hide the fact that a participant is not even human, let alone a troll or state-sponsored actor. Large-language models such as GPT will increasingly be used in ways to appear as though something published to a website was from a human author and for reasons that are too unpredictable to enumerate. It seems wise to offer a solution.
Relying on private companies such as Meta or Amazon for identity verification is unwise for a number of reasons, but most importantly that private companies are in the business of providing services to their customers. Just look how easy it is for someone to engage in social engineering when faced with a person trained in part to keep the customer happy! Can you imagine the "crying baby trick" working with the an employee of the DMV? From my experience the DMV is not in the business of keeping anyone happy and has plenty of experience and protocols in place to limit fraudulent identification.
So how do we go about such state-level identity verification?
March 31st, 2019
Perhaps you remember the moment, perhaps you don't. Maybe you were outraged, maybe you were on #TeamKendall, maybe you don't care too much about it either way. Kendall Jenner was featured in a Pepsi advertisement, that for at least for a few days became a source of popular controversy that propagated throughout the digital media ecosystem.
The video portrayed a number of creative young individuals who join an unknown cause expressed as a joyous public protest. This includes Kendall Jenner, who leaves a modeling photo shoot to join the mass, eventually coming face-to-face with a line of policemen. She then gives one of the officers a can of Pepsi, everyone smiles and the video cuts to the corporate logo.
As Bernice King, daughter of Martin Luther King, Jr., stated on Twitter,
If only Daddy would have known about the power of #Pepsi.
February 18th, 2019
It is a moot point wether or not Facebook, Twitter or Google are engaged in censorship when they remove content from their platforms, as this discussion is mainly about semantics. While it is true that private companies have the legal right to decide on their own editorial policies it becomes problematic when those private companies hold an incredibly large sway over society. As of early 2019 Facebook has over 2.3 billion active monthly users. There is nary a working journalist or politician without a Twitter account. Their policies on what information to promote or disallow has a profound effect on societies across the globe.
As Thomas Macaulay wrote of British Parliament in 1828,
The gallery in which the reporters sit has become a fourth estate of the realm. The publication of the debates, a practice which seemed to the most liberal statesmen of the old school full of danger to the great safeguards of public liberty, is now regarded by many persons as a safeguard tantamount, and more than tantamount, to all the rest together.
Representative democracies rely on the relationship between journalism and government. The problem we are facing is that our contemporary means of publishing information to the voting public is primarily through privately controlled and for-profit corporations.
January 16th, 2019
From the Federalist Papers to contemporary whistleblowers, there is plenty of evidence of the benefits of an anonymous check on power. There is no question that the anonymity of the masses is the enemy of the traditional despot. Throughout history it has been deemed advantageous by authoritarian leaders to controls the means of communication and to punish those that question their powers.
Cryptography and the internet have forever closed the door on this kind of censorship. While individual websites like Facebook or YouTube can indeed monitor and police the content that is published on their platforms, there will always be alternative methods of publication that are impossible to silence. Between tools and technologies like Signal, Telegram, Tor, Bitcoin, or BitTorrent, there are many ways for people to avoid the prying eyes of nefarious controlling bodies.
While there are benefits to being anonymous, there are very good reasons why people would want to use a communication platform that requires people to use their real names and identities. People have a need to interact with their friends, family, neighbors and other people whose identities they already know. The vast majority of our daily interactions are face-to-face.
Accountability and transparency, foundational elements of our society, are somewhat at odds with anonymity. Commercial and financial transactions are built on various types of infrastructure to facilitate and enforce accountability. Facebook's marketplace works best with a verified identity for the same fundamental reason that a pawn shop requires a state-issued photo ID. There is also a need for accountability for the content published on social media platforms. Physical threats and other forms of unprotected speech will always need to be policed.