What does FREST stand for? I have no idea! However Guren Howe is calling a set of ideas that I find neat FREST. I think they could be a lot more developed and cohesive but it’s not bad food for thought. You’ll find a compilation of notes I took from his blog posts below.


Our industry’s greatest moral failure isn’t security breaches or privacy violations. It’s that we’ve built a priesthood of programmers, hoarding the power of computing behind arcane incantations of JavaScript and Docker containers. We’ve chosen approaches that suit our highly trained elite rather than ones that democratize computing.

Where are all the bicycles for the mind?

Imagine a world where:

  • Every piece of data has an address, but what you see at that address depends on who you are

  • Everything you see always has a useful, relational, searchable UI

  • Security isn’t a bolt-on feature but emerges naturally from how things compose

  • Functions are just relations waiting to be filled in

  • Everything is a query, and every query can be changed

This isn’t science fiction. The building blocks have existed since the 1970s. The relational model. Functional programming. Capability-based security. We just haven’t put them together right.

We’ve spent fifty years building software that serves the priesthood. Tools that make sense if you think in abstractions and can hold a mental model of asynchronous state mutations. Tools that actively resist modification by anyone without years of training.

It’s time to burn the priesthood down.

The next generation of software won’t be built on promises of scalability or developer ergonomics. It will be built on a radical premise: that everyone deserves tools they can understand and modify. The priests won’t like it. But then, they never do.

The most successful products for non-programmers to do computing are those which allow folks to directly manipulate highly expressive abstractions.

Frest is currently a software design philosophy, or you might say a “pattern”. The relational model and SQL. URLs and the filesystem. Direct manipulation of abstractions with a nice GUI, and rolling yet another HTML form by hand.

Today’s most popular programming languages put ideas that were fringe and theoretical just a few years ago right in your face. Advanced type systems. The Actor model of parallelism. Synchronisation of distributed data. AI.

Before Typescript, advanced type systems were largely the stuff of academic papers. A couple of years after Typescript’s release, advanced type systems are suddenly everywhere.

This project seeks to go where the puck is going much faster. There are a small number of mature ideas we should adopt in one go:

  1. The network is the basis

Everything important is addressable and serialisable. Every field in every table in your database. Every high-level function in your business model. Every conceptually distinct element in your UI.

In FREST, the filesystem isn’t the starting point. The filesystem isn’t even necessary1. Addressable content is the better way. Even within single applications, major articulation points should be connected by URLs2.

Even code isn’t loaded from a file; it’s at an address. Everything is at an address.

  1. Direct manipulation of abstractions

FileMaker and Access (and these days, say, Notion) are end user relational data bases with some functional features. It turns out that when given a nice GUI for manipulating such things, non-programmers can employ relational database concepts

One of the main questions FREST seeks to ask and answer is: What other highly expressive abstractions can we present to non-programmers in an intuitive way?

The FREST project’s bet is: quite a few: actors, encryption, append-only data stores, logic, …

  1. There’s always a GUI. Always.

Excel and FileMaker let users directly manipulate abstractions, always with an appropriate GUI presentation (even if it’s just a textual function editor).

Everything addressable in a FREST system is able to present itself in any of a small number of composable ways, such as:

  • icon

  • descriptive link

  • table cell

  • table row

  • table or form header

  • “full page”

FREST is agnostic about its presentation layer, just requiring that there should be one. Most obviously in the first case, FREST would probably present HTML versions of these things, perhaps as Web Components.

This sort of collection of presentations is sufficient for robust and subtle embedding. For example, a table can be embedded as an icon or descriptive link in some richer context — an outliner, or a web page element, or an object in a drawing program. Within those UI paradigms, the content can be expanded and manipulated.

All that a programmer has to do if they introduce a new type is to provide those presentations of it. Usually, this can be done through existing presentations. A programmer who writes a function need only describe its input and output types (and any security constraints) and it will be available to use anywhere applicable, through the GUI or the API.

  1. The UI is always navigable

FREST content might present all sorts of interesting buttons, menus and other chrome for interacting with content. But at the very least, every FREST value responds to a right click or long press or the like, presenting a meta view of the thing the gesture is addressed to.

There will in time likely be all sorts of semantic, pragmatic and other content on the meta UI. But at the very least initially, the meta view will allow the user to discover and invoke all the things that can be done with the value. It lets the user switch between the standard presentation and others (a table of data might be viewable as a chart, for example). It lets the user choose between functions that take the value as an argument. This might create a new single value, or a new column in a table.

  1. Functional Programming

The addressable functions of which a FREST system is composed include functional programming constructs that allow composition of existing things into new things.

I’ll discuss this in more detail later, but briefly:

  • partial application is central;

  • functions present themselves as forms;

  • user interface elaborations are preformed through functional operations, for example, starting from a table of addresses, a user can add a column of maps of those addresses, which is to say the user applies a (functional) map operation to the data underlying the table;

  • API operations are functional programming operations. API clients can create new values, including functions

  • API operations are asynchronous. If a client of an API wants a value, it passes an address for the return value to be sent to. FREST is a continuation-passing architecture. This means, for example, that any function call can be a remote call back.

  1. Relations

Try to forget SQL.Think in terms of simple relational operations such as you might use through the user interface in Access or FileMaker. Joining relations, querying them, obtaining new values through functions of old ones.

Relations are elegant and beautiful and it is possible and fruitful to represent much more of our software through relations.

FREST says APIs should be relational. GraphQL is our industry already heading in this direction. The result is APIs of much greater subtlety, flexibility and efficiency. More on that soon.

  1. Composition and Security

Security and composition are two sides of the same idea in FREST.

Briefly, a client of a FREST system is faced with values (which might be functions, rows, whole relations, addresses, anything at all) that are missing, that are provided as a default, or that are fixed. The client can provide or override any value that isn’t fixed.

This is why even the internal relationships within a FREST system are accessed through addresses: so they can be externally overridden.

Many things will have a default value that can be changed. Most of the logic and layouts of UI generation will be a default. Many behaviours will be defaults. The user will be able to right-click something in their UI, navigate all the defaults that produced that thing, and change any of them.

This is where the relations comes in. To take just one example, the sequence of operations that occur when you add an item to your shopping basket should be described in a relation, not buried in code.

Imagine if you could customise your Amazon user interface by right clicking and removing things, surfacing things that are hidden, changing the actions when an item is added to a shopping basket, and so on. FREST promises to make software like that easier to write than the current rigid Amazon experience was to write in the first place.

business software in practice is nearly always small pieces of fairly simple code that run asynchronously, serialising and deserialising bits of the state of whatever is being worked on.

The instances of running code can be separated by:

  • time — perhaps a backup process must be run every night at midnight;

  • space — computation distributed in physically separate devices must be sent across a network;

  • logic — Some of the logic of the final computation might be best executed in the database; or

  • resource constraints — we must do some computation in pieces or in the database because the data involved don’t fit in memory.

The tasks we achieve with the code we write can be separated into three kinds:

  • causing side-effects (e.g. sending an email);

  • creating new state from other state (creating a new appointment based on a HTTP request); and

  • performing complex computations (resizing an image).

Side Effects through New State

Sending emails and other sort of external state change must in the end be performed by regular code. But these effects are in general self-contained and can be represented as a consequence of a clear and simple set of input states.

This means that we can generally set things up so side effects can be represented as “creating state from other state”. So for sending out emails, we can marshall the template and its arguments in the database and then run the small amount of fixed code that causes the side-effect to occur.

Creating State from other State

Much of the code we write just rearranges state. A HTTP request comes in from a user, we pull the request apart, and we create state as a result — a new appointment, say.

Rules

SQL is a logic engine, although its design tries hard to hide this. In particular, it’s a bit odd to use a rule in SQL. A rule expresses how to derive some state from other state. We can say if a customer is on the gold list, they get a 10% discount. Or if an order is created, a shipping task should be created for the warehouse

It is useful to think of rules as being either:

  • forward, meaning that whenever a new case of the antecedent of the rule becomes true, we immediately generate and insert its consequent; or

  • backward, meaning that when we want to know if the consequent is true, we go looking for matching antecedents

In SQL databases, a forward rule is a trigger, and a backward rule is a view or query.

Declarative Triggers

Postgres and SQLite both support triggers in something like pure SQL, giving us declarative rules, letting us have rules while avoiding the issues TC languages bring. Even within the limits of the other databases, we can write state-rearranging triggers in a simple, essentially declarative way, just chaining together SQL queries.

Limiting Turing Completeness

Much — most, even — of what you do in your TC language can be straightforwardly expressed in the data layer, especially once we can represent functions in the data layer.

Imagine where the TC language inserts all incoming requests as JSON into a requests table (you would probably be logging the request anyway, so if we stop doing that, we’re not using significantly different storage). Now, a trigger on the requests table can extract perform the above insert and then gather values and a mustache template for the resulting web page.

Shaping the inputs to code

Such TC code as we must write should be written such that the data given to it has exactly the shape needed to carry out the must-be-Turing-Complete part of the computation in the most straightforward way possible. Note that this is just good coding practice anyway.

The consequence of the above following might be rendering a web page to the user’s browser. We might have one function that turns values and a template into HTML. Another would take HTML and send it to the user. The data layer can invoke User Defined Functions for the first, and return the second as the result of the action that inserted the original request into the requests table.

What does this Mean?

I am arguing for writing software differently in two different ways:

  • We should do more in the query language, limiting the use of TC programming languages to where we must; and

  • We should simplify the TC code we write. Since we have to travel through the sea of state in the database anyway, we should use the power of the query engine to present our TC code with exactly the data in exactly the shape that will make that code easiest to write.

Also, our industry should support development of a better alternative to SQL (i.e. Datalog). The success of SurrealDB, Supabase and the like demonstrates that developers are open to change in this area.