How Eve unifies your entire programming stack

23,236 reads

Welcome to Part I of my VI-part series about Eve, an exciting and fascinating new programming language.

Eve is the culmination of years of research and development by the visionary team who previously founded Light Table. Version 0.2 of Eve launched last month and made a big splash on Hacker News, which is how I first heard about it.

This latest version of Eve makes for some very cool live demos, such as “Flappy Eve”:

Scrolling through the flappy.eve demo for the first time, a few striking features jump out:

The IDE looks like a WYSIWYG blog editor. Eve code is designed to be embedded within Markdown-formatted prose; it’s literate programming to the max.

The syntax is unfamiliar, but still looks clean and approachable — mostly it just looks sparse. Part of me can’t help thinking, “I see all these bracketed parts, but where’s the actual code?”

The code is ridiculously compact — about 100 lines. Similarly, their todomvc.eve weighs in at only 63 lines. For comparison, React’s TodoMVC has 300+ lines of JavaScript.

So that was my first impression. Here’s my impression after spending hours browsing the examples, pondering over the docs, and watching tech talk videos: Wow!

Eve is a cornucopia of solutions to problems I hadn’t even realized we had. It’s like I’ve been raised in a society of bicyclists, and after seeing a motorized vehicle for the first time, I’m suddenly understanding the limitations of a pedal-based architecture.

After having been exposed to Eve, I can retroactively diagnose various problems in the architecture of mainstream programming stacks. In this series, I’ll try to explain what all these problems are and how Eve solves them.

Problem: Layers doing the same thing differently

Your software stack has many layers. The following three layers are usually the “core system” doing the heavy lifting:

Database layer

Remote API layer

Application layer

But there are also plenty of other layers that the core system talks to:

Rendering layers

I/O event layers

Configuration layers

Logging layers

At a high level, these layers all do the same thing: they process data. They read input values, they compute other values, they mutate internal state, and they output values to pass to other layers. But, when you zoom into each layer, you see countless differences that obscure the fact that they’re all fundamentally about data processing.

Different data models

You have one or more online database systems. Their data models look like SQL tables, document collections, key-value maps and/or graphs.

You have a remote API that models data as chunks of JSON or XML, or maybe as a GraphQL graph.

You have a running application that models in-memory data structures and variables in a scope chain.

Different operations

To operate on the database layer, you can send various kinds of SQL or NoSQL queries.

To operate on the API layer, you can query for data via HTTP GET and update data via HTTP POST and friends. If it’s a GraphQL API, you operate with GQL queries and mutations.

To operate on the application layer, you can look up variables from the scope chain, and you can traverse or mutate in-memory data structures.

For each layer of your stack, there are different data models and operations:

Since each layer is different, it creates friction and room for error. You have to reason separately about each one’s properties and guarantees, and use separate programming patterns for each. And you have to write a lot of “glue code”.

Solution: A uniform data-processing language

Eve has a single low-level data model and a single set of operations which you can use across every layer of your stack.

Uniform data model

In Eve, data (a.k.a. state) lives in a set of databases. Different layers of your stack might correspond to different databases, e.g.:

In-memory application data lives in the @session database

database The browser’s DOM tree lives in the @browser database

database User I/O events live in the @event database

Each database contains records. A record is a key-value mapping that can store primitive values as well as references to other records. Records have a simple bracketed syntax:

There are no tables or collections for holding records within a database, just databases containing linked structures of records.

Eve’s universal data model of linked records is reminiscent of “semantic web” technologies like RDF and JSON-LD. But Eve is more than a uniform data model…

Uniform set of operations

It’s also a uniform set of operations. The three operations search , commit and bind make up the entire functionality of Eve:

search queries for data, similar to SQL’s SELECT

queries for data, similar to SQL’s commit mutates the state of your data, similar to SQL’s INSERT / UPDATE / DELETE

mutates the state of your data, similar to SQL’s / / bind writes special “deduced values”, which are like SQL’s materialized views or MobX’s computed values. I’ll say lots more about the awesomeness of bind later in this series.

It’s amazing that we can control different layers of the stack by using this uniform set of operations on Eve’s uniform data model. For example, here’s how we render a <div> into the DOM:

Since the DOM tree lives in the @browser database, rendering a <div> just means commit ing a record with tag: "div" .

Now, for each layer of your stack, there’s only one data model and set of operations:

Since each layer is the same, there’s less friction and room for error. You can reason more easily about properties and guarantees, and use similar programming patterns for each. And you don’t need to “glue” anything together, because everything’s already connected.

Higher abstractions

The Eve team invented a uniform data model and uniform set of operations that can operate across your entire application stack. To accomplish that feat, they had to identify a higher abstraction that the rest of us didn’t realize was possible.

To wrap your head around this achievement, it helps if you’ve already put in the effort to understand another abstraction leap that debuted this year: GraphQL.

It takes people a while to understand that GraphQL isn’t a database or a server, but rather a graph query language (or “GraphQL” if you will). The point of GraphQL is to change the client’s view of an API from a small rigid set of REST endpoints to a unified linked-data structure that accepts arbitrary graph queries.

Like GraphQL, Eve also isn’t a database backend or a server; it’s a language at a higher level of abstraction than we’re used to. Consider the example code from a section of Eve’s home page titled “A simple model: the world as data”:

When you run that search @slack block, you’re communicating with the third-party Slack application, which of course has its own internal database. But you get to pretend that everything is part of the Eve data universe — just like GraphQL lets you pretend that arbitrary API calls are part of a big graph universe.

So if you like what GraphQL is doing for the API layer, but just wish someone would do the same thing for all the other layers in one fell swoop… say hello to Eve.

Next post:

II. When logic programming meets CQRS

Tags